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.
- package/CHANGELOG.md +14 -0
- package/dist/src/channel/adapter.d.ts +2 -1
- package/dist/src/channel/instrumentation.js +1 -1
- package/dist/src/cli/commands/registry-project.d.ts +3 -0
- package/dist/src/cli/commands/registry-project.js +2 -1
- package/dist/src/cli/commands/registry.d.ts +2 -0
- package/dist/src/cli/commands/registry.js +1 -1
- package/dist/src/cli/dev/tui/traces/trace-view.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/compiled/jsonc-parser/index.d.ts +19 -0
- package/dist/src/compiler/extension-compatibility.d.ts +2 -2
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/execution/workflow-trace-context.js +1 -1
- package/dist/src/harness/channel-delivery-instrumentation.js +1 -1
- package/dist/src/harness/instrumentation/lifecycle.d.ts +4 -0
- package/dist/src/harness/instrumentation/native-events.d.ts +2 -0
- package/dist/src/harness/instrumentation/native-events.js +1 -1
- package/dist/src/harness/prepare-trace-context.d.ts +2 -0
- package/dist/src/harness/prepare-trace-context.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
- package/dist/src/public/channels/chat-sdk/audience.d.ts +2 -0
- package/dist/src/public/channels/chat-sdk/audience.js +1 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +2 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
- package/dist/src/public/channels/discord/audience.d.ts +5 -0
- package/dist/src/public/channels/discord/audience.js +1 -0
- package/dist/src/public/channels/discord/discordChannel.d.ts +2 -0
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/discord/inbound.d.ts +1 -0
- package/dist/src/public/channels/discord/inbound.js +1 -1
- package/dist/src/public/channels/discord/index.d.ts +1 -0
- package/dist/src/public/channels/index.d.ts +3 -2
- package/dist/src/public/channels/slack/slackChannel.d.ts +4 -0
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/teams/index.d.ts +1 -0
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/telegram/audience.d.ts +3 -0
- package/dist/src/public/channels/telegram/audience.js +1 -0
- package/dist/src/public/channels/telegram/index.d.ts +1 -0
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +2 -0
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/definitions/channel.d.ts +1 -0
- package/dist/src/public/instrumentation/otel.d.ts +6 -10
- package/dist/src/public/instrumentation/otel.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +2 -1
- package/dist/src/setup/scaffold/create/web-template.js +373 -1
- package/dist/src/shared/channel-audience.d.ts +7 -0
- package/dist/src/shared/channel-audience.js +1 -0
- package/dist/src/shared/channel-definition.d.ts +2 -1
- package/dist/src/tracing/agent-action-instrumentation.js +1 -1
- package/dist/src/tracing/agent-approval-instrumentation.js +1 -1
- package/dist/src/tracing/agent-channel-delivery-instrumentation.js +1 -1
- package/dist/src/tracing/agent-otel-provider.d.ts +2 -0
- package/dist/src/tracing/agent-otel-provider.js +2 -2
- package/dist/src/tracing/agent-otel-session-context.d.ts +2 -0
- package/dist/src/tracing/agent-otel-session-context.js +1 -1
- package/dist/src/tracing/agent-trace-context-store.js +1 -1
- package/dist/src/tracing/agent-trace-state.d.ts +3 -0
- package/dist/src/tracing/channel-audience-context.d.ts +4 -0
- package/dist/src/tracing/channel-audience-context.js +1 -0
- package/dist/src/tracing/content-attributes.js +1 -1
- package/dist/src/tracing/content-span-processor.d.ts +7 -7
- package/dist/src/tracing/content-span-processor.js +1 -1
- package/dist/src/tracing/install-instrumentation-runtime.js +1 -1
- package/dist/src/tracing/local-instrumentation-runtime.d.ts +3 -0
- package/dist/src/tracing/local-instrumentation-runtime.js +1 -1
- package/dist/src/tracing/local-traces.d.ts +1 -10
- package/dist/src/tracing/local-traces.js +1 -1
- package/dist/src/tracing/otel-declaration.d.ts +34 -27
- package/dist/src/tracing/otel-declaration.js +1 -1
- package/dist/src/tracing/sampled-trace.d.ts +2 -0
- package/dist/src/tracing/sampled-trace.js +1 -0
- package/dist/src/tracing/span-export-policy.d.ts +41 -0
- package/dist/src/tracing/span-export-policy.js +1 -0
- package/dist/src/tracing/suppress-tracing.d.ts +2 -0
- package/dist/src/tracing/suppress-tracing.js +1 -0
- package/docs/channels/custom.mdx +2 -0
- package/docs/guides/instrumentation.md +2 -0
- package/docs/tutorial/ship-it.mdx +1 -1
- 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(
|
|
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(
|
|
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(
|
|
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)
|
|
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(
|
|
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(
|
|
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};
|