diff --git a/x-pack/platform/packages/shared/kbn-langchain/server/tracers/README.mdx b/x-pack/platform/packages/shared/kbn-langchain/server/tracers/README.mdx index b7ddd03ccf811..6b57683bf9611 100644 --- a/x-pack/platform/packages/shared/kbn-langchain/server/tracers/README.mdx +++ b/x-pack/platform/packages/shared/kbn-langchain/server/tracers/README.mdx @@ -1,29 +1,39 @@ -### Tracing LangChain Retrievers, LLMs, Chains, and Tools using Elastic APM and LangSmith +# LangChain Tracers -This document describes how to trace LangChain retrievers, LLMs, chains, and tools using Elastic APM and LangSmith. +This package provides tracers for monitoring and debugging LangChain retrievers, LLMs, chains, and tools within Kibana. -If the `assistantModelEvaluation` experimental feature flag is enabled, and an APM server is configured, messages that have a corresponding trace will have an additional `View APM trace` action in the message title bar: +## Available Tracers -

- -

+| Tracer | Purpose | Configuration | +|--------|---------|---------------| +| `APMTracer` | Elastic APM integration for distributed tracing | Kibana APM settings | +| `TelemetryTracer` | Event-based telemetry for usage analytics | Analytics service setup | +| `LangChainTracer` (LangSmith) | LangSmith integration for LLM observability | Environment variables or session storage | -Viewing the trace you can see a breakdown of the time spent in each retriever, llm, chain, and tool: -

- -

+## APMTracer -The Evaluation interface has been updated to support adding additional metadata like `Project Name`, `Run Name`, and pulling test datasets from LangSmith. Predictions can now also be run without having to run an Evaluation, so datasets can quickly be run for manual analysis. +The `APMTracer` integrates with Elastic APM to provide distributed tracing of LangChain operations. It creates spans for retrievers, LLMs, chains, and tools, allowing you to visualize the execution flow in APM. -

- -

+### Usage +```typescript +import { APMTracer } from '@kbn/langchain/server/tracers'; -

- -

+const tracer = new APMTracer( + { projectName: 'my-project', exampleId: 'optional-example-id' }, + logger +); + +// Pass to LangChain callbacks +const result = await chain.invoke(input, { callbacks: [tracer] }); +``` + +### Traced Operations +- `onRetrieverStart/End/Error` - Document retrieval operations +- `onLLMStart/End/Error` - LLM invocations +- `onChainStart/End/Error` - Chain executions +- `onToolStart/End/Error` - Tool calls ### Configuring APM @@ -33,7 +43,7 @@ First, enable the `assistantModelEvaluation` experimental feature flag by adding xpack.securitySolution.enableExperimental: [ 'assistantModelEvaluation' ] ``` -Next, you'll need an APM server to collect the traces. You can either [follow the documentation for installing](https://www.elastic.co/guide/en/apm/guide/current/installing.html) the released artifact, or [run from source](https://github.com/elastic/apm-server#apm-server-development) and set up using the [quickstart guide provided](https://www.elastic.co/guide/en/apm/guide/current/apm-quick-start.html) (be sure to install the APM Server integration to ensure the necessary indices are created! In dev environments you must click `Display beta integrations` on main Integrations page to ensure the latest package is installed.). Once your APM server is running, add your APM server configuration to your `kibana.dev.yml` as well using the following: +Next, you'll need an APM server to collect the traces. You can either [follow the documentation for installing](https://www.elastic.co/guide/en/apm/guide/current/installing.html) the released artifact, or [run from source](https://github.com/elastic/apm-server#apm-server-development) and set up using the [quickstart guide provided](https://www.elastic.co/guide/en/apm/guide/current/apm-quick-start.html) (be sure to install the APM Server integration to ensure the necessary indices are created! In dev environments you must click `Display beta integrations` on main Integrations page to ensure the latest package is installed.). Once your APM server is running, add your APM server configuration to your `kibana.dev.yml` as well using the following: ``` # APM @@ -54,7 +64,95 @@ If using a remote APM Server/Kibana instance for viewing traces, you can set the > If connecting to a cloud APM server (like our [ai-assistant apm deployment](https://ai-assistant-apm-do-not-delete.kb.us-central1.gcp.cloud.es.io/)), follow [these steps](https://www.elastic.co/guide/en/apm/guide/current/api-key.html#create-an-api-key) to create an API key, and then set it via `apiKey` and also set your `serverUrl` as shown in the APM Integration details within fleet. > [!NOTE] -> If you're an Elastic developer running Kibana from source, you can just enable APM as above, and _not_ include a `serverUrl`, and your traces will be sent to the https://kibana-cloud-apm.elastic.dev cluster. +> If you're an Elastic developer running Kibana from source, you can just enable APM as above, and _not_ include a `serverUrl`, and your traces will be sent to the https://kibana-cloud-apm.elastic.dev cluster. + +### Viewing Traces + +If the `assistantModelEvaluation` experimental feature flag is enabled, and an APM server is configured, messages that have a corresponding trace will have an additional `View APM trace` action in the message title bar: + +

+ +

+ +Viewing the trace you can see a breakdown of the time spent in each retriever, llm, chain, and tool: + +

+ +

+ +## TelemetryTracer + +The `TelemetryTracer` provides event-based telemetry for tracking LangChain usage analytics. It reports events to Kibana's analytics service for monitoring assistant interactions. + +### Usage + +```typescript +import { TelemetryTracer } from '@kbn/langchain/server/tracers'; + +const tracer = new TelemetryTracer( + { + elasticTools: ['tool1', 'tool2'], // List of known Elastic tool names + telemetry: analyticsService, + telemetryParams: { + assistantStreamingEnabled: true, + actionTypeId: '.gen-ai', + isEnabledKnowledgeBase: true, + eventType: 'invoke_assistant', + model: 'gpt-4', + }, + }, + logger +); + +// Pass to LangChain callbacks +const result = await chain.invoke(input, { callbacks: [tracer] }); +``` + +### Tracked Events + +- **`invoke_assistant`** - Emitted on chain completion with: + - Duration in milliseconds + - Tools invoked (with counts) + - Model and configuration details + - Knowledge base status + +- **`invoke_assistant_error`** - Emitted on tool errors with: + - Error message and location + - Action type and model info + - Configuration state + +### Telemetry Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `assistantStreamingEnabled` | `boolean` | Whether streaming is enabled | +| `actionTypeId` | `string` | The connector action type ID | +| `isEnabledKnowledgeBase` | `boolean` | Whether knowledge base is active | +| `eventType` | `string` | The telemetry event type to report | +| `model` | `string` (optional) | The LLM model being used | + +## LangSmith Tracer + +The LangSmith tracer integrates with [LangSmith](https://docs.smith.langchain.com/) for LLM observability and testing. + +### Usage + +```typescript +import { getLangSmithTracer, isLangSmithEnabled } from '@kbn/langchain/server/tracers'; + +// Check if LangSmith is enabled +if (isLangSmithEnabled()) { + const tracers = getLangSmithTracer({ + apiKey: 'your-api-key', // Optional, reads from env if not provided + projectName: 'my-project', + exampleId: 'optional-dataset-example-id', + logger, + }); + + // Pass to LangChain callbacks + const result = await chain.invoke(input, { callbacks: tracers }); +} +``` ### Configuring LangSmith @@ -70,3 +168,30 @@ export LANGCHAIN_PROJECT="8.12 ESQL Query Generation" If wanting to configure LangSmith in cloud or other environments where you may not have the ability to set env vars, you can set the `LangSmith Project` and `LangSmith API Key` values in session storage as outlined in https://github.com/elastic/kibana/pull/180227. +### Dataset Integration + +The Evaluation interface supports adding additional metadata like `Project Name`, `Run Name`, and pulling test datasets from LangSmith. Predictions can now also be run without having to run an Evaluation, so datasets can quickly be run for manual analysis. + +

+ +

+ +

+ +

+ +## Combining Multiple Tracers + +You can use multiple tracers simultaneously by passing them all to the callbacks array: + +```typescript +import { APMTracer, TelemetryTracer, getLangSmithTracer } from '@kbn/langchain/server/tracers'; + +const tracers = [ + new APMTracer({ projectName: 'my-project' }, logger), + new TelemetryTracer({ elasticTools, telemetry, telemetryParams }, logger), + ...getLangSmithTracer({ apiKey, projectName, logger }), +]; + +const result = await chain.invoke(input, { callbacks: tracers }); +``` diff --git a/x-pack/platform/packages/shared/kbn-langchain/server/tracers/index.ts b/x-pack/platform/packages/shared/kbn-langchain/server/tracers/index.ts new file mode 100644 index 0000000000000..eba98c54cfc59 --- /dev/null +++ b/x-pack/platform/packages/shared/kbn-langchain/server/tracers/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { APMTracer } from './apm'; +export { TelemetryTracer } from './telemetry'; +export type { TelemetryParams, LangChainTracerFields } from './telemetry'; +export { getLangSmithTracer, isLangSmithEnabled } from './langsmith'; diff --git a/x-pack/platform/packages/shared/kbn-langchain/server/tracers/telemetry/index.ts b/x-pack/platform/packages/shared/kbn-langchain/server/tracers/telemetry/index.ts index 079c0e9a33087..f0b33bc9b52af 100644 --- a/x-pack/platform/packages/shared/kbn-langchain/server/tracers/telemetry/index.ts +++ b/x-pack/platform/packages/shared/kbn-langchain/server/tracers/telemetry/index.ts @@ -6,3 +6,4 @@ */ export { TelemetryTracer } from './telemetry_tracer'; +export type { TelemetryParams, LangChainTracerFields } from './telemetry_tracer'; diff --git a/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/default/prompts/research_agent.ts b/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/default/prompts/research_agent.ts index b2106fe5ac474..8506577d8b514 100644 --- a/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/default/prompts/research_agent.ts +++ b/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/default/prompts/research_agent.ts @@ -152,21 +152,26 @@ If plausible organizational or product-specific knowledge is involved, default t Precedence sequence (stop at first applicable): 1. User-specified tool: If the user explicitly requests or has previously instructed you (for this session or similar queries) to use a specific tool and it is not clearly unsafe or irrelevant, use it first. If unsuitable or unavailable, skip and continue. - 2. Specialized tool: Use a domain-targeted tool that directly produces the needed answer more precisely than a general search. +${ + experimentalFeatures.skills + ? ` 2. Skill discovery (MANDATORY): Before using any general-purpose or specialized tool, check the SKILLS section. If any available skill description is relevant to the user's query, you MUST load it first by calling \\\`filestore.read\\\` with the skill's path. The loaded skill will provide domain-specific instructions and may unlock inline tools that are more precise than general alternatives. Only proceed to the next steps after loading the relevant skill. + 3. Specialized tool: Use a domain-targeted tool that directly produces the needed answer more precisely than a general search. Prefer inline tools loaded from a skill over general-purpose tools.` + : ` 2. Specialized tool: Use a domain-targeted tool that directly produces the needed answer more precisely than a general search.` +} Examples of specialized categories (illustrative, only use if available and relevant): • Custom domain / vertical analyzers (e.g., detection engineering, incident triage, attack pattern classifiers). • External system connectors (e.g., SaaS platform search) or federated knowledge base connectors (e.g., Confluence / wiki / code repo / ticketing / CRM / knowledge store), when required data resides outside Elasticsearch. • Structured analytics & aggregation tools (metrics, time-series rollups, statistical or anomaly detection utilities). • Log or event pattern mining, clustering, summarization, correlation, causality, or root-cause analytic utilities. - 3. General search fallback: If no user-specified or specialized tool applies, call \`${ + ${experimentalFeatures.skills ? '4' : '3'}. General search fallback: If no user-specified${experimentalFeatures.skills ? ', skill,' : ''} or specialized tool applies, call \`${ tools.search }\` (if available). **It can discover indices itself—do NOT call index tools just to find an index**. - 4. Index inspection fallback: Use \`${tools.indexExplorer}\` or \`${ + ${experimentalFeatures.skills ? '5' : '4'}. Index inspection fallback: Use \`${tools.indexExplorer}\` or \`${ tools.listIndices }\` ONLY if (a) the user explicitly asks to list / inspect indices / fields / metadata, OR (b) \`${ tools.search }\` is unavailable and structural discovery is necessary. - 5. Additional calls: If initial results do not fully answer all explicit sub-parts, issue targeted follow-up tool calls before asking the user for more info. + ${experimentalFeatures.skills ? '6' : '5'}. Additional calls: If initial results do not fully answer all explicit sub-parts, issue targeted follow-up tool calls before asking the user for more info. Constraints: - Do not delay an initial eligible search for non-mandatory clarifications. - **Ask 1-2 focused questions only if a mandatory parameter is missing and blocks any tool call.** @@ -180,9 +185,13 @@ Constraints: - If the query matches a category for bypassing research, your decision is made. Your only task is to respond in plain text to initiate the handover. Do not proceed to the next steps. Step 2 — Plan Research (if necessary) - If the query is informational and requires research, formulate a step-by-step plan to find the answer. - - Parse user intent, sub-questions, entities, constraints, etc. + - Parse user intent, sub-questions, entities, constraints, etc.${ + experimentalFeatures.skills + ? `\n - Check the SKILLS section: if any skill matches the query, your first action MUST be to load it via \\\`filestore.read\\\`.` + : '' + } Step 3 — Execute & Iterate - - Apply the Tool Selection Policy to execute the first step of your plan. + - Apply the Tool Selection Policy to execute the first step of your plan${experimentalFeatures.skills ? ' (skill loading takes priority)' : ''}. - After each tool call, review the gathered information. - If more information is needed, update your plan and execute the next tool call. Step 4 — Conclude Research diff --git a/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/utils/select_tools.ts b/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/utils/select_tools.ts index bb0d09747e7d5..fd1996ec3e379 100644 --- a/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/utils/select_tools.ts +++ b/x-pack/platform/plugins/shared/agent_builder/server/services/agents/modes/utils/select_tools.ts @@ -28,7 +28,7 @@ import type { ProcessedConversation } from './prepare_conversation'; export const selectTools = async ({ conversation, - previousDynamicToolIds, + previousDynamicToolIds = [], skills, request, toolProvider, @@ -37,19 +37,19 @@ export const selectTools = async ({ filestore, spaceId, runner, - experimentalFeatures, + experimentalFeatures = { filestore: false, skills: false }, }: { conversation: ProcessedConversation; - previousDynamicToolIds: string[]; - skills: SkillsService; + previousDynamicToolIds?: string[]; + skills?: SkillsService; request: KibanaRequest; toolProvider: ToolProvider; attachmentsService: AttachmentsService; - filestore: IFileStore; + filestore?: IFileStore; agentConfiguration: AgentConfiguration; spaceId: string; runner: ScopedRunner; - experimentalFeatures: ExperimentalFeatures; + experimentalFeatures?: ExperimentalFeatures; }) => { const formatContext: AttachmentFormatContext = { request, spaceId }; @@ -74,7 +74,7 @@ export const selectTools = async ({ }); // create tools for filesystem (only if feature is enabled) - const filestoreTools = experimentalFeatures.filestore + const filestoreTools = experimentalFeatures.filestore && filestore ? getStoreTools({ filestore }).map((tool) => builtinToolToExecutable({ tool, runner })) : []; @@ -105,17 +105,19 @@ export const selectTools = async ({ request, }); - const dynamicInlineTools = ( - await Promise.all( - skills - .list() - .filter((skill) => skill.getInlineTools !== undefined) - .map((skill) => skill.getInlineTools!()) + const dynamicInlineTools = skills + ? ( + await Promise.all( + skills + .list() + .filter((skill) => skill.getInlineTools !== undefined) + .map((skill) => skill.getInlineTools!()) + ) ) - ) - .flat() - .filter((tool) => previousDynamicToolIds.includes(tool.id)) - .map((tool) => skills.convertSkillTool(tool)); + .flat() + .filter((tool) => previousDynamicToolIds.includes(tool.id)) + .map((tool) => skills.convertSkillTool(tool)) + : []; return { staticTools: [...dedupedStaticTools.values()], diff --git a/x-pack/platform/plugins/shared/agent_builder/server/services/skills/prompts.ts b/x-pack/platform/plugins/shared/agent_builder/server/services/skills/prompts.ts index 791af4f1860d2..c2ea91d8489c4 100644 --- a/x-pack/platform/plugins/shared/agent_builder/server/services/skills/prompts.ts +++ b/x-pack/platform/plugins/shared/agent_builder/server/services/skills/prompts.ts @@ -28,9 +28,10 @@ export const getSkillsInstructions = async ({ : [ '## SKILLS', [ - 'Load a skill using filestore tools to get detailed instructions for a specific task.', - 'Skills provide specialized knowledge and best practices for specific tasks.', - "Use them when a task matches a skill's description or the skill is useful for the task.", + 'Before using any general-purpose tool or model knowledge, you MUST first check the available skills below.', + 'If ANY skill description matches or is relevant to the user query, you MUST load it by calling `filestore.read` with the skill path BEFORE calling any other tool.', + 'Skills provide specialized knowledge, domain-specific instructions, and access to inline tools that produce more accurate results than general-purpose alternatives.', + 'Skipping a relevant skill and going directly to general tools (e.g., search, execute_esql) is a protocol violation.', 'Only the skills listed here are available:', ].join(' '), generateXmlTree({ diff --git a/x-pack/platform/plugins/shared/agent_builder/server/tracing/create_tracer.test.ts b/x-pack/platform/plugins/shared/agent_builder/server/tracing/create_tracer.test.ts new file mode 100644 index 0000000000000..24cc92e5ba125 --- /dev/null +++ b/x-pack/platform/plugins/shared/agent_builder/server/tracing/create_tracer.test.ts @@ -0,0 +1,112 @@ +/* + * 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 { trace } from '@opentelemetry/api'; +import { + createTracer, + createTracerFactory, + getAgentBuilderTracer, + AGENT_BUILDER_TRACER_NAME, +} from './create_tracer'; + +describe('create_tracer', () => { + describe('createTracer', () => { + it('creates a tracer with the default name', () => { + const tracer = createTracer(); + + expect(tracer).toBeDefined(); + // The tracer should be retrievable with the same name + expect(tracer).toBe(trace.getTracer(AGENT_BUILDER_TRACER_NAME)); + }); + + it('creates a tracer with a custom name', () => { + const customName = 'agent_builder/tools'; + const tracer = createTracer({ name: customName }); + + expect(tracer).toBeDefined(); + expect(tracer).toBe(trace.getTracer(customName)); + }); + + it('creates a versioned tracer', () => { + const version = '1.0.0'; + const tracer = createTracer({ version }); + + expect(tracer).toBeDefined(); + expect(tracer).toBe(trace.getTracer(AGENT_BUILDER_TRACER_NAME, version)); + }); + + it('creates a tracer with custom name and version', () => { + const name = 'agent_builder/runner'; + const version = '2.0.0'; + const tracer = createTracer({ name, version }); + + expect(tracer).toBeDefined(); + expect(tracer).toBe(trace.getTracer(name, version)); + }); + }); + + describe('getAgentBuilderTracer', () => { + it('returns the default agent_builder tracer', () => { + const tracer = getAgentBuilderTracer(); + + expect(tracer).toBeDefined(); + expect(tracer).toBe(trace.getTracer(AGENT_BUILDER_TRACER_NAME)); + }); + + it('returns the same tracer instance on multiple calls', () => { + const tracer1 = getAgentBuilderTracer(); + const tracer2 = getAgentBuilderTracer(); + + expect(tracer1).toBe(tracer2); + }); + }); + + describe('createTracerFactory', () => { + it('creates a factory that produces tracers with default options', () => { + const factory = createTracerFactory(); + + const tracer = factory(); + expect(tracer).toBeDefined(); + expect(tracer).toBe(trace.getTracer(AGENT_BUILDER_TRACER_NAME)); + }); + + it('creates a factory that produces named tracers', () => { + const factory = createTracerFactory(); + + const toolsTracer = factory('agent_builder/tools'); + const runnerTracer = factory('agent_builder/runner'); + + expect(toolsTracer).toBe(trace.getTracer('agent_builder/tools')); + expect(runnerTracer).toBe(trace.getTracer('agent_builder/runner')); + expect(toolsTracer).not.toBe(runnerTracer); + }); + + it('creates a factory with shared version', () => { + const version = '1.0.0'; + const factory = createTracerFactory({ version }); + + const tracer1 = factory('agent_builder/scope1'); + const tracer2 = factory('agent_builder/scope2'); + + expect(tracer1).toBe(trace.getTracer('agent_builder/scope1', version)); + expect(tracer2).toBe(trace.getTracer('agent_builder/scope2', version)); + }); + + it('falls back to default name when called without arguments', () => { + const factory = createTracerFactory({ version: '1.0.0' }); + + const tracer = factory(); + expect(tracer).toBe(trace.getTracer(AGENT_BUILDER_TRACER_NAME, '1.0.0')); + }); + }); + + describe('AGENT_BUILDER_TRACER_NAME', () => { + it('has the expected value', () => { + expect(AGENT_BUILDER_TRACER_NAME).toBe('agent_builder'); + }); + }); +}); diff --git a/x-pack/platform/plugins/shared/agent_builder/server/tracing/create_tracer.ts b/x-pack/platform/plugins/shared/agent_builder/server/tracing/create_tracer.ts new file mode 100644 index 0000000000000..866391c1404fd --- /dev/null +++ b/x-pack/platform/plugins/shared/agent_builder/server/tracing/create_tracer.ts @@ -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 type { Tracer, TracerOptions } from '@opentelemetry/api'; +import { trace } from '@opentelemetry/api'; + +/** Default tracer name for agent_builder plugin */ +export const AGENT_BUILDER_TRACER_NAME = 'agent_builder'; + +export interface CreateTracerOptions { + /** + * Name of the tracer. This appears in spans and helps identify the source. + * Defaults to 'agent_builder'. + */ + name?: string; + /** + * Version of the tracer/instrumentation. Typically the plugin version. + */ + version?: string; + /** + * Additional OpenTelemetry tracer options. + */ + tracerOptions?: TracerOptions; +} + +/** + * Creates a tracer for the agent_builder plugin. + * + * Tracers are used to create spans for distributed tracing. Each tracer + * should have a unique name that identifies the instrumentation scope + * (e.g., 'agent_builder', 'agent_builder/tools', 'agent_builder/runner'). + * + * @example + * ```ts + * // Create default agent_builder tracer + * const tracer = createTracer(); + * + * // Create a tracer for a specific scope + * const toolsTracer = createTracer({ name: 'agent_builder/tools' }); + * + * // Create a versioned tracer + * const versionedTracer = createTracer({ + * name: 'agent_builder', + * version: '1.0.0' + * }); + * ``` + */ +export function createTracer(options: CreateTracerOptions = {}): Tracer { + const { name = AGENT_BUILDER_TRACER_NAME, version, tracerOptions } = options; + return trace.getTracer(name, version, tracerOptions); +} + +/** + * Returns the default tracer for the agent_builder plugin. + * + * This is a convenience function that returns a singleton-like tracer + * with the default agent_builder name. Use this when you don't need + * a specific tracer scope. + * + * @example + * ```ts + * import { getAgentBuilderTracer } from './tracing'; + * + * const tracer = getAgentBuilderTracer(); + * tracer.startSpan('myOperation'); + * ``` + */ +export function getAgentBuilderTracer(): Tracer { + return createTracer(); +} + +/** + * Creates a factory function for tracers with a shared configuration. + * + * Useful when you need to create multiple tracers with the same base + * configuration (e.g., same version) but different names. + * + * @example + * ```ts + * const tracerFactory = createTracerFactory({ version: '1.0.0' }); + * + * const agentTracer = tracerFactory('agent_builder/agent'); + * const toolTracer = tracerFactory('agent_builder/tools'); + * const runnerTracer = tracerFactory('agent_builder/runner'); + * ``` + */ +export function createTracerFactory( + baseOptions: Omit = {} +): (name?: string) => Tracer { + return (name?: string) => { + return createTracer({ + ...baseOptions, + name: name ?? AGENT_BUILDER_TRACER_NAME, + }); + }; +} diff --git a/x-pack/platform/plugins/shared/agent_builder/server/tracing/index.ts b/x-pack/platform/plugins/shared/agent_builder/server/tracing/index.ts index 4a90b285401c1..449b689be5216 100644 --- a/x-pack/platform/plugins/shared/agent_builder/server/tracing/index.ts +++ b/x-pack/platform/plugins/shared/agent_builder/server/tracing/index.ts @@ -8,3 +8,10 @@ export { withAgentSpan } from './with_agent_span'; export { withConverseSpan } from './with_converse_span'; export { getCurrentTraceId } from './get_current_trace_id'; +export { + createTracer, + createTracerFactory, + getAgentBuilderTracer, + AGENT_BUILDER_TRACER_NAME, +} from './create_tracer'; +export type { CreateTracerOptions } from './create_tracer';