eve 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/src/channel/adapter.d.ts +2 -1
  3. package/dist/src/channel/instrumentation.js +1 -1
  4. package/dist/src/cli/commands/registry-project.d.ts +3 -0
  5. package/dist/src/cli/commands/registry-project.js +2 -1
  6. package/dist/src/cli/commands/registry.d.ts +2 -0
  7. package/dist/src/cli/commands/registry.js +1 -1
  8. package/dist/src/cli/dev/tui/traces/trace-view.js +1 -1
  9. package/dist/src/compiled/.vendor-stamp.json +1 -1
  10. package/dist/src/compiled/jsonc-parser/index.d.ts +19 -0
  11. package/dist/src/compiler/extension-compatibility.d.ts +2 -2
  12. package/dist/src/compiler/extension-compatibility.js +1 -1
  13. package/dist/src/execution/workflow-trace-context.js +1 -1
  14. package/dist/src/harness/channel-delivery-instrumentation.js +1 -1
  15. package/dist/src/harness/instrumentation/lifecycle.d.ts +4 -0
  16. package/dist/src/harness/instrumentation/native-events.d.ts +2 -0
  17. package/dist/src/harness/instrumentation/native-events.js +1 -1
  18. package/dist/src/harness/prepare-trace-context.d.ts +2 -0
  19. package/dist/src/harness/prepare-trace-context.js +1 -1
  20. package/dist/src/harness/tool-loop.js +2 -2
  21. package/dist/src/internal/application/package.js +1 -1
  22. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
  23. package/dist/src/public/channels/chat-sdk/audience.d.ts +2 -0
  24. package/dist/src/public/channels/chat-sdk/audience.js +1 -0
  25. package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +2 -0
  26. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  27. package/dist/src/public/channels/discord/audience.d.ts +5 -0
  28. package/dist/src/public/channels/discord/audience.js +1 -0
  29. package/dist/src/public/channels/discord/discordChannel.d.ts +2 -0
  30. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  31. package/dist/src/public/channels/discord/inbound.d.ts +1 -0
  32. package/dist/src/public/channels/discord/inbound.js +1 -1
  33. package/dist/src/public/channels/discord/index.d.ts +1 -0
  34. package/dist/src/public/channels/index.d.ts +3 -2
  35. package/dist/src/public/channels/slack/slackChannel.d.ts +4 -0
  36. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  37. package/dist/src/public/channels/teams/index.d.ts +1 -0
  38. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  39. package/dist/src/public/channels/telegram/audience.d.ts +3 -0
  40. package/dist/src/public/channels/telegram/audience.js +1 -0
  41. package/dist/src/public/channels/telegram/index.d.ts +1 -0
  42. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  43. package/dist/src/public/channels/twilio/twilioChannel.d.ts +2 -0
  44. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  45. package/dist/src/public/definitions/channel.d.ts +1 -0
  46. package/dist/src/public/instrumentation/otel.d.ts +6 -10
  47. package/dist/src/public/instrumentation/otel.js +1 -1
  48. package/dist/src/setup/scaffold/create/project.js +1 -1
  49. package/dist/src/setup/scaffold/create/web-template.d.ts +2 -1
  50. package/dist/src/setup/scaffold/create/web-template.js +373 -1
  51. package/dist/src/shared/channel-audience.d.ts +7 -0
  52. package/dist/src/shared/channel-audience.js +1 -0
  53. package/dist/src/shared/channel-definition.d.ts +2 -1
  54. package/dist/src/tracing/agent-action-instrumentation.js +1 -1
  55. package/dist/src/tracing/agent-approval-instrumentation.js +1 -1
  56. package/dist/src/tracing/agent-channel-delivery-instrumentation.js +1 -1
  57. package/dist/src/tracing/agent-otel-provider.d.ts +2 -0
  58. package/dist/src/tracing/agent-otel-provider.js +2 -2
  59. package/dist/src/tracing/agent-otel-session-context.d.ts +2 -0
  60. package/dist/src/tracing/agent-otel-session-context.js +1 -1
  61. package/dist/src/tracing/agent-trace-context-store.js +1 -1
  62. package/dist/src/tracing/agent-trace-state.d.ts +3 -0
  63. package/dist/src/tracing/channel-audience-context.d.ts +4 -0
  64. package/dist/src/tracing/channel-audience-context.js +1 -0
  65. package/dist/src/tracing/content-attributes.js +1 -1
  66. package/dist/src/tracing/content-span-processor.d.ts +7 -7
  67. package/dist/src/tracing/content-span-processor.js +1 -1
  68. package/dist/src/tracing/install-instrumentation-runtime.js +1 -1
  69. package/dist/src/tracing/local-instrumentation-runtime.d.ts +3 -0
  70. package/dist/src/tracing/local-instrumentation-runtime.js +1 -1
  71. package/dist/src/tracing/local-traces.d.ts +1 -10
  72. package/dist/src/tracing/local-traces.js +1 -1
  73. package/dist/src/tracing/otel-declaration.d.ts +34 -27
  74. package/dist/src/tracing/otel-declaration.js +1 -1
  75. package/dist/src/tracing/sampled-trace.d.ts +2 -0
  76. package/dist/src/tracing/sampled-trace.js +1 -0
  77. package/dist/src/tracing/span-export-policy.d.ts +41 -0
  78. package/dist/src/tracing/span-export-policy.js +1 -0
  79. package/dist/src/tracing/suppress-tracing.d.ts +2 -0
  80. package/dist/src/tracing/suppress-tracing.js +1 -0
  81. package/docs/channels/custom.mdx +2 -0
  82. package/docs/guides/instrumentation.md +2 -0
  83. package/docs/tutorial/ship-it.mdx +1 -1
  84. package/package.json +1 -1
@@ -208,6 +208,7 @@ import type {
208
208
  EveAuthorizationPart,
209
209
  EveDynamicToolPart,
210
210
  EveMessage,
211
+ EveMessageInputRequest,
211
212
  EveMessagePart,
212
213
  } from "eve/react";
213
214
  import {
@@ -219,6 +220,17 @@ import {
219
220
  XCircleIcon,
220
221
  } from "lucide-react";
221
222
  import { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";
223
+ import {
224
+ Question,
225
+ QuestionActions,
226
+ QuestionDescription,
227
+ QuestionInput,
228
+ QuestionOption,
229
+ QuestionOptions,
230
+ QuestionPrompt,
231
+ type QuestionResponse,
232
+ QuestionSubmit,
233
+ } from "@/components/ai-elements/question";
222
234
  import { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";
223
235
  import {
224
236
  Tool,
@@ -305,7 +317,19 @@ function AgentMessagePart({
305
317
  return <AttachmentPart part={part} />;
306
318
  case "authorization":
307
319
  return <AuthorizationPrompt part={part} />;
308
- case "dynamic-tool":
320
+ case "dynamic-tool": {
321
+ const inputRequest = part.toolMetadata?.eve?.inputRequest;
322
+ if (inputRequest?.kind === "question") {
323
+ return (
324
+ <QuestionRequest
325
+ canRespond={canRespond}
326
+ inputRequest={inputRequest}
327
+ inputResponse={part.toolMetadata?.eve?.inputResponse}
328
+ onInputResponses={onInputResponses}
329
+ />
330
+ );
331
+ }
332
+
309
333
  return (
310
334
  <Tool
311
335
  defaultOpen={part.state === "approval-requested" || part.state === "approval-responded"}
@@ -327,9 +351,76 @@ function AgentMessagePart({
327
351
  </ToolContent>
328
352
  </Tool>
329
353
  );
354
+ }
330
355
  }
331
356
  }
332
357
 
358
+ function QuestionRequest({
359
+ canRespond,
360
+ inputRequest,
361
+ inputResponse,
362
+ onInputResponses,
363
+ }: {
364
+ readonly canRespond: boolean;
365
+ readonly inputRequest: EveMessageInputRequest;
366
+ readonly inputResponse?: AgentInputResponse;
367
+ readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;
368
+ }) {
369
+ const selectedOption = inputRequest.options?.find(
370
+ (option) => option.id === inputResponse?.optionId,
371
+ );
372
+ const hasOptions = (inputRequest.options?.length ?? 0) > 0;
373
+ const acceptsFreeform = inputRequest.allowFreeform === true || !hasOptions;
374
+
375
+ const submitResponse = ({ selectedValues, text }: QuestionResponse) =>
376
+ onInputResponses([
377
+ {
378
+ optionId: selectedValues[0],
379
+ requestId: inputRequest.requestId,
380
+ text,
381
+ },
382
+ ]);
383
+
384
+ return (
385
+ <Question
386
+ defaultValue={{
387
+ selectedValues: inputResponse?.optionId ? [inputResponse.optionId] : [],
388
+ text: inputResponse?.text ?? "",
389
+ }}
390
+ disabled={!canRespond || inputResponse !== undefined}
391
+ onSubmit={submitResponse}
392
+ >
393
+ <QuestionPrompt>{inputRequest.prompt}</QuestionPrompt>
394
+ {hasOptions ? (
395
+ <QuestionOptions className="flex-col items-stretch" aria-label={inputRequest.prompt}>
396
+ {inputRequest.options?.map((option) => (
397
+ <QuestionOption className="justify-start text-left" key={option.id} value={option.id}>
398
+ <span>
399
+ <span className="block">{option.label}</span>
400
+ {option.description ? (
401
+ <span className="block font-normal text-xs opacity-70">{option.description}</span>
402
+ ) : null}
403
+ </span>
404
+ </QuestionOption>
405
+ ))}
406
+ </QuestionOptions>
407
+ ) : null}
408
+ {acceptsFreeform ? (
409
+ <QuestionInput aria-label="Answer" placeholder="Type your answer…" />
410
+ ) : null}
411
+ {inputResponse ? (
412
+ <QuestionDescription>
413
+ Responded: {selectedOption?.label ?? inputResponse.text ?? inputResponse.optionId}
414
+ </QuestionDescription>
415
+ ) : (
416
+ <QuestionActions>
417
+ <QuestionSubmit>Answer</QuestionSubmit>
418
+ </QuestionActions>
419
+ )}
420
+ </Question>
421
+ );
422
+ }
423
+
333
424
  function AttachmentPart({ part }: { readonly part: EveFilePart }) {
334
425
  const label = part.filename ?? "Attachment";
335
426
  const detail = [part.mediaType, formatBytes(part.size)].filter(Boolean).join(" - ");
@@ -3149,6 +3240,287 @@ export const PromptInputCommandSeparator = ({
3149
3240
  className,
3150
3241
  ...props
3151
3242
  }: PromptInputCommandSeparatorProps) => <CommandSeparator className={cn(className)} {...props} />;
3243
+ `,"components/ai-elements/question.tsx":`"use client";
3244
+
3245
+ import type {
3246
+ ChangeEvent,
3247
+ ComponentProps,
3248
+ FormEvent,
3249
+ HTMLAttributes,
3250
+ MouseEvent,
3251
+ ReactNode,
3252
+ } from "react";
3253
+
3254
+ import { Button } from "@/components/ui/button";
3255
+ import { Textarea } from "@/components/ui/textarea";
3256
+ import { cn } from "@/lib/utils";
3257
+ import { createContext, useCallback, useContext, useMemo, useState } from "react";
3258
+
3259
+ export interface QuestionValue {
3260
+ selectedValues: readonly string[];
3261
+ text: string;
3262
+ }
3263
+
3264
+ export interface QuestionResponse {
3265
+ selectedValues: readonly string[];
3266
+ text?: string;
3267
+ }
3268
+
3269
+ type SelectionMode = "multiple" | "single";
3270
+
3271
+ interface QuestionContextValue {
3272
+ disabled: boolean;
3273
+ selectedValues: readonly string[];
3274
+ selectionMode: SelectionMode;
3275
+ setText: (text: string) => void;
3276
+ text: string;
3277
+ toggleValue: (value: string) => void;
3278
+ }
3279
+
3280
+ const QuestionContext = createContext<QuestionContextValue | null>(null);
3281
+
3282
+ const useQuestion = () => {
3283
+ const context = useContext(QuestionContext);
3284
+
3285
+ if (!context) {
3286
+ throw new Error("Question components must be used within Question");
3287
+ }
3288
+
3289
+ return context;
3290
+ };
3291
+
3292
+ export type QuestionProps = Omit<ComponentProps<"form">, "defaultValue" | "onSubmit" | "value"> & {
3293
+ defaultValue?: QuestionValue;
3294
+ disabled?: boolean;
3295
+ onSubmit?: (
3296
+ response: QuestionResponse,
3297
+ event: FormEvent<HTMLFormElement>,
3298
+ ) => void | Promise<void>;
3299
+ onValueChange?: (value: QuestionValue) => void;
3300
+ selectionMode?: SelectionMode;
3301
+ value?: QuestionValue;
3302
+ };
3303
+
3304
+ const EMPTY_VALUE: QuestionValue = { selectedValues: [], text: "" };
3305
+
3306
+ const getSelectedValues = (
3307
+ currentValues: readonly string[],
3308
+ optionValue: string,
3309
+ selectionMode: SelectionMode,
3310
+ ): readonly string[] => {
3311
+ const isSelected = currentValues.includes(optionValue);
3312
+
3313
+ if (selectionMode === "single") {
3314
+ return isSelected ? [] : [optionValue];
3315
+ }
3316
+
3317
+ if (isSelected) {
3318
+ return currentValues.filter((item) => item !== optionValue);
3319
+ }
3320
+
3321
+ return [...currentValues, optionValue];
3322
+ };
3323
+
3324
+ export const Question = ({
3325
+ children,
3326
+ className,
3327
+ defaultValue = EMPTY_VALUE,
3328
+ disabled = false,
3329
+ onSubmit,
3330
+ onValueChange,
3331
+ selectionMode = "single",
3332
+ value: controlledValue,
3333
+ ...props
3334
+ }: QuestionProps) => {
3335
+ const [internalValue, setInternalValue] = useState(defaultValue);
3336
+ const value = controlledValue ?? internalValue;
3337
+
3338
+ const setValue = useCallback(
3339
+ (nextValue: QuestionValue) => {
3340
+ if (controlledValue === undefined) {
3341
+ setInternalValue(nextValue);
3342
+ }
3343
+ onValueChange?.(nextValue);
3344
+ },
3345
+ [controlledValue, onValueChange],
3346
+ );
3347
+
3348
+ const setText = useCallback(
3349
+ (text: string) => {
3350
+ setValue({ ...value, text });
3351
+ },
3352
+ [setValue, value],
3353
+ );
3354
+
3355
+ const toggleValue = useCallback(
3356
+ (optionValue: string) => {
3357
+ const selectedValues = getSelectedValues(value.selectedValues, optionValue, selectionMode);
3358
+ setValue({ ...value, selectedValues });
3359
+ },
3360
+ [selectionMode, setValue, value],
3361
+ );
3362
+
3363
+ const contextValue = useMemo(
3364
+ () => ({
3365
+ disabled,
3366
+ selectedValues: value.selectedValues,
3367
+ selectionMode,
3368
+ setText,
3369
+ text: value.text,
3370
+ toggleValue,
3371
+ }),
3372
+ [disabled, selectionMode, setText, toggleValue, value],
3373
+ );
3374
+
3375
+ const handleSubmit = useCallback(
3376
+ async (event: FormEvent<HTMLFormElement>) => {
3377
+ event.preventDefault();
3378
+ if (disabled) {
3379
+ return;
3380
+ }
3381
+
3382
+ const text = value.text.trim();
3383
+ if (value.selectedValues.length === 0 && text.length === 0) {
3384
+ return;
3385
+ }
3386
+
3387
+ await onSubmit?.(
3388
+ {
3389
+ selectedValues: value.selectedValues,
3390
+ text: text.length > 0 ? text : undefined,
3391
+ },
3392
+ event,
3393
+ );
3394
+ },
3395
+ [disabled, onSubmit, value],
3396
+ );
3397
+
3398
+ return (
3399
+ <QuestionContext.Provider value={contextValue}>
3400
+ <form
3401
+ className={cn("space-y-4 rounded-lg border bg-background p-4", className)}
3402
+ onSubmit={handleSubmit}
3403
+ {...props}
3404
+ >
3405
+ {children}
3406
+ </form>
3407
+ </QuestionContext.Provider>
3408
+ );
3409
+ };
3410
+
3411
+ export type QuestionPromptProps = HTMLAttributes<HTMLParagraphElement>;
3412
+
3413
+ export const QuestionPrompt = ({ className, ...props }: QuestionPromptProps) => (
3414
+ <p className={cn("font-medium text-sm", className)} {...props} />
3415
+ );
3416
+
3417
+ export type QuestionDescriptionProps = HTMLAttributes<HTMLParagraphElement>;
3418
+
3419
+ export const QuestionDescription = ({ className, ...props }: QuestionDescriptionProps) => (
3420
+ <p className={cn("text-muted-foreground text-sm", className)} {...props} />
3421
+ );
3422
+
3423
+ export type QuestionOptionsProps = HTMLAttributes<HTMLDivElement>;
3424
+
3425
+ export const QuestionOptions = ({ className, ...props }: QuestionOptionsProps) => {
3426
+ const { selectionMode } = useQuestion();
3427
+
3428
+ return (
3429
+ <div
3430
+ className={cn("flex flex-wrap gap-2", className)}
3431
+ role={selectionMode === "single" ? "radiogroup" : "group"}
3432
+ {...props}
3433
+ />
3434
+ );
3435
+ };
3436
+
3437
+ export type QuestionOptionProps = Omit<ComponentProps<typeof Button>, "value"> & {
3438
+ value: string;
3439
+ };
3440
+
3441
+ export const QuestionOption = ({
3442
+ children,
3443
+ className,
3444
+ disabled,
3445
+ onClick,
3446
+ value,
3447
+ variant,
3448
+ ...props
3449
+ }: QuestionOptionProps) => {
3450
+ const question = useQuestion();
3451
+ const isSelected = question.selectedValues.includes(value);
3452
+ const role = question.selectionMode === "single" ? "radio" : "checkbox";
3453
+ const handleClick = useCallback(
3454
+ (event: MouseEvent<HTMLButtonElement>) => {
3455
+ question.toggleValue(value);
3456
+ onClick?.(event);
3457
+ },
3458
+ [onClick, question, value],
3459
+ );
3460
+
3461
+ return (
3462
+ <Button
3463
+ aria-checked={isSelected}
3464
+ className={cn("h-auto whitespace-normal", className)}
3465
+ disabled={question.disabled || disabled}
3466
+ onClick={handleClick}
3467
+ role={role}
3468
+ type="button"
3469
+ variant={variant ?? (isSelected ? "default" : "outline")}
3470
+ {...props}
3471
+ >
3472
+ {children ?? value}
3473
+ </Button>
3474
+ );
3475
+ };
3476
+
3477
+ export type QuestionInputProps = Omit<ComponentProps<typeof Textarea>, "defaultValue" | "value">;
3478
+
3479
+ export const QuestionInput = ({ className, disabled, onChange, ...props }: QuestionInputProps) => {
3480
+ const question = useQuestion();
3481
+ const handleChange = useCallback(
3482
+ (event: ChangeEvent<HTMLTextAreaElement>) => {
3483
+ question.setText(event.currentTarget.value);
3484
+ onChange?.(event);
3485
+ },
3486
+ [onChange, question],
3487
+ );
3488
+
3489
+ return (
3490
+ <Textarea
3491
+ className={cn("min-h-20", className)}
3492
+ disabled={question.disabled || disabled}
3493
+ onChange={handleChange}
3494
+ value={question.text}
3495
+ {...props}
3496
+ />
3497
+ );
3498
+ };
3499
+
3500
+ export type QuestionActionsProps = HTMLAttributes<HTMLDivElement>;
3501
+
3502
+ export const QuestionActions = ({ className, ...props }: QuestionActionsProps) => (
3503
+ <div className={cn("flex items-center justify-end gap-2", className)} {...props} />
3504
+ );
3505
+
3506
+ export type QuestionSubmitProps = ComponentProps<typeof Button> & {
3507
+ children?: ReactNode;
3508
+ };
3509
+
3510
+ export const QuestionSubmit = ({
3511
+ children = "Submit",
3512
+ disabled,
3513
+ ...props
3514
+ }: QuestionSubmitProps) => {
3515
+ const question = useQuestion();
3516
+ const hasResponse = question.selectedValues.length > 0 || question.text.trim().length > 0;
3517
+
3518
+ return (
3519
+ <Button disabled={question.disabled || disabled || !hasResponse} type="submit" {...props}>
3520
+ {children}
3521
+ </Button>
3522
+ );
3523
+ };
3152
3524
  `,"components/ai-elements/reasoning.tsx":`"use client";
3153
3525
 
3154
3526
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
@@ -0,0 +1,7 @@
1
+ export declare const CHANNEL_AUDIENCES: readonly ["public", "private", "unknown"];
2
+ /** Who can observe the conversation on its originating channel. */
3
+ export type ChannelAudience = (typeof CHANNEL_AUDIENCES)[number];
4
+ export interface ChannelAudienceMetadata {
5
+ readonly audience?: ChannelAudience;
6
+ }
7
+ export declare function normalizeChannelAudience(value: unknown): ChannelAudience;
@@ -0,0 +1 @@
1
+ const CHANNEL_AUDIENCES=[`public`,`private`,`unknown`];function normalizeChannelAudience(e){return typeof e==`string`&&CHANNEL_AUDIENCES.includes(e)?e:`unknown`}export{CHANNEL_AUDIENCES,normalizeChannelAudience};
@@ -5,6 +5,7 @@ import type { RouteDefinition } from "#channel/routes.js";
5
5
  import type { Session, SessionHandle } from "#channel/session.js";
6
6
  import type { DeliverPayload, SessionAuthContext, TurnPolicy } from "#channel/types.js";
7
7
  import type { StepInput } from "#harness/types.js";
8
+ import type { ChannelAudienceMetadata } from "#shared/channel-audience.js";
8
9
  /**
9
10
  * Enriched return shape from a channel's {@link ChannelAdapter.fetchFile}
10
11
  * function. Return a bare {@link Buffer} when only bytes are known, or
@@ -40,7 +41,7 @@ export interface GenericReceiveInput<TReceiveTarget = Record<string, unknown>> {
40
41
  * `TReceiveTarget` (cross-channel target shape), `TMetadata` (instrumentation
41
42
  * projection).
42
43
  */
43
- export interface GenericChannelDefinition<TEvents, TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
44
+ export interface GenericChannelDefinition<TEvents, TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> & ChannelAudienceMetadata = Record<string, unknown>> {
44
45
  /** Policy used by message sends that do not provide an explicit override. */
45
46
  readonly turnPolicy?: TurnPolicy;
46
47
  deliver?(payload: DeliverPayload, ctx: TCtx): StepInput | void | Promise<StepInput | void>;
@@ -1 +1 @@
1
- import{ROOT_CONTEXT,SpanStatusCode,trace}from"#compiled/@opentelemetry/api/index.js";import{actionIdempotencyKey,attemptIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{contentAttribute}from"#tracing/agent-otel-content.js";import{setAgentUsage}from"#tracing/agent-otel-usage.js";function createAgentActionInstrumentation(e){let t=new Map,onStarted=async n=>{let r=await e.resolveTraceContext(n);if(r===void 0)return;let o=await e.stateStore.getAction(n.idempotencyKey)??{attemptIndex:n.scope.attemptIndex,callId:n.callId,inputAttribute:e.recordInputs?contentAttribute(n.input,!1):void 0,kind:n.kind,name:n.name,parent:{spanId:e.idGenerator.deriveSpanId(attemptIdempotencyKey(n.scope)),traceFlags:r.traceFlags,traceId:r.traceId},rootSessionId:n.scope.rootSessionId??n.scope.sessionId,sessionId:n.scope.sessionId,spanId:e.idGenerator.deriveSpanId(`action:${n.idempotencyKey}`),startTimeMs:Date.now(),stepIndex:n.scope.stepIndex,turnId:n.scope.turnId};await e.stateStore.setAction(n.idempotencyKey,o);let s=t.get(n.scope.attemptId)??new Set;s.add(n.idempotencyKey),t.set(n.scope.attemptId,s)},onTerminal=async t=>{let n=await e.stateStore.getAction(t.idempotencyKey);if(n!==void 0)try{let r=startSpan(n);if(r.setAttribute(`agent.action.outcome`,t.outcome),t.type===`action.failed`)t.errorCode!==void 0&&(r.setAttribute(`agent.action.error.code`,t.errorCode),r.setAttribute(`error.type`,t.errorCode)),recordError(r,t.error);else if(t.output.type===`error`)recordError(r,t.output.error);else if(t.usage!==void 0&&setAgentUsage(r,t.usage),e.recordOutputs){let e=contentAttribute(t.output.output,!1);e!==void 0&&r.setAttribute(`gen_ai.tool.call.result`,e)}r.end(t.acceptedAtMs)}finally{await e.stateStore.deleteAction(t.idempotencyKey),forget(t.idempotencyKey)}},startSpan=t=>{let n=e.idGenerator.withSpanId(t.spanId,()=>e.tracer.startSpan(`agent.action`,{attributes:{"agent.action.call_id":t.callId,"agent.action.kind":t.kind,"agent.action.name":t.name,"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.root.session.id":t.rootSessionId,"agent.session.id":t.sessionId,"agent.step.attempt":t.attemptIndex,"agent.step.index":t.stepIndex,"agent.turn.id":t.turnId},startTime:t.startTimeMs},contextFromActionState(t)));return t.inputAttribute!==void 0&&n.setAttribute(`gen_ai.tool.call.arguments`,t.inputAttribute),n};return{async contextFor(t,n,i){let a=actionIdempotencyKey(t,n,i),o=await e.stateStore.getAction(a);if(o!==void 0)return actionContext(o);let s=await e.stateStore.findAction(t,i);return s===void 0?void 0:actionContext(s)},deleteForSession:t=>e.stateStore.deleteActions(t),deleteForTurn:(t,n)=>e.stateStore.deleteActions(t,n),async failForAttempt(n,r){let i=t.get(n.attemptId);if(i!==void 0){t.delete(n.attemptId);for(let t of i){let n=await e.stateStore.getAction(t);if(n===void 0)continue;let i=startSpan(n);recordError(i,r),i.end(),await e.stateStore.deleteAction(t)}}},events:{"action.completed":onTerminal,"action.failed":onTerminal,"action.started":onStarted}};function forget(e){for(let[n,r]of t)r.delete(e),r.size===0&&t.delete(n)}}function actionContext(t){let r={isRemote:!1,spanId:t.spanId,traceFlags:t.parent.traceFlags,traceId:t.parent.traceId};return{context:trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(r)),spanContext:r}}function contextFromActionState(t){return trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext({...t.parent,isRemote:!1}))}function recordError(e,n){n instanceof Error?(e.recordException(n),e.setStatus({code:SpanStatusCode.ERROR,message:n.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentActionInstrumentation};
1
+ import{normalizeChannelAudience}from"#shared/channel-audience.js";import{ROOT_CONTEXT,SpanStatusCode,trace}from"#compiled/@opentelemetry/api/index.js";import{actionIdempotencyKey,attemptIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{contentAttribute}from"#tracing/agent-otel-content.js";import{setAgentUsage}from"#tracing/agent-otel-usage.js";import{isSampledTrace}from"#tracing/sampled-trace.js";import{withChannelAudience}from"#tracing/channel-audience-context.js";function createAgentActionInstrumentation(t){let n=new Map,onStarted=async r=>{let i=await t.resolveTraceContext(r);if(i===void 0||!isSampledTrace(i))return;let s=await t.stateStore.getAction(r.idempotencyKey)??{attemptIndex:r.scope.attemptIndex,callId:r.callId,channelAudience:normalizeChannelAudience(r.scope.channelAudience),inputAttribute:t.recordInputs?contentAttribute(r.input,!1):void 0,kind:r.kind,name:r.name,parent:{spanId:t.idGenerator.deriveSpanId(attemptIdempotencyKey(r.scope)),traceFlags:i.traceFlags,traceId:i.traceId},rootSessionId:r.scope.rootSessionId??r.scope.sessionId,sessionId:r.scope.sessionId,spanId:t.idGenerator.deriveSpanId(`action:${r.idempotencyKey}`),startTimeMs:Date.now(),stepIndex:r.scope.stepIndex,turnId:r.scope.turnId};await t.stateStore.setAction(r.idempotencyKey,s);let c=n.get(r.scope.attemptId)??new Set;c.add(r.idempotencyKey),n.set(r.scope.attemptId,c)},onTerminal=async e=>{let n=await t.stateStore.getAction(e.idempotencyKey);if(n!==void 0)try{let r=startSpan(n);if(r.setAttribute(`agent.action.outcome`,e.outcome),e.type===`action.failed`)e.errorCode!==void 0&&(r.setAttribute(`agent.action.error.code`,e.errorCode),r.setAttribute(`error.type`,e.errorCode)),recordError(r,e.error);else if(e.output.type===`error`)recordError(r,e.output.error);else if(e.usage!==void 0&&setAgentUsage(r,e.usage),t.recordOutputs){let t=contentAttribute(e.output.output,!1);t!==void 0&&r.setAttribute(`gen_ai.tool.call.result`,t)}r.end(e.acceptedAtMs)}finally{await t.stateStore.deleteAction(e.idempotencyKey),forget(e.idempotencyKey)}},startSpan=e=>{let n=t.idGenerator.withSpanId(e.spanId,()=>t.tracer.startSpan(`agent.action`,{attributes:{"agent.action.call_id":e.callId,"agent.action.kind":e.kind,"agent.action.name":e.name,"agent.framework.name":`eve`,"agent.framework.version":t.frameworkVersion,"agent.root.session.id":e.rootSessionId,"agent.session.id":e.sessionId,"agent.step.attempt":e.attemptIndex,"agent.step.index":e.stepIndex,"agent.turn.id":e.turnId},startTime:e.startTimeMs},contextFromActionState(e)));return e.inputAttribute!==void 0&&n.setAttribute(`gen_ai.tool.call.arguments`,e.inputAttribute),n};return{async contextFor(e,n,r){let a=actionIdempotencyKey(e,n,r),o=await t.stateStore.getAction(a);if(o!==void 0)return actionContext(o);let s=await t.stateStore.findAction(e,r);return s===void 0?void 0:actionContext(s)},deleteForSession:e=>t.stateStore.deleteActions(e),deleteForTurn:(e,n)=>t.stateStore.deleteActions(e,n),async failForAttempt(e,r){let i=n.get(e.attemptId);if(i!==void 0){n.delete(e.attemptId);for(let e of i){let n=await t.stateStore.getAction(e);if(n===void 0)continue;let i=startSpan(n);recordError(i,r),i.end(),await t.stateStore.deleteAction(e)}}},events:{"action.completed":onTerminal,"action.failed":onTerminal,"action.started":onStarted}};function forget(e){for(let[t,r]of n)r.delete(e),r.size===0&&n.delete(t)}}function actionContext(e){let n={isRemote:!1,spanId:e.spanId,traceFlags:e.parent.traceFlags,traceId:e.parent.traceId};return{context:withChannelAudience(trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(n)),e.channelAudience),spanContext:n}}function contextFromActionState(e){return withChannelAudience(trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext({...e.parent,isRemote:!1})),e.channelAudience)}function recordError(e,t){t instanceof Error?(e.recordException(t),e.setStatus({code:SpanStatusCode.ERROR,message:t.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentActionInstrumentation};
@@ -1 +1 @@
1
- import{ROOT_CONTEXT,SpanStatusCode,trace}from"#compiled/@opentelemetry/api/index.js";import{contentAttribute}from"#tracing/agent-otel-content.js";function createAgentApprovalInstrumentation(t){return{"input.requested":async(e,n)=>{if(e.kind!==`tool-approval`||readState(n.state.get())!==void 0)return;let i=await t.actionContextFor(e.scope.sessionId,e.scope.turnId,e.action.callId);if(i===void 0)return;let a={actionCallId:e.action.callId,actionName:e.action.name,attemptIndex:e.scope.attemptIndex,parent:{spanId:i.spanContext.spanId,traceFlags:i.spanContext.traceFlags,traceId:i.spanContext.traceId},requestId:e.requestId,rootSessionId:e.scope.rootSessionId??e.scope.sessionId,sessionId:e.scope.sessionId,startTimeMs:Date.now(),stepIndex:e.scope.stepIndex,turnId:e.scope.turnId},o=t.recordInputs?contentAttribute(e.request,!1):void 0;o!==void 0&&(a.requestAttribute=o),n.state.set(a)},"input.resolved":(i,a)=>{let o=readState(a.state.get());if(o===void 0)return;let s=t.idGenerator.withSpanId(t.idGenerator.deriveSpanId(`approval:${i.idempotencyKey}`),()=>t.tracer.startSpan(`agent.approval`,{attributes:{"agent.action.call_id":o.actionCallId,"agent.action.name":o.actionName,"agent.approval.kind":`tool-approval`,"agent.approval.outcome":i.outcome,"agent.approval.request_id":o.requestId,"agent.framework.name":`eve`,"agent.framework.version":t.frameworkVersion,"agent.root.session.id":o.rootSessionId,"agent.session.id":o.sessionId,"agent.step.attempt":o.attemptIndex,"agent.step.index":o.stepIndex,"agent.turn.id":o.turnId},startTime:o.startTimeMs},trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext({...o.parent,isRemote:!1}))));if(o.requestAttribute!==void 0&&s.setAttribute(`agent.approval.request`,o.requestAttribute),t.recordOutputs&&i.response!==void 0){let e=contentAttribute(i.response,!1);e!==void 0&&s.setAttribute(`agent.approval.response`,e)}i.outcome===`failed`&&recordError(s,i.error),s.end()}}}function readState(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=e,n=t.parent;if(typeof n!=`object`||!n||Array.isArray(n))return;let r=n;if(typeof t.actionCallId!=`string`||typeof t.actionName!=`string`||typeof t.attemptIndex!=`number`||typeof r.spanId!=`string`||typeof r.traceFlags!=`number`||typeof r.traceId!=`string`||typeof t.requestId!=`string`||typeof t.rootSessionId!=`string`||typeof t.sessionId!=`string`||typeof t.startTimeMs!=`number`||typeof t.stepIndex!=`number`||typeof t.turnId!=`string`)return;let i=t.requestAttribute;if(!(i!==void 0&&typeof i!=`string`))return{actionCallId:t.actionCallId,actionName:t.actionName,attemptIndex:t.attemptIndex,parent:{isRemote:!1,spanId:r.spanId,traceFlags:r.traceFlags,traceId:r.traceId},requestAttribute:i,requestId:t.requestId,rootSessionId:t.rootSessionId,sessionId:t.sessionId,startTimeMs:t.startTimeMs,stepIndex:t.stepIndex,turnId:t.turnId}}function recordError(e,n){n instanceof Error?(e.recordException(n),e.setStatus({code:SpanStatusCode.ERROR,message:n.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentApprovalInstrumentation};
1
+ import{normalizeChannelAudience}from"#shared/channel-audience.js";import{ROOT_CONTEXT,SpanStatusCode,trace}from"#compiled/@opentelemetry/api/index.js";import{contentAttribute}from"#tracing/agent-otel-content.js";function createAgentApprovalInstrumentation(n){return{"input.requested":async(t,r)=>{if(t.kind!==`tool-approval`||readState(r.state.get())!==void 0)return;let a=await n.actionContextFor(t.scope.sessionId,t.scope.turnId,t.action.callId);if(a===void 0)return;let o={actionCallId:t.action.callId,actionName:t.action.name,attemptIndex:t.scope.attemptIndex,channelAudience:normalizeChannelAudience(t.scope.channelAudience),parent:{spanId:a.spanContext.spanId,traceFlags:a.spanContext.traceFlags,traceId:a.spanContext.traceId},requestId:t.requestId,rootSessionId:t.scope.rootSessionId??t.scope.sessionId,sessionId:t.scope.sessionId,startTimeMs:Date.now(),stepIndex:t.scope.stepIndex,turnId:t.scope.turnId},s=n.recordInputs?contentAttribute(t.request,!1):void 0;s!==void 0&&(o.requestAttribute=s),r.state.set(o)},"input.resolved":(e,a)=>{let o=readState(a.state.get());if(o===void 0)return;let s=n.idGenerator.withSpanId(n.idGenerator.deriveSpanId(`approval:${e.idempotencyKey}`),()=>n.tracer.startSpan(`agent.approval`,{attributes:{"agent.action.call_id":o.actionCallId,"agent.action.name":o.actionName,"agent.approval.kind":`tool-approval`,"agent.approval.outcome":e.outcome,"agent.approval.request_id":o.requestId,"agent.framework.name":`eve`,"agent.framework.version":n.frameworkVersion,"agent.root.session.id":o.rootSessionId,"agent.session.id":o.sessionId,"agent.step.attempt":o.attemptIndex,"agent.step.index":o.stepIndex,"agent.turn.id":o.turnId},startTime:o.startTimeMs},trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext({...o.parent,isRemote:!1}))));if(o.requestAttribute!==void 0&&s.setAttribute(`agent.approval.request`,o.requestAttribute),n.recordOutputs&&e.response!==void 0){let t=contentAttribute(e.response,!1);t!==void 0&&s.setAttribute(`agent.approval.response`,t)}e.outcome===`failed`&&recordError(s,e.error),s.end()}}}function readState(t){if(typeof t!=`object`||!t||Array.isArray(t))return;let n=t,r=n.parent;if(typeof r!=`object`||!r||Array.isArray(r))return;let i=r;if(typeof n.actionCallId!=`string`||typeof n.actionName!=`string`||typeof n.attemptIndex!=`number`||typeof i.spanId!=`string`||typeof i.traceFlags!=`number`||typeof i.traceId!=`string`||typeof n.requestId!=`string`||typeof n.rootSessionId!=`string`||typeof n.sessionId!=`string`||typeof n.startTimeMs!=`number`||typeof n.stepIndex!=`number`||typeof n.turnId!=`string`)return;let a=n.requestAttribute;if(!(a!==void 0&&typeof a!=`string`))return{actionCallId:n.actionCallId,actionName:n.actionName,attemptIndex:n.attemptIndex,channelAudience:normalizeChannelAudience(n.channelAudience),parent:{isRemote:!1,spanId:i.spanId,traceFlags:i.traceFlags,traceId:i.traceId},requestAttribute:a,requestId:n.requestId,rootSessionId:n.rootSessionId,sessionId:n.sessionId,startTimeMs:n.startTimeMs,stepIndex:n.stepIndex,turnId:n.turnId}}function recordError(e,t){t instanceof Error?(e.recordException(t),e.setStatus({code:SpanStatusCode.ERROR,message:t.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentApprovalInstrumentation};
@@ -1 +1 @@
1
- import{ROOT_CONTEXT,SpanKind,SpanStatusCode,trace}from"#compiled/@opentelemetry/api/index.js";import{sessionIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{contentAttribute}from"#tracing/agent-otel-content.js";function createAgentChannelDeliveryInstrumentation(e){let onStarted=async(t,n)=>{let r=await e.ensureSessionContext({agentName:t.agentName,channelKind:t.delivery.channelKind,idempotencyKey:sessionIdempotencyKey(t.sessionId),parentTraceContext:t.parentTraceContext,rootSessionId:t.rootSessionId,sessionId:t.sessionId,type:`session.started`}),o=e.recordInputs?contentAttribute(t.input,!1):void 0,s={parent:{isRemote:r.context.isRemote??!1,spanId:r.context.spanId,traceFlags:r.context.traceFlags,traceId:r.context.traceId},spanId:e.idGenerator.deriveSpanId(`channel-delivery:${t.idempotencyKey}`),startTimeMs:Date.now(),window:r.window};o!==void 0&&(s.inputAttribute=o),t.delivery.requestTraceContext!==void 0&&(s.requestTraceContext={spanId:t.delivery.requestTraceContext.spanId,traceFlags:t.delivery.requestTraceContext.traceFlags,traceId:t.delivery.requestTraceContext.traceId}),n.state.set(s)},onTerminal=async(n,r)=>{let i=readState(r.state.get());if(i===void 0)return;let a=n.turnId===void 0?void 0:await e.stateStore.getTurn(n.sessionId,n.turnId),o=await e.stateStore.getSession(n.sessionId),s=a===void 0?i.parent:{isRemote:a.parentIsRemote??!1,spanId:a.parentSpanId,traceFlags:a.context.traceFlags,traceId:a.context.traceId},c=a===void 0?i.startTimeMs:Math.max(i.startTimeMs,a.startTimeMs),l=i.requestTraceContext,u=e.idGenerator.withSpanId(i.spanId,()=>e.tracer.startSpan(`agent.channel.delivery`,{attributes:{"agent.channel.delivery.id":n.delivery.deliveryId,"agent.channel.delivery.outcome":n.outcome,"agent.channel.kind":n.delivery.channelKind,"agent.channel.name":n.delivery.channelName,"agent.channel.request.id":n.delivery.requestId,"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.name":n.agentName,"agent.root.session.id":n.rootSessionId,"agent.session.id":n.sessionId,"agent.session.window":o?.window??i.window,"agent.turn.id":n.turnId,"agent.turn.sequence":n.sequence},kind:SpanKind.CONSUMER,links:l===void 0?void 0:[{attributes:{"eve.link.type":`channel.request`},context:l}],startTime:c},contextFromSpanContext(s)));if(u.addEvent(`channel.delivery.started`,void 0,c),u.addEvent(n.type),i.inputAttribute!==void 0&&u.setAttribute(`agent.channel.delivery.input`,i.inputAttribute),n.outcome===`failed`){let e=n.errorCode??(n.error instanceof Error?n.error.name:`Error`);u.setAttribute(`error.type`,e),n.errorCode!==void 0&&u.setAttribute(`agent.channel.delivery.error.code`,n.errorCode),recordError(u,n.error)}u.end()};return{"channel.delivery.cancelled":onTerminal,"channel.delivery.completed":onTerminal,"channel.delivery.failed":onTerminal,"channel.delivery.started":onStarted}}function readState(e){if(!isRecord(e)||!isSpanContext(e.parent)||typeof e.spanId!=`string`||typeof e.startTimeMs!=`number`||typeof e.window!=`number`)return;let t=isSpanContext(e.requestTraceContext)?e.requestTraceContext:void 0;return{inputAttribute:typeof e.inputAttribute==`string`?e.inputAttribute:void 0,parent:e.parent,requestTraceContext:t,spanId:e.spanId,startTimeMs:e.startTimeMs,window:e.window}}function isSpanContext(e){return isRecord(e)&&typeof e.spanId==`string`&&typeof e.traceFlags==`number`&&typeof e.traceId==`string`}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function contextFromSpanContext(t){return trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(t))}function recordError(e,t){t instanceof Error?(e.recordException(t),e.setStatus({code:SpanStatusCode.ERROR,message:t.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentChannelDeliveryInstrumentation};
1
+ import{normalizeChannelAudience}from"#shared/channel-audience.js";import{ROOT_CONTEXT,SpanKind,SpanStatusCode,trace}from"#compiled/@opentelemetry/api/index.js";import{sessionIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{contentAttribute}from"#tracing/agent-otel-content.js";import{isSampledTrace}from"#tracing/sampled-trace.js";function createAgentChannelDeliveryInstrumentation(t){let onStarted=async(n,r)=>{let i=await t.ensureSessionContext({agentName:n.agentName,channelAudience:n.delivery.channelAudience,channelKind:n.delivery.channelKind,idempotencyKey:sessionIdempotencyKey(n.sessionId),parentTraceContext:n.parentTraceContext,rootSessionId:n.rootSessionId,sessionId:n.sessionId,type:`session.started`});if(!isSampledTrace(i.context))return;let c=t.recordInputs?contentAttribute(n.input,!1):void 0,l={channelAudience:normalizeChannelAudience(n.delivery.channelAudience),parent:{isRemote:i.context.isRemote??!1,spanId:i.context.spanId,traceFlags:i.context.traceFlags,traceId:i.context.traceId},spanId:t.idGenerator.deriveSpanId(`channel-delivery:${n.idempotencyKey}`),startTimeMs:Date.now(),window:i.window};c!==void 0&&(l.inputAttribute=c),n.delivery.requestTraceContext!==void 0&&(l.requestTraceContext={spanId:n.delivery.requestTraceContext.spanId,traceFlags:n.delivery.requestTraceContext.traceFlags,traceId:n.delivery.requestTraceContext.traceId}),r.state.set(l)},onTerminal=async(e,r)=>{let i=readState(r.state.get());if(i===void 0)return;let a=e.turnId===void 0?void 0:await t.stateStore.getTurn(e.sessionId,e.turnId),o=await t.stateStore.getSession(e.sessionId),s=a===void 0?i.parent:{isRemote:a.parentIsRemote??!1,spanId:a.parentSpanId,traceFlags:a.context.traceFlags,traceId:a.context.traceId},c=a===void 0?i.startTimeMs:Math.max(i.startTimeMs,a.startTimeMs),l=i.requestTraceContext,u=t.idGenerator.withSpanId(i.spanId,()=>t.tracer.startSpan(`agent.channel.delivery`,{attributes:{"agent.channel.delivery.id":e.delivery.deliveryId,"agent.channel.delivery.outcome":e.outcome,"agent.channel.kind":e.delivery.channelKind,"agent.channel.name":e.delivery.channelName,"agent.channel.request.id":e.delivery.requestId,"agent.framework.name":`eve`,"agent.framework.version":t.frameworkVersion,"agent.name":e.agentName,"agent.root.session.id":e.rootSessionId,"agent.session.id":e.sessionId,"agent.session.window":o?.window??i.window,"agent.turn.id":e.turnId,"agent.turn.sequence":e.sequence},kind:SpanKind.CONSUMER,links:l===void 0?void 0:[{attributes:{"eve.link.type":`channel.request`},context:l}],startTime:c},contextFromSpanContext(s)));if(u.addEvent(`channel.delivery.started`,void 0,c),u.addEvent(e.type),i.inputAttribute!==void 0&&u.setAttribute(`agent.channel.delivery.input`,i.inputAttribute),e.outcome===`failed`){let t=e.errorCode??(e.error instanceof Error?e.error.name:`Error`);u.setAttribute(`error.type`,t),e.errorCode!==void 0&&u.setAttribute(`agent.channel.delivery.error.code`,e.errorCode),recordError(u,e.error)}u.end()};return{"channel.delivery.cancelled":onTerminal,"channel.delivery.completed":onTerminal,"channel.delivery.failed":onTerminal,"channel.delivery.started":onStarted}}function readState(t){if(!isRecord(t)||!isSpanContext(t.parent)||typeof t.spanId!=`string`||typeof t.startTimeMs!=`number`||typeof t.window!=`number`)return;let n=isSpanContext(t.requestTraceContext)?t.requestTraceContext:void 0;return{channelAudience:normalizeChannelAudience(t.channelAudience),inputAttribute:typeof t.inputAttribute==`string`?t.inputAttribute:void 0,parent:t.parent,requestTraceContext:n,spanId:t.spanId,startTimeMs:t.startTimeMs,window:t.window}}function isSpanContext(e){return isRecord(e)&&typeof e.spanId==`string`&&typeof e.traceFlags==`number`&&typeof e.traceId==`string`}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function contextFromSpanContext(e){return trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(e))}function recordError(e,t){t instanceof Error?(e.recordException(t),e.setStatus({code:SpanStatusCode.ERROR,message:t.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentChannelDeliveryInstrumentation};
@@ -1,6 +1,7 @@
1
1
  import { type Tracer } from "#compiled/@opentelemetry/api/index.js";
2
2
  import type { AgentTraceStateStore } from "#tracing/agent-trace-state.js";
3
3
  import type { AgentSpanIdGenerator } from "#tracing/agent-span-id-generator.js";
4
+ import type { TraceCapturePolicy } from "#tracing/otel-declaration.js";
4
5
  import type { InstrumentationContextRunner, InstrumentationProviderDefinition, InstrumentationSessionStartedEvent, InstrumentationTraceContext, InstrumentationTurnStartedEvent } from "#harness/instrumentation/lifecycle.js";
5
6
  export interface AgentOtelInstrumentationInput {
6
7
  /**
@@ -15,6 +16,7 @@ export interface AgentOtelInstrumentationInput {
15
16
  readonly idGenerator: AgentSpanIdGenerator;
16
17
  readonly stateStore: AgentTraceStateStore;
17
18
  readonly tracer: Tracer;
19
+ readonly tracePolicy?: TraceCapturePolicy;
18
20
  }
19
21
  /** OTel event definition and its trusted framework context runner. */
20
22
  export interface AgentOtelInstrumentation {
@@ -1,2 +1,2 @@
1
- import{ROOT_CONTEXT,SpanStatusCode,context,trace}from"#compiled/@opentelemetry/api/index.js";import{attemptIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{contentAttribute,genAiInputMessagesAttribute,genAiOutputMessagesAttribute,genAiSystemInstructionsAttribute,messagesContentAttribute,systemPromptAttribute,textContentAttribute,toolResultsContentAttribute}from"#tracing/agent-otel-content.js";import{setAgentUsage}from"#tracing/agent-otel-usage.js";import{createAgentActionInstrumentation}from"#tracing/agent-action-instrumentation.js";import{createAgentApprovalInstrumentation}from"#tracing/agent-approval-instrumentation.js";import{createAgentChannelDeliveryInstrumentation}from"#tracing/agent-channel-delivery-instrumentation.js";import{createAgentToolInstrumentation}from"#tracing/agent-tool-instrumentation.js";import{createAgentOtelSessionContext}from"#tracing/agent-otel-session-context.js";function createAgentOtelInstrumentation(e){let t=e.recordInputs??!1,f=e.recordOutputs??!1,p=new WeakMap,m=new Map,h=new WeakMap,g=new WeakMap,_=createAgentActionInstrumentation({frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,recordInputs:t,recordOutputs:f,resolveTraceContext:async t=>(await e.stateStore.getTurn(t.scope.sessionId,t.scope.turnId))?.context,stateStore:e.stateStore,tracer:e.tracer}),v=createAgentApprovalInstrumentation({actionContextFor:_.contextFor,frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,recordInputs:t,recordOutputs:f,tracer:e.tracer}),y=createAgentToolInstrumentation({actionContextFor:_.contextFor,idGenerator:e.idGenerator,recordInputs:t,recordOutputs:f,resolveFallback:e=>{let t=m.get(e.scope.attemptId)??e.scope,n=h.get(t)?.step;return n===void 0?void 0:{context:n.context,spanContext:n.span.spanContext()}},tracer:e.tracer}),{ensureSessionContext:b,prepareSessionTrace:x,prepareTurnTrace:S}=createAgentOtelSessionContext(e),onSessionStarted=async e=>{await x(e)},onTurnStarted=async e=>{await S(e)},onStepStarted=async t=>{let a=await e.stateStore.getTurn(t.scope.sessionId,t.scope.turnId);if(a===void 0)return;let o=contextFromSpanContext(a.context),s=trace.getSpan(context.active())?.spanContext(),c=e.idGenerator.withSpanId(e.idGenerator.deriveSpanId(attemptIdempotencyKey(t.scope)),()=>e.tracer.startSpan(`agent.step`,{attributes:{"agent.session.id":t.scope.sessionId,"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.root.session.id":t.scope.rootSessionId??t.scope.sessionId,"agent.step.attempt":t.scope.attemptIndex,"agent.step.index":t.scope.stepIndex,"agent.turn.id":t.scope.turnId,"agent.name":t.scope.functionId,...runtimeContextAttributes(t.runtimeContext)},links:s===void 0||s.traceId===a.context.traceId?void 0:[{attributes:{"eve.link.type":`workflow.delivery`},context:s}]},o));c.addEvent(`step.started`);let l=trace.setSpan(o,c),u=t.operation.operationId,d=e.tracer.startSpan(u,{attributes:{"ai.operation.name":u,"ai.provider.name":t.operation.provider,"ai.request.model":t.operation.modelId,...runtimeContextAttributes(t.runtimeContext)}},l);h.set(t.scope,{operation:{context:trace.setSpan(l,d),name:u,span:d},step:{context:l,span:c}}),m.set(t.scope.attemptId,t.scope)},onStepTerminal=async e=>{let t=m.get(e.scope.attemptId)??e.scope;p.delete(t),drainOpenSpans({...e,scope:t}),y.drain(e.scope.attemptId,e.type===`step.attempt.failed`?{error:e.error}:void 0),e.type===`step.attempt.failed`&&await _.failForAttempt(t,e.error),m.delete(e.scope.attemptId);let n=h.get(t);n!==void 0&&(n.step.span.addEvent(e.type===`step.attempt.completed`?`step.completed`:`step.failed`),e.type===`step.attempt.failed`&&(recordError(n.operation.span,e.error),recordError(n.step.span,e.error)),n.operation.span.end(),n.step.span.end(),h.delete(t))},onTurnTerminal=async t=>{(t.type===`turn.cancelled`||t.type===`turn.failed`)&&await _.deleteForTurn(t.sessionId,t.turnId);let n=await e.stateStore.getTurn(t.sessionId,t.turnId);n!==void 0&&await e.stateStore.setTurn(t.sessionId,t.turnId,{...n,terminal:t.type===`turn.failed`?{error:t.error,type:t.type}:{type:t.type}})},onSessionTransition=async t=>{if(t.turnId!==void 0){let n=await e.stateStore.getTurn(t.sessionId,t.turnId);if(n!==void 0){let r=await e.stateStore.getSession(t.sessionId),i=e.idGenerator.withSpanId(n.context.spanId,()=>e.tracer.startSpan(`agent.turn`,{attributes:{"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.name":r?.agentName,...parentLineageAttributes(n.lineage),"agent.root.session.id":n.rootSessionId,"agent.session.id":t.sessionId,"agent.session.window":r?.window,"agent.turn.id":t.turnId,"agent.turn.sequence":n.sequence},startTime:n.startTimeMs},contextFromSpanContext({isRemote:n.parentIsRemote??!1,spanId:n.parentSpanId,traceFlags:n.context.traceFlags,traceId:n.context.traceId})));i.addEvent(`turn.started`,void 0,n.startTimeMs),n.terminal!==void 0&&(i.addEvent(n.terminal.type),n.terminal.type===`turn.failed`&&recordError(i,n.terminal.error)),i.end(),await e.stateStore.deleteTurn(t.sessionId,t.turnId)}}(t.type===`session.completed`||t.type===`session.failed`)&&(await _.deleteForSession(t.sessionId),await e.stateStore.deleteSession(t.sessionId))},onModelCallStarted=n=>{let i=h.get(n.scope);if(i===void 0)return;i.step.span.setAttribute(`agent.model.id`,n.model.modelId),i.step.span.setAttribute(`agent.model.provider`,n.model.provider);let a=e.tracer.startSpan(modelSpanName(n.model.modelId),{attributes:{"gen_ai.agent.name":n.scope.functionId,"gen_ai.operation.name":`chat`,"gen_ai.provider.name":n.model.provider,"gen_ai.request.model":n.model.modelId,...runtimeContextAttributes(n.runtimeContext)}},i.operation.context);if(t&&n.input!==void 0){let e=messagesContentAttribute(n.input.messages);e!==void 0&&a.setAttribute(`ai.prompt.messages`,e);let t=genAiInputMessagesAttribute(n.input.messages);t!==void 0&&a.setAttribute(`gen_ai.input.messages`,t);let r=systemPromptAttribute(n.input.instructions);r!==void 0&&a.setAttribute(`ai.prompt.system`,r);let i=genAiSystemInstructionsAttribute(n.input.instructions);i!==void 0&&a.setAttribute(`gen_ai.system_instructions`,i)}let s={context:trace.setSpan(i.operation.context,a),span:a};getExecutionContexts(n.scope).set(n.idempotencyKey,s.context),getSpanStates(g,n.scope).set(n.idempotencyKey,s)},onModelCallTerminal=e=>{p.get(e.scope)?.delete(e.idempotencyKey);let t=takeSpanState(g,e.scope,e.idempotencyKey);if(t!==void 0){if(e.type===`model.call.failed`)recordError(t.span,e.error);else{setAgentUsage(t.span,e.usage),t.span.setAttribute(`gen_ai.response.finish_reasons`,[e.finishReason]);let n=h.get(e.scope);if(n!==void 0&&setAgentUsage(n.step.span,e.usage),f){t.span.setAttribute(`ai.response.finish_reason`,e.finishReason);let n=e.content??[],r=genAiOutputMessagesAttribute(n,e.finishReason);r!==void 0&&t.span.setAttribute(`gen_ai.output.messages`,r);let i=textContentAttribute(n.filter(e=>e.type===`reasoning`).map(e=>e.text).filter(e=>e.trim().length>0).join(`
2
- `));i!==void 0&&t.span.setAttribute(`ai.response.reasoning`,i);let o=textContentAttribute(n.filter(e=>e.type===`text`).map(e=>e.text).join(``));o!==void 0&&t.span.setAttribute(`ai.response.text`,o);let c=n.filter(e=>e.type===`tool-call`).map(e=>({callId:e.callId,input:e.input,toolName:e.toolName}));if(c.length>0){let e=contentAttribute(c,!1);e!==void 0&&t.span.setAttribute(`ai.response.tool_calls`,e)}let l=n.filter(e=>e.type===`tool-result`||e.type===`tool-error`).map(e=>e.type===`tool-result`?{callId:e.callId,input:e.input,output:e.output,toolName:e.toolName}:{callId:e.callId,error:errorText(e.error),input:e.input,toolName:e.toolName});if(l.length>0){let e=toolResultsContentAttribute(l);e!==void 0&&t.span.setAttribute(`ai.response.tool_results`,e)}}}t.span.end()}},C=createAgentChannelDeliveryInstrumentation({ensureSessionContext:b,frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,recordInputs:t,stateStore:e.stateStore,tracer:e.tracer}),onStepMetadata=e=>{let t=h.get(e.scope);if(t===void 0)return;let n=readGatewayCost(e.providerMetadata);if(n!==void 0)for(let[e,r]of Object.entries(n))t.step.span.setAttribute(e,r)};return{hook:{capture:t||f?`content`:`metadata`,events:{...C,"action.completed":_.events[`action.completed`],"action.failed":_.events[`action.failed`],async"action.started"(e,t){await _.events[`action.started`](e,t),await y.actionStarted(e)},...v,"step.attempt.completed":onStepTerminal,"step.attempt.failed":onStepTerminal,"step.attempt.metadata":onStepMetadata,"step.attempt.started":onStepStarted,"model.call.completed":onModelCallTerminal,"model.call.failed":onModelCallTerminal,"model.call.started":onModelCallStarted,"session.completed":onSessionTransition,"session.failed":onSessionTransition,"session.started":onSessionStarted,"session.waiting":onSessionTransition,...y.events,"turn.cancelled":onTurnTerminal,"turn.completed":onTurnTerminal,"turn.failed":onTurnTerminal,"turn.started":onTurnStarted},name:`eve.otel`},prepareSessionTrace:x,prepareTurnTrace:S,runInContext(e,t){let r=m.get(e.scope.attemptId)??e.scope,i=p.get(r),a=e.type===`model.call`?i?.get(e.idempotencyKey):y.contextFor(e.scope.attemptId,e.idempotencyKey);return a===void 0?t():context.with(a,t)}};function getExecutionContexts(e){let t=p.get(e);return t===void 0&&(t=new Map,p.set(e,t)),t}function drainOpenSpans(e){for(let t of g.get(e.scope)?.values()??[])e.type===`step.attempt.failed`&&recordError(t.span,e.error),t.span.end();g.delete(e.scope)}}function getSpanStates(e,t){let n=e.get(t);return n===void 0&&(n=new Map,e.set(t,n)),n}function takeSpanState(e,t,n){let r=e.get(t),i=r?.get(n);if(r!==void 0)return r.delete(n),r.size===0&&e.delete(t),i}function parentLineageAttributes(e){if(e===void 0)return{};let t={"agent.parent.call_id":e.callId,"agent.parent.session.id":e.sessionId,"agent.parent.turn.id":e.turnId};return e.subagentName!==void 0&&(t[`agent.subagent.name`]=e.subagentName),t}function contextFromSpanContext(t){return trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(t))}function readGatewayCost(e){let t=e.gateway;if(!isRecord(t))return;let n={},r=readUsd(t.cost);r!==void 0&&(n[`gen_ai.usage.cost`]=r);let i=readUsd(t.gatewayCost);i!==void 0&&(n[`gen_ai.usage.gateway_cost`]=i);let a=readUsd(t.inputInferenceCost);a!==void 0&&(n[`gen_ai.usage.input_cost`]=a);let o=readUsd(t.outputInferenceCost);return o!==void 0&&(n[`gen_ai.usage.output_cost`]=o),typeof t.generationId==`string`&&t.generationId.length>0&&(n[`gen_ai.generation.id`]=t.generationId),Object.keys(n).length===0?void 0:n}function readUsd(e){if(typeof e!=`string`)return;let t=Number(e);return Number.isFinite(t)?t:void 0}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function modelSpanName(e){return`chat ${e}`}function runtimeContextAttributes(e){let t={};if(e===void 0)return t;for(let[n,r]of Object.entries(e))flattenContextAttribute(t,`ai.settings.context.${n}`,r);return t}function flattenContextAttribute(e,t,n){if(n!=null){if(typeof n==`string`||typeof n==`number`||typeof n==`boolean`){e[t]=n;return}if(Array.isArray(n)){let r=n.filter(e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`);if(r.length!==n.length||new Set(r.map(e=>typeof e)).size!==1)return;e[t]=r;return}if(typeof n==`object`)for(let[r,i]of Object.entries(n))flattenContextAttribute(e,`${t}.${r}`,i)}}function errorText(e){return e instanceof Error?e.message:e}function recordError(e,n){n instanceof Error?(e.recordException(n),e.setStatus({code:SpanStatusCode.ERROR,message:n.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentOtelInstrumentation};
1
+ import{ROOT_CONTEXT,SpanStatusCode,context,trace}from"#compiled/@opentelemetry/api/index.js";import{attemptIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{contentAttribute,genAiInputMessagesAttribute,genAiOutputMessagesAttribute,genAiSystemInstructionsAttribute,messagesContentAttribute,systemPromptAttribute,textContentAttribute,toolResultsContentAttribute}from"#tracing/agent-otel-content.js";import{setAgentUsage}from"#tracing/agent-otel-usage.js";import{isSampledTrace}from"#tracing/sampled-trace.js";import{withChannelAudience}from"#tracing/channel-audience-context.js";import{createAgentActionInstrumentation}from"#tracing/agent-action-instrumentation.js";import{createAgentApprovalInstrumentation}from"#tracing/agent-approval-instrumentation.js";import{createAgentChannelDeliveryInstrumentation}from"#tracing/agent-channel-delivery-instrumentation.js";import{createAgentToolInstrumentation}from"#tracing/agent-tool-instrumentation.js";import{createAgentOtelSessionContext}from"#tracing/agent-otel-session-context.js";import{suppressTracing}from"#tracing/suppress-tracing.js";function createAgentOtelInstrumentation(e){let t=e.recordInputs??!1,f=e.recordOutputs??!1,p=new WeakMap,m=new Map,h=new WeakMap,g=new WeakMap,_=createAgentActionInstrumentation({frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,recordInputs:t,recordOutputs:f,resolveTraceContext:async t=>(await e.stateStore.getTurn(t.scope.sessionId,t.scope.turnId))?.context,stateStore:e.stateStore,tracer:e.tracer}),v=createAgentApprovalInstrumentation({actionContextFor:_.contextFor,frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,recordInputs:t,recordOutputs:f,tracer:e.tracer}),y=createAgentToolInstrumentation({actionContextFor:_.contextFor,idGenerator:e.idGenerator,recordInputs:t,recordOutputs:f,resolveFallback:e=>{let t=m.get(e.scope.attemptId)??e.scope,n=h.get(t)?.step;return n===void 0?void 0:{context:n.context,spanContext:n.span.spanContext()}},tracer:e.tracer}),{ensureSessionContext:b,prepareSessionTrace:x,prepareTurnTrace:S}=createAgentOtelSessionContext(e),onSessionStarted=async e=>{await x(e)},onTurnStarted=async e=>{await S(e)},onStepStarted=async t=>{let a=await e.stateStore.getTurn(t.scope.sessionId,t.scope.turnId);if(a===void 0||!isSampledTrace(a.context))return;let o=withChannelAudience(contextFromSpanContext(a.context),t.scope.channelAudience),s=trace.getSpan(context.active())?.spanContext(),c=e.idGenerator.withSpanId(e.idGenerator.deriveSpanId(attemptIdempotencyKey(t.scope)),()=>e.tracer.startSpan(`agent.step`,{attributes:{"agent.session.id":t.scope.sessionId,"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.root.session.id":t.scope.rootSessionId??t.scope.sessionId,"agent.step.attempt":t.scope.attemptIndex,"agent.step.index":t.scope.stepIndex,"agent.turn.id":t.scope.turnId,"agent.name":t.scope.functionId,...runtimeContextAttributes(t.runtimeContext)},links:s===void 0||s.traceId===a.context.traceId?void 0:[{attributes:{"eve.link.type":`workflow.delivery`},context:s}]},o));c.addEvent(`step.started`);let l=trace.setSpan(o,c),u=t.operation.operationId,d=e.tracer.startSpan(u,{attributes:{"ai.operation.name":u,"ai.provider.name":t.operation.provider,"ai.request.model":t.operation.modelId,...runtimeContextAttributes(t.runtimeContext)}},l);h.set(t.scope,{operation:{context:trace.setSpan(l,d),name:u,span:d},step:{context:l,span:c}}),m.set(t.scope.attemptId,t.scope)},onStepTerminal=async e=>{let t=m.get(e.scope.attemptId)??e.scope;p.delete(t),drainOpenSpans({...e,scope:t}),y.drain(e.scope.attemptId,e.type===`step.attempt.failed`?{error:e.error}:void 0),e.type===`step.attempt.failed`&&await _.failForAttempt(t,e.error),m.delete(e.scope.attemptId);let n=h.get(t);n!==void 0&&(n.step.span.addEvent(e.type===`step.attempt.completed`?`step.completed`:`step.failed`),e.type===`step.attempt.failed`&&(recordError(n.operation.span,e.error),recordError(n.step.span,e.error)),n.operation.span.end(),n.step.span.end(),h.delete(t))},onTurnTerminal=async t=>{(t.type===`turn.cancelled`||t.type===`turn.failed`)&&await _.deleteForTurn(t.sessionId,t.turnId);let n=await e.stateStore.getTurn(t.sessionId,t.turnId);n!==void 0&&await e.stateStore.setTurn(t.sessionId,t.turnId,{...n,terminal:t.type===`turn.failed`?{error:t.error,type:t.type}:{type:t.type}})},onSessionTransition=async t=>{if(t.turnId!==void 0){let n=await e.stateStore.getTurn(t.sessionId,t.turnId);if(n!==void 0){let r=await e.stateStore.getSession(t.sessionId);if(isSampledTrace(n.context)){let i=e.idGenerator.withSpanId(n.context.spanId,()=>e.tracer.startSpan(`agent.turn`,{attributes:{"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.name":r?.agentName,...parentLineageAttributes(n.lineage),"agent.root.session.id":n.rootSessionId,"agent.session.id":t.sessionId,"agent.session.window":r?.window,"agent.turn.id":t.turnId,"agent.turn.sequence":n.sequence},startTime:n.startTimeMs},contextFromSpanContext({isRemote:n.parentIsRemote??!1,spanId:n.parentSpanId,traceFlags:n.context.traceFlags,traceId:n.context.traceId})));i.addEvent(`turn.started`,void 0,n.startTimeMs),n.terminal!==void 0&&(i.addEvent(n.terminal.type),n.terminal.type===`turn.failed`&&recordError(i,n.terminal.error)),i.end()}await e.stateStore.deleteTurn(t.sessionId,t.turnId)}}(t.type===`session.completed`||t.type===`session.failed`)&&(await _.deleteForSession(t.sessionId),await e.stateStore.deleteSession(t.sessionId))},onModelCallStarted=n=>{let i=h.get(n.scope);if(i===void 0)return;i.step.span.setAttribute(`agent.model.id`,n.model.modelId),i.step.span.setAttribute(`agent.model.provider`,n.model.provider);let a=e.tracer.startSpan(modelSpanName(n.model.modelId),{attributes:{"gen_ai.agent.name":n.scope.functionId,"gen_ai.operation.name":`chat`,"gen_ai.provider.name":n.model.provider,"gen_ai.request.model":n.model.modelId,...runtimeContextAttributes(n.runtimeContext)}},i.operation.context);if(t&&n.input!==void 0){let e=messagesContentAttribute(n.input.messages);e!==void 0&&a.setAttribute(`ai.prompt.messages`,e);let t=genAiInputMessagesAttribute(n.input.messages);t!==void 0&&a.setAttribute(`gen_ai.input.messages`,t);let r=systemPromptAttribute(n.input.instructions);r!==void 0&&a.setAttribute(`ai.prompt.system`,r);let i=genAiSystemInstructionsAttribute(n.input.instructions);i!==void 0&&a.setAttribute(`gen_ai.system_instructions`,i)}let s={context:trace.setSpan(i.operation.context,a),span:a};getExecutionContexts(n.scope).set(n.idempotencyKey,s.context),getSpanStates(g,n.scope).set(n.idempotencyKey,s)},onModelCallTerminal=e=>{p.get(e.scope)?.delete(e.idempotencyKey);let t=takeSpanState(g,e.scope,e.idempotencyKey);if(t!==void 0){if(e.type===`model.call.failed`)recordError(t.span,e.error);else{setAgentUsage(t.span,e.usage),t.span.setAttribute(`gen_ai.response.finish_reasons`,[e.finishReason]);let n=h.get(e.scope);if(n!==void 0&&setAgentUsage(n.step.span,e.usage),f){t.span.setAttribute(`ai.response.finish_reason`,e.finishReason);let n=e.content??[],r=genAiOutputMessagesAttribute(n,e.finishReason);r!==void 0&&t.span.setAttribute(`gen_ai.output.messages`,r);let i=textContentAttribute(n.filter(e=>e.type===`reasoning`).map(e=>e.text).filter(e=>e.trim().length>0).join(`
2
+ `));i!==void 0&&t.span.setAttribute(`ai.response.reasoning`,i);let o=textContentAttribute(n.filter(e=>e.type===`text`).map(e=>e.text).join(``));o!==void 0&&t.span.setAttribute(`ai.response.text`,o);let c=n.filter(e=>e.type===`tool-call`).map(e=>({callId:e.callId,input:e.input,toolName:e.toolName}));if(c.length>0){let e=contentAttribute(c,!1);e!==void 0&&t.span.setAttribute(`ai.response.tool_calls`,e)}let l=n.filter(e=>e.type===`tool-result`||e.type===`tool-error`).map(e=>e.type===`tool-result`?{callId:e.callId,input:e.input,output:e.output,toolName:e.toolName}:{callId:e.callId,error:errorText(e.error),input:e.input,toolName:e.toolName});if(l.length>0){let e=toolResultsContentAttribute(l);e!==void 0&&t.span.setAttribute(`ai.response.tool_results`,e)}}}t.span.end()}},C=createAgentChannelDeliveryInstrumentation({ensureSessionContext:b,frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,recordInputs:t,stateStore:e.stateStore,tracer:e.tracer}),onStepMetadata=e=>{let t=h.get(e.scope);if(t===void 0)return;let n=readGatewayCost(e.providerMetadata);if(n!==void 0)for(let[e,r]of Object.entries(n))t.step.span.setAttribute(e,r)};return{hook:{capture:t||f?`content`:`metadata`,events:{...C,"action.completed":_.events[`action.completed`],"action.failed":_.events[`action.failed`],async"action.started"(e,t){await _.events[`action.started`](e,t),await y.actionStarted(e)},...v,"step.attempt.completed":onStepTerminal,"step.attempt.failed":onStepTerminal,"step.attempt.metadata":onStepMetadata,"step.attempt.started":onStepStarted,"model.call.completed":onModelCallTerminal,"model.call.failed":onModelCallTerminal,"model.call.started":onModelCallStarted,"session.completed":onSessionTransition,"session.failed":onSessionTransition,"session.started":onSessionStarted,"session.waiting":onSessionTransition,...y.events,"turn.cancelled":onTurnTerminal,"turn.completed":onTurnTerminal,"turn.failed":onTurnTerminal,"turn.started":onTurnStarted},name:`eve.otel`},prepareSessionTrace:x,prepareTurnTrace:S,async runInContext(t,r){let i=m.get(t.scope.attemptId)??t.scope,a=p.get(i),o=t.type===`model.call`?a?.get(t.idempotencyKey):y.contextFor(t.scope.attemptId,t.idempotencyKey);if(o===void 0){let n=await e.stateStore.getTurn(t.scope.sessionId,t.scope.turnId);n!==void 0&&(o=withChannelAudience(contextFromSpanContext(n.context),t.scope.channelAudience),isSampledTrace(n.context)||(o=suppressTracing(o)))}return o===void 0?r():context.with(o,r)}};function getExecutionContexts(e){let t=p.get(e);return t===void 0&&(t=new Map,p.set(e,t)),t}function drainOpenSpans(e){for(let t of g.get(e.scope)?.values()??[])e.type===`step.attempt.failed`&&recordError(t.span,e.error),t.span.end();g.delete(e.scope)}}function getSpanStates(e,t){let n=e.get(t);return n===void 0&&(n=new Map,e.set(t,n)),n}function takeSpanState(e,t,n){let r=e.get(t),i=r?.get(n);if(r!==void 0)return r.delete(n),r.size===0&&e.delete(t),i}function parentLineageAttributes(e){if(e===void 0)return{};let t={"agent.parent.call_id":e.callId,"agent.parent.session.id":e.sessionId,"agent.parent.turn.id":e.turnId};return e.subagentName!==void 0&&(t[`agent.subagent.name`]=e.subagentName),t}function contextFromSpanContext(t){return trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(t))}function readGatewayCost(e){let t=e.gateway;if(!isRecord(t))return;let n={},r=readUsd(t.cost);r!==void 0&&(n[`gen_ai.usage.cost`]=r);let i=readUsd(t.gatewayCost);i!==void 0&&(n[`gen_ai.usage.gateway_cost`]=i);let a=readUsd(t.inputInferenceCost);a!==void 0&&(n[`gen_ai.usage.input_cost`]=a);let o=readUsd(t.outputInferenceCost);return o!==void 0&&(n[`gen_ai.usage.output_cost`]=o),typeof t.generationId==`string`&&t.generationId.length>0&&(n[`gen_ai.generation.id`]=t.generationId),Object.keys(n).length===0?void 0:n}function readUsd(e){if(typeof e!=`string`)return;let t=Number(e);return Number.isFinite(t)?t:void 0}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function modelSpanName(e){return`chat ${e}`}function runtimeContextAttributes(e){let t={};if(e===void 0)return t;for(let[n,r]of Object.entries(e))flattenContextAttribute(t,`ai.settings.context.${n}`,r);return t}function flattenContextAttribute(e,t,n){if(n!=null){if(typeof n==`string`||typeof n==`number`||typeof n==`boolean`){e[t]=n;return}if(Array.isArray(n)){let r=n.filter(e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`);if(r.length!==n.length||new Set(r.map(e=>typeof e)).size!==1)return;e[t]=r;return}if(typeof n==`object`)for(let[r,i]of Object.entries(n))flattenContextAttribute(e,`${t}.${r}`,i)}}function errorText(e){return e instanceof Error?e.message:e}function recordError(e,n){n instanceof Error?(e.recordException(n),e.setStatus({code:SpanStatusCode.ERROR,message:n.message})):e.setStatus({code:SpanStatusCode.ERROR})}export{createAgentOtelInstrumentation};
@@ -1,12 +1,14 @@
1
1
  import type { Tracer } from "#compiled/@opentelemetry/api/index.js";
2
2
  import { type InstrumentationSessionStartedEvent, type InstrumentationTraceContext, type InstrumentationTurnStartedEvent } from "#harness/instrumentation/lifecycle.js";
3
3
  import type { AgentSpanIdGenerator } from "#tracing/agent-span-id-generator.js";
4
+ import type { TraceCapturePolicy } from "#tracing/otel-declaration.js";
4
5
  import { type AgentSessionTraceState, type AgentTraceStateStore } from "#tracing/agent-trace-state.js";
5
6
  interface AgentOtelSessionContextInput {
6
7
  readonly frameworkVersion: string;
7
8
  readonly idGenerator: AgentSpanIdGenerator;
8
9
  readonly stateStore: AgentTraceStateStore;
9
10
  readonly tracer: Tracer;
11
+ readonly tracePolicy?: TraceCapturePolicy;
10
12
  }
11
13
  interface AgentOtelSessionContext {
12
14
  readonly ensureSessionContext: (event: InstrumentationSessionStartedEvent) => Promise<AgentSessionTraceState>;
@@ -1 +1 @@
1
- import{sessionIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{SESSION_WINDOW_TURN_LIMIT}from"#tracing/agent-trace-state.js";function createAgentOtelSessionContext(n){let openSessionWindow=e=>{let t=n.tracer.startSpan(`agent.session`,{attributes:{"agent.framework.name":`eve`,"agent.framework.version":n.frameworkVersion,"agent.name":e.agentName,"agent.root.session.id":e.rootSessionId,"agent.session.id":e.sessionId,"agent.session.window":e.index,"agent.trace.schema.version":1,...e.previousTraceId===void 0?{}:{"agent.session.window.previous.trace.id":e.previousTraceId}},root:!0});return t.addEvent(e.index===0?`session.started`:`session.window.opened`),t.end(),t.spanContext()},ensureSessionContext=async e=>{let t=await n.stateStore.getSession(e.sessionId);return t===void 0&&(t={agentName:e.agentName,channelKind:e.channelKind,context:e.parentTraceContext===void 0?openSessionWindow({agentName:e.agentName,index:0,rootSessionId:e.rootSessionId,sessionId:e.sessionId}):adoptedSpanContext(e.parentTraceContext),rootSessionId:e.rootSessionId,turnsInWindow:0,window:0},await n.stateStore.setSession(e.sessionId,t)),t},advanceSessionWindow=(e,n)=>{if(n.turnsInWindow<SESSION_WINDOW_TURN_LIMIT)return n;let r=n.window+1;return{...n,context:openSessionWindow({agentName:n.agentName,index:r,previousTraceId:n.context.traceId,rootSessionId:n.rootSessionId,sessionId:e}),turnsInWindow:0,window:r}};return{ensureSessionContext,prepareSessionTrace:async e=>portableSpanContext((await ensureSessionContext(e)).context),prepareTurnTrace:async t=>{let r=await n.stateStore.getTurn(t.sessionId,t.turnId);if(r!==void 0)return{spanId:r.parentSpanId,traceFlags:r.context.traceFlags,traceId:r.context.traceId};let i=advanceSessionWindow(t.sessionId,await ensureSessionContext({agentName:void 0,channelKind:void 0,idempotencyKey:sessionIdempotencyKey(t.sessionId),parentTraceContext:t.parentTraceContext,rootSessionId:t.rootSessionId,sessionId:t.sessionId,type:`session.started`})),a={isRemote:!1,spanId:n.idGenerator.deriveSpanId(`turn:${t.idempotencyKey}`),traceFlags:i.context.traceFlags,traceId:i.context.traceId};return await n.stateStore.setSession(t.sessionId,{...i,turnsInWindow:i.turnsInWindow+1}),await n.stateStore.setTurn(t.sessionId,t.turnId,{context:a,lineage:t.parentLineage,parentIsRemote:i.context.isRemote,parentSpanId:i.context.spanId,rootSessionId:t.rootSessionId,sequence:t.sequence,startTimeMs:Date.now()}),portableSpanContext(i.context)}}}function portableSpanContext(e){return{spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}function adoptedSpanContext(e){return{isRemote:`isRemote`in e&&e.isRemote===!0,spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}export{createAgentOtelSessionContext};
1
+ import{normalizeChannelAudience}from"#shared/channel-audience.js";import{sessionIdempotencyKey}from"#harness/instrumentation/lifecycle.js";import{SESSION_WINDOW_TURN_LIMIT}from"#tracing/agent-trace-state.js";function createAgentOtelSessionContext(r){let openSessionWindow=e=>{if(!shouldTrace(r.tracePolicy,e))return{isRemote:!1,spanId:r.idGenerator.deriveSpanId(`session:${e.sessionId}:${e.index}`),traceFlags:0,traceId:r.idGenerator.generateTraceId()};let t=r.tracer.startSpan(`agent.session`,{attributes:{"agent.framework.name":`eve`,"agent.framework.version":r.frameworkVersion,"agent.channel.audience":e.channelAudience,"agent.name":e.agentName,"agent.root.session.id":e.rootSessionId,"agent.session.id":e.sessionId,"agent.session.window":e.index,"agent.trace.schema.version":1,...e.previousTraceId===void 0?{}:{"agent.session.window.previous.trace.id":e.previousTraceId}},root:!0});return t.addEvent(e.index===0?`session.started`:`session.window.opened`),t.end(),t.spanContext()},ensureSessionContext=async t=>{let n=await r.stateStore.getSession(t.sessionId);return n===void 0&&(n={agentName:t.agentName,channelAudience:normalizeChannelAudience(t.channelAudience),channelKind:t.channelKind,context:t.parentTraceContext===void 0?openSessionWindow({agentName:t.agentName,channelAudience:normalizeChannelAudience(t.channelAudience),index:0,rootSessionId:t.rootSessionId,sessionId:t.sessionId}):adoptedSpanContext(t.parentTraceContext,shouldTrace(r.tracePolicy,{agentName:t.agentName,channelAudience:normalizeChannelAudience(t.channelAudience),rootSessionId:t.rootSessionId,sessionId:t.sessionId})),rootSessionId:t.rootSessionId,turnsInWindow:0,window:0},await r.stateStore.setSession(t.sessionId,n)),n},advanceSessionWindow=(t,r)=>{if(r.turnsInWindow<SESSION_WINDOW_TURN_LIMIT)return r;let i=r.window+1;return{...r,context:openSessionWindow({agentName:r.agentName,channelAudience:normalizeChannelAudience(r.channelAudience),index:i,previousTraceId:r.context.traceId,rootSessionId:r.rootSessionId,sessionId:t}),turnsInWindow:0,window:i}};return{ensureSessionContext,prepareSessionTrace:async e=>portableSpanContext((await ensureSessionContext(e)).context),prepareTurnTrace:async e=>{let n=await r.stateStore.getTurn(e.sessionId,e.turnId);if(n!==void 0)return{spanId:n.parentSpanId,traceFlags:n.context.traceFlags,traceId:n.context.traceId};let i=advanceSessionWindow(e.sessionId,await ensureSessionContext({agentName:void 0,channelAudience:`unknown`,channelKind:void 0,idempotencyKey:sessionIdempotencyKey(e.sessionId),parentTraceContext:e.parentTraceContext,rootSessionId:e.rootSessionId,sessionId:e.sessionId,type:`session.started`})),a={isRemote:!1,spanId:r.idGenerator.deriveSpanId(`turn:${e.idempotencyKey}`),traceFlags:i.context.traceFlags,traceId:i.context.traceId};return await r.stateStore.setSession(e.sessionId,{...i,turnsInWindow:i.turnsInWindow+1}),await r.stateStore.setTurn(e.sessionId,e.turnId,{context:a,lineage:e.parentLineage,parentIsRemote:i.context.isRemote,parentSpanId:i.context.spanId,rootSessionId:e.rootSessionId,sequence:e.sequence,startTimeMs:Date.now()}),portableSpanContext(i.context)}}}function shouldTrace(e,t){try{return e?.({agentName:t.agentName,audience:t.channelAudience,rootSessionId:t.rootSessionId,sessionId:t.sessionId})??t.channelAudience===`public`}catch{return!1}}function portableSpanContext(e){return{spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}function adoptedSpanContext(e,t=!0){return{isRemote:`isRemote`in e&&e.isRemote===!0,spanId:e.spanId,traceFlags:t?e.traceFlags:0,traceId:e.traceId}}export{createAgentOtelSessionContext};