Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
cc0410c
Attachment for APM error (inline)
viduni94 Nov 20, 2025
3a28d9a
Merge branch 'main' into agent-builder-error-sample-contextual-insights
viduni94 Nov 24, 2025
1ccbfd1
Use feature flag to determine which contextual insights to show
viduni94 Nov 24, 2025
35603e5
Use feature flag to determine which contextual insights to show
viduni94 Nov 24, 2025
10483ab
Introduce tools to fetch error details when needed for the error atta…
viduni94 Nov 24, 2025
8f8c78f
Update tool name
viduni94 Nov 24, 2025
a3d5ed8
Merge branch 'main' into agent-builder-error-sample-contextual-insights
viduni94 Nov 25, 2025
4982c72
Finalize prompts and instructions
viduni94 Nov 25, 2025
5da195b
Optionally test with Obs Agent
viduni94 Nov 25, 2025
af0ac1d
Merge branch 'main' into agent-builder-error-sample-contextual-insights
viduni94 Nov 26, 2025
3bb2c87
Inline contextual insights summary
viduni94 Nov 27, 2025
3cf2b6e
Inline contextual insights summary
viduni94 Nov 27, 2025
aee61ef
Remove attachment-specific tools
viduni94 Nov 27, 2025
6ee9a8e
Merge branch 'main' into agent-builder-error-sample-contextual-insights
viduni94 Nov 27, 2025
fbf77c1
Merge branch 'main' into agent-builder-error-sample-contextual-insights
viduni94 Nov 28, 2025
f77d911
Use common component and rename folders to agent_builder
viduni94 Nov 28, 2025
cbff403
Consume common attachment
viduni94 Nov 28, 2025
1d5a789
Remove error attachment
viduni94 Nov 28, 2025
ad40e30
Revert minor change
viduni94 Nov 28, 2025
de7aa86
Update route folder
viduni94 Nov 28, 2025
22f8f7a
Remove unused tools
viduni94 Nov 28, 2025
0cefbe2
Update attachment ID
viduni94 Nov 28, 2025
8cbf990
Update descriptions
viduni94 Nov 28, 2025
dac8c5b
Rename file
viduni94 Nov 28, 2025
6ee275c
Add todos
viduni94 Nov 28, 2025
3f61d56
Remove extra newline
viduni94 Nov 28, 2025
68d173e
Merge branch 'main' into agent-builder-error-sample-contextual-insights
viduni94 Dec 2, 2025
58787be
Fix conflicts
viduni94 Dec 3, 2025
49e4ace
Update return type
viduni94 Dec 3, 2025
e97411b
Use hook exposed by agent builder for connector selection
viduni94 Dec 3, 2025
68cc56f
Use hook exposed by agent builder for connector selection
viduni94 Dec 3, 2025
3299c90
Use data registry and move the error AI insights route to the observa…
viduni94 Dec 3, 2025
1b33932
Bring back the error attachment
viduni94 Dec 3, 2025
e224c63
Add server-side system prompt
viduni94 Dec 3, 2025
d3f9665
Attach error when the flyout is opened from that page
viduni94 Dec 3, 2025
6b822e9
Add comment
viduni94 Dec 3, 2025
7afd665
Add guardrail
viduni94 Dec 3, 2025
08c553a
Add data fetchers
viduni94 Dec 4, 2025
42c338a
Remove comment
viduni94 Dec 4, 2025
185c3c4
Merge branch 'main' into agent-builder-error-sample-contextual-insights
viduni94 Dec 4, 2025
a8adac0
Changes from node scripts/lint_ts_projects --fix
kibanamachine Dec 4, 2025
d8a8a2d
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine Dec 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export const AGENT_BUILDER_BUILTIN_TOOLS: string[] = [
'observability.get_alerts',
'observability.get_services',
'observability.get_downstream_dependencies',
'observability.get_error_by_id',
'observability.get_transaction_by_id',
'observability.get_trace_overview_by_id',
'observability.get_span_by_id',
'observability.get_error_group_by_key',
];

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const OBSERVABILITY_AGENT_ID = 'observability.agent';
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@
export const OBSERVABILITY_GET_DOWNSTREAM_DEPENDENCIES_TOOL_ID =
'observability.get_downstream_dependencies';
export const OBSERVABILITY_GET_SERVICES_TOOL_ID = 'observability.get_services';
export const OBSERVABILITY_GET_ERROR_BY_ID_TOOL_ID = 'observability.get_error_by_id';
export const OBSERVABILITY_GET_TRANSACTION_BY_ID_TOOL_ID = 'observability.get_transaction_by_id';
export const OBSERVABILITY_GET_TRACE_OVERVIEW_BY_ID_TOOL_ID =
'observability.get_trace_overview_by_id';
export const OBSERVABILITY_GET_SPAN_BY_ID_TOOL_ID = 'observability.get_span_by_id';
export const OBSERVABILITY_GET_ERROR_GROUP_BY_KEY_TOOL_ID = 'observability.get_error_group_by_key';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

// Duplicate of the attachment type ID defined in @kbn/observability-agent-plugin/server/attachments/error.ts
// Re-defined here to avoid cross-plugin dependency cycles
export const OBSERVABILITY_ERROR_ATTACHMENT_TYPE_ID = 'observability.error';
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { CoreStart } from '@kbn/core/public';
import {
OBSERVABILITY_AGENT_FEATURE_FLAG,
OBSERVABILITY_AGENT_FEATURE_FLAG_DEFAULT,
} from './feature_flag';

export function getIsObservabilityAgentEnabled(coreStart: CoreStart): boolean {
return coreStart.featureFlags.getBooleanValue(
OBSERVABILITY_AGENT_FEATURE_FLAG,
OBSERVABILITY_AGENT_FEATURE_FLAG_DEFAULT
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const renderApp = ({
lens: pluginsStart.lens,
uiActions: pluginsStart.uiActions,
observabilityAIAssistant: pluginsStart.observabilityAIAssistant,
onechat: pluginsStart.onechat,
share: pluginsSetup.share,
kibanaEnvironment,
licensing: pluginsStart.licensing,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { EuiFlexItem, EuiSpacer } from '@elastic/eui';
import dedent from 'dedent';
import { i18n } from '@kbn/i18n';
import type { Message } from '@kbn/observability-ai-assistant-plugin/public';
import React, { useMemo, useState } from 'react';
import { EuiButton, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import type { AT_TIMESTAMP } from '@kbn/apm-types';
import type { Message } from '@kbn/observability-ai-assistant-plugin/public';
// import { OBSERVABILITY_AGENT_ID } from '../../../../../common/observability_agent/agent_id';
import { OBSERVABILITY_ERROR_ATTACHMENT_TYPE_ID } from '../../../../../common/observability_agent/attachment_ids';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
import type { APMError } from '../../../../../typings/es_schemas/ui/apm_error';
import { getIsObservabilityAgentEnabled } from '../../../../../common/observability_agent/get_is_obs_agent_enabled';
import { ErrorSampleDetailTabContent } from './error_sample_detail';
import { exceptionStacktraceTab, logStacktraceTab } from './error_tabs';

Expand Down Expand Up @@ -39,12 +43,17 @@ export function ErrorSampleContextualInsight({
};
};
}) {
const { observabilityAIAssistant } = useApmPluginContext();
const { observabilityAIAssistant, onechat, core } = useApmPluginContext();
const isObservabilityAgentEnabled = getIsObservabilityAgentEnabled(core);

const [logStacktrace, setLogStacktrace] = useState('');
const [exceptionStacktrace, setExceptionStacktrace] = useState('');

const messages = useMemo<Message[] | undefined>(() => {
if (onechat && isObservabilityAgentEnabled) {
return undefined;
}

const serviceName = error.service.name;
const languageName = error.service.language?.name ?? '';
const runtimeName = error.service.runtime?.name ?? '';
Expand Down Expand Up @@ -76,7 +85,145 @@ export function ErrorSampleContextualInsight({
: ''
}`,
});
}, [error, transaction, logStacktrace, exceptionStacktrace, observabilityAIAssistant]);
}, [
error,
transaction,
logStacktrace,
exceptionStacktrace,
observabilityAIAssistant,
onechat,
isObservabilityAgentEnabled,
]);

const attachments = useMemo(() => {
if (!onechat || !isObservabilityAgentEnabled) {
return [];
}

const serviceName = error.service.name;
const languageName = error.service.language?.name ?? '';
const runtimeName = error.service.runtime?.name ?? '';
const runtimeVersion = error.service.runtime?.version ?? '';
const transactionName = transaction?.transaction.name ?? '';

return [
{
id: 'apm_error_details_screen_context',
type: 'screen_context',
getContent: () => ({
app: 'apm',
url: window.location.href,
description: `APM error details page for ${serviceName}`,
}),
},
{
id: 'apm_error_details_instructions',
type: 'text',
getContent: () => ({
content: dedent(`
<contextual_instructions>
I'm an SRE. I am looking at an exception in the Kibana APM UI and trying to understand what it means.
Your task is to describe what the error means and what it could be caused by. Using **ONLY** the provided data produce a concise, action-oriented response.

Only call tools if the attachments do not contain the necessary data to analyze the error.
Prefer using attachment data if possible and only call tools to fetch any missing context (e.g., grouping key, trace, transaction, span, downstream dependencies) when required.
**DO NOT** call any tools before providing your first response as all the error details are provided in the attachments.

Respond using the following structure:
- Summary: One paragraph explaining what the error means and likely causes.
- Failure pinpoint: Identify whether this is application code or a dependency (e.g., network/HTTP), and name the failing component/endpoint if clear. Cite specific fields or key stack frames (function:file:line) that support your reasoning.
- Impact: Scope and severity (Reference endpoint(s)/service and time window if evident)
- Immediate actions: Ordered checklist of concrete steps to remediate or validate (e.g., config/network checks, retries/backoff, circuit breakers).
- Open questions and required data (if any): Explicit gaps and the quickest queries/tools to fill them.

Response format:
- Prefer Markdown. Use short headings and bullet points. Include brief code blocks only if essential.

Keep the answer practical and concise. Avoid repeating raw stacktraces; reference only key frames.
</contextual_instructions>`),
}),
},
{
id: 'apm_error_details_error_attachment',
type: OBSERVABILITY_ERROR_ATTACHMENT_TYPE_ID,
getContent: () => ({
service: {
name: serviceName,
environment: error.service.environment,
language: languageName,
runtime_name: runtimeName,
runtime_version: runtimeVersion,
},
transaction_name: transactionName,
error_id: error.error.id,
occurred_at: error['@timestamp'],
log_stacktrace: logStacktrace,
exception_stacktrace: exceptionStacktrace,
}),
},
];
}, [
error,
transaction,
logStacktrace,
exceptionStacktrace,
onechat,
isObservabilityAgentEnabled,
]);

if (onechat && isObservabilityAgentEnabled) {
return (
<>
<EuiSpacer size="s" />
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="apmErrorContextualInsightExplainThisErrorButton"
iconType="sparkles"
onClick={() => {
onechat.openConversationFlyout({
initialMessage: i18n.translate(
'xpack.apm.errorGroupContextualInsight.agentBuilderFlyoutInitialMessage',
{
defaultMessage:
"I'm looking at an exception and trying to understand what it means",
}
),
attachments,
sessionTag: 'apm-error-context',
newConversation: true,
// agentId: OBSERVABILITY_AGENT_ID,
});
}}
>
{i18n.translate('xpack.apm.errorGroupContextualInsight.explainButtonLabel', {
defaultMessage: 'Explain this error',
})}
</EuiButton>
</EuiFlexItem>
<EuiSpacer size="s" />
<div
ref={(next) => {
setLogStacktrace(next?.innerText ?? '');
}}
style={{ display: 'none' }}
>
{error.error.log?.message && (
<ErrorSampleDetailTabContent error={error} currentTab={logStacktraceTab} />
)}
</div>
<div
ref={(next) => {
setExceptionStacktrace(next?.innerText ?? '');
}}
style={{ display: 'none' }}
>
{error.error.exception?.length && (
<ErrorSampleDetailTabContent error={error} currentTab={exceptionStacktraceTab} />
)}
</div>
</>
);
}

return observabilityAIAssistant?.ObservabilityAIAssistantContextualInsight && messages ? (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
import type { SharePluginSetup } from '@kbn/share-plugin/public';
import type { OnechatPluginStart } from '@kbn/onechat-plugin/public';
import type { LicensingPluginStart } from '@kbn/licensing-plugin/public';
import type { ApmPluginSetupDeps } from '../../plugin';
import type { ConfigSchema } from '../..';
Expand All @@ -38,6 +39,7 @@ export interface ApmPluginContextValue {
unifiedSearch: UnifiedSearchPublicPluginStart;
uiActions: UiActionsStart;
observabilityAIAssistant?: ObservabilityAIAssistantPublicStart;
onechat?: OnechatPluginStart;
share: SharePluginSetup;
kibanaEnvironment: KibanaEnvContext;
lens: LensPublicStart;
Expand Down
2 changes: 2 additions & 0 deletions x-pack/solutions/observability/plugins/apm/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/publ
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
import type { SharePublicStart } from '@kbn/share-plugin/public/plugin';
import type { ApmSourceAccessPluginStart } from '@kbn/apm-sources-access-plugin/public';
import type { OnechatPluginStart } from '@kbn/onechat-plugin/public';
import type { CasesPublicStart } from '@kbn/cases-plugin/public';
import type {
DiscoverSharedPublicSetup,
Expand Down Expand Up @@ -167,6 +168,7 @@ export interface ApmPluginStartDeps {
share?: SharePublicStart;
notifications: NotificationsStart;
discoverShared: DiscoverSharedPublicStart;
onechat?: OnechatPluginStart;
}

const applicationsTitle = i18n.translate('xpack.apm.navigation.rootTitle', {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { z } from '@kbn/zod';
import type { CoreSetup, Logger } from '@kbn/core/server';
import type { BuiltinToolDefinition, StaticToolRegistration } from '@kbn/onechat-server';
import { ToolType } from '@kbn/onechat-common';
import { ToolResultType } from '@kbn/onechat-common/tools/tool_result';
import { timeRangeSchema } from './utils/tool_schemas';
import { buildApmToolResources } from './utils/build_apm_tool_resources';
import { getApmToolAvailability } from './utils/get_apm_tool_availability';
import type { APMPluginSetupDependencies, APMPluginStartDependencies } from '../types';
import { OBSERVABILITY_GET_ERROR_BY_ID_TOOL_ID } from '../../common/observability_agent/agent_tool_ids';
import { getErrorSampleDetails } from '../routes/errors/get_error_groups/get_error_sample_details';
import { parseDatemath } from './utils/time';

const getErrorByIdSchema = z.object({
...timeRangeSchema.shape,
errorId: z.string().describe('Error identifier to fetch the specific error document'),
serviceName: z.string().describe('Service name of the error document'),
environment: z.string().optional().describe('Optional environment filter'),
kqlFilter: z.string().optional().describe('Optional KQL filter to narrow results'),
});

export function createGetErrorByIdTool({
core,
plugins,
logger,
}: {
core: CoreSetup<APMPluginStartDependencies>;
plugins: APMPluginSetupDependencies;
logger: Logger;
}): StaticToolRegistration<typeof getErrorByIdSchema> {
const toolDefinition: BuiltinToolDefinition<typeof getErrorByIdSchema> = {
id: OBSERVABILITY_GET_ERROR_BY_ID_TOOL_ID,
type: ToolType.builtin,
description: 'Fetch a single error document by error.id or _id.',
schema: getErrorByIdSchema,
tags: ['observability', 'apm', 'error'],
availability: {
cacheMode: 'space',
handler: async ({ request }) => {
return getApmToolAvailability({ core, plugins, request, logger });
},
},
handler: async (args, context) => {
const { request, esClient, logger: scopedLogger } = context;
try {
const { apmEventClient } = await buildApmToolResources({
core,
plugins,
request,
esClient,
logger: scopedLogger,
});

const { start, end, errorId, serviceName, environment = '', kqlFilter = '' } = args;

const { error, transaction } = await getErrorSampleDetails({
environment,
kuery: kqlFilter,
serviceName,
errorId,
apmEventClient,
start: parseDatemath(start),
end: parseDatemath(end),
});

return {
results: [
{
type: ToolResultType.other,
data: {
error,
transaction,
},
},
],
};
} catch (error) {
logger.error(`Failed to fetch error by id: ${error.message}`);
logger.debug(error);

return {
results: [
{
type: ToolResultType.error,
data: { message: `Failed to fetch error: ${error.message}`, stack: error.stack },
},
],
};
}
},
};

return toolDefinition;
}
Loading