@economic/agents 2.12.0 → 2.13.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/README.md +40 -13
- package/dist/index.d.mts +105 -1
- package/dist/index.mjs +435 -185
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -640,7 +640,30 @@ When configured:
|
|
|
640
640
|
AI telemetry is emitted per turn from the `ai` SDK's OpenTelemetry spans:
|
|
641
641
|
|
|
642
642
|
- **Audit logs** → one JSON object per turn in `AGENTS_AUDIT_LOGS` (model, actor, IP, prompt, response, tool calls).
|
|
643
|
-
- **Analytics** → per-turn and per-tool
|
|
643
|
+
- **Analytics** → typed per-turn and per-tool events. By default these are written to
|
|
644
|
+
`AGENTS_ANALYTICS` using the existing Analytics Engine schema.
|
|
645
|
+
|
|
646
|
+
Additional analytics destinations can receive the same events by overriding
|
|
647
|
+
`getAnalyticsHandlers()`. Analytics Engine remains enabled whenever `AGENTS_ANALYTICS` is bound:
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
import type { AnalyticsHandler } from "@economic/agents";
|
|
651
|
+
|
|
652
|
+
const warehouse: AnalyticsHandler = {
|
|
653
|
+
name: "warehouse",
|
|
654
|
+
async handle(event) {
|
|
655
|
+
await sendToWarehouse(event);
|
|
656
|
+
},
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
getAnalyticsHandlers() {
|
|
660
|
+
return [warehouse];
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
Handler failures are isolated and recorded as operational errors. Delivery runs through the
|
|
665
|
+
agent's lifetime management without blocking the response. `prompt.received` includes the raw
|
|
666
|
+
prompt for destinations such as conversation classification; handlers must treat it as sensitive.
|
|
644
667
|
|
|
645
668
|
Separately, the SDK writes structured operational logs for completed/failed LLM and tool calls, turn duration, framework failures, and selected recovery warnings. Prompt, response, tool argument, and tool result content is excluded. These records use the stable fields `source`, `event`, `level`, `timestamp`, `agentName`, `agentClass`, `durableObjectName`, and `attributes`, while preserving Cloudflare's diagnostic events.
|
|
646
669
|
|
|
@@ -669,21 +692,25 @@ Imported from `@economic/agents` unless noted.
|
|
|
669
692
|
| `ToolContext` | `RequestContext & { _userContext?: UserContext }`. |
|
|
670
693
|
| `AgentEnv` | The bindings the runtime expects. |
|
|
671
694
|
| `AgentConnectionState` / `AgentConnectionStatus` / `AgentConnectionType` | Connection state shared with the client. |
|
|
695
|
+
| `AnalyticsHandler` / `AnalyticsEvent` | Typed, consumer-configured product-analytics destinations. |
|
|
696
|
+
| `createAnalyticsEngineHandler(dataset)` | Analytics Engine destination using the existing v2 positional schema. |
|
|
672
697
|
|
|
673
698
|
### Members
|
|
674
699
|
|
|
675
|
-
| Member | On | Description
|
|
676
|
-
| ---------------------------------------------- | ----------- |
|
|
677
|
-
| `getModel(ctx?)` | `Agent` | Required. Model for inference.
|
|
678
|
-
| `getSystemPrompt(ctx?)` | `Agent` | Required. System prompt.
|
|
679
|
-
| `getTools()` | `Agent` | Always-on tools (default `{}`).
|
|
680
|
-
| `getSkills()` | `Agent` | Local skills (default `[]`).
|
|
681
|
-
| `
|
|
682
|
-
| `
|
|
683
|
-
| `
|
|
684
|
-
| `
|
|
685
|
-
| `
|
|
686
|
-
| `
|
|
700
|
+
| Member | On | Description |
|
|
701
|
+
| ---------------------------------------------- | ----------- | ---------------------------------------------------------------------- |
|
|
702
|
+
| `getModel(ctx?)` | `Agent` | Required. Model for inference. |
|
|
703
|
+
| `getSystemPrompt(ctx?)` | `Agent` | Required. System prompt. |
|
|
704
|
+
| `getTools()` | `Agent` | Always-on tools (default `{}`). |
|
|
705
|
+
| `getSkills()` | `Agent` | Local skills (default `[]`). |
|
|
706
|
+
| `getAnalyticsHandlers()` | `Agent` | Additional analytics destinations; Analytics Engine remains automatic. |
|
|
707
|
+
| `getAnalyticsAttributes()` | `Agent` | Additional dimensions included on every analytics event. |
|
|
708
|
+
| `static getJwtAuthConfig(env)` | `Agent` | Optional JWT verification and actor binding. |
|
|
709
|
+
| `getUserContext(jwtToken)` | `Agent` | Optional per-user context after auth. |
|
|
710
|
+
| `submitMessageFeedback` / `getMessageFeedback` | `ChatAgent` | Callable message feedback. |
|
|
711
|
+
| `agent` | `Assistant` | Required. Your `ChatAgent` subclass. |
|
|
712
|
+
| `fastModel` | `Assistant` | Required. Cheap model for titles/summaries. |
|
|
713
|
+
| `createChat` / `getChats` / `deleteChat` | `Assistant` | Callable chat management. |
|
|
687
714
|
|
|
688
715
|
### Package root (`@economic/agents`)
|
|
689
716
|
|
package/dist/index.d.mts
CHANGED
|
@@ -114,6 +114,102 @@ type Tool<Context extends Record<string, unknown> = Record<string, unknown>, INP
|
|
|
114
114
|
};
|
|
115
115
|
declare function tool<Context extends Record<string, unknown> = Record<string, unknown>, INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any>(definition: Tool<Context, INPUT, OUTPUT>): Tool$1<INPUT, OUTPUT>;
|
|
116
116
|
//#endregion
|
|
117
|
+
//#region src/server/features/analytics/types.d.ts
|
|
118
|
+
type AnalyticsAttribute = string | number | boolean;
|
|
119
|
+
type AnalyticsAttributes = Readonly<Record<string, AnalyticsAttribute>>;
|
|
120
|
+
interface AnalyticsUsage {
|
|
121
|
+
inputTokens: number;
|
|
122
|
+
outputTokens: number;
|
|
123
|
+
totalTokens: number;
|
|
124
|
+
cachedInputTokens?: number;
|
|
125
|
+
cacheWriteTokens?: number;
|
|
126
|
+
reasoningTokens?: number;
|
|
127
|
+
}
|
|
128
|
+
type AnalyticsEventPayload = {
|
|
129
|
+
type: "prompt.received"; /** Raw model messages. Handlers must treat this field as sensitive data. */
|
|
130
|
+
messages: readonly ModelMessage[];
|
|
131
|
+
continuation: boolean;
|
|
132
|
+
} | {
|
|
133
|
+
type: "turn.completed";
|
|
134
|
+
requestId: string;
|
|
135
|
+
status: string;
|
|
136
|
+
continuation: boolean;
|
|
137
|
+
responseSize: number;
|
|
138
|
+
} | {
|
|
139
|
+
type: "llm.completed";
|
|
140
|
+
model: string;
|
|
141
|
+
provider: string;
|
|
142
|
+
finishReason: string;
|
|
143
|
+
usage: AnalyticsUsage;
|
|
144
|
+
durationMs: number;
|
|
145
|
+
inputSize: number;
|
|
146
|
+
responseSize: number;
|
|
147
|
+
} | {
|
|
148
|
+
type: "tool.completed";
|
|
149
|
+
toolCallId?: string;
|
|
150
|
+
toolName: string;
|
|
151
|
+
skillNames: readonly string[];
|
|
152
|
+
success: boolean;
|
|
153
|
+
durationMs: number;
|
|
154
|
+
inputSize: number;
|
|
155
|
+
outputSize: number;
|
|
156
|
+
} | {
|
|
157
|
+
type: "feedback.submitted";
|
|
158
|
+
messageId: string;
|
|
159
|
+
rating: 1 | -1 | 0;
|
|
160
|
+
};
|
|
161
|
+
type AnalyticsEvent = AnalyticsEventPayload & {
|
|
162
|
+
schemaVersion: 1;
|
|
163
|
+
eventId: string;
|
|
164
|
+
timestamp: number;
|
|
165
|
+
agentName: string;
|
|
166
|
+
durableObjectName: string;
|
|
167
|
+
actorId: string;
|
|
168
|
+
attributes: AnalyticsAttributes;
|
|
169
|
+
};
|
|
170
|
+
/** Receives typed product-analytics events emitted by the SDK. */
|
|
171
|
+
interface AnalyticsHandler {
|
|
172
|
+
readonly name?: string;
|
|
173
|
+
handle(event: AnalyticsEvent): void | Promise<void>;
|
|
174
|
+
}
|
|
175
|
+
interface AnalyticsEventContext {
|
|
176
|
+
agentName: string;
|
|
177
|
+
durableObjectName: string;
|
|
178
|
+
actorId: string;
|
|
179
|
+
attributes?: AnalyticsAttributes;
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/server/features/analytics/analytics-engine.d.ts
|
|
183
|
+
/**
|
|
184
|
+
* Creates a Cloudflare Analytics Engine destination for SDK analytics events.
|
|
185
|
+
* It preserves the SDK v2 positional schema and never writes prompt content.
|
|
186
|
+
*/
|
|
187
|
+
declare function createAnalyticsEngineHandler(dataset: AnalyticsEngineDataset): AnalyticsHandler;
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/server/features/analytics/dispatcher.d.ts
|
|
190
|
+
declare function createAnalyticsEvent(context: AnalyticsEventContext, payload: AnalyticsEventPayload): AnalyticsEvent;
|
|
191
|
+
declare function dispatchAnalyticsEvent(handlers: readonly AnalyticsHandler[], event: AnalyticsEvent): Promise<void>;
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/server/features/analytics/emitter.d.ts
|
|
194
|
+
interface AnalyticsOptions {
|
|
195
|
+
getContext(): AnalyticsEventContext;
|
|
196
|
+
getHandlers(): readonly AnalyticsHandler[];
|
|
197
|
+
keepAlive<T>(callback: () => Promise<T>): Promise<T>;
|
|
198
|
+
}
|
|
199
|
+
declare class Analytics {
|
|
200
|
+
private readonly options;
|
|
201
|
+
private handlers?;
|
|
202
|
+
constructor(options: AnalyticsOptions);
|
|
203
|
+
private getHandlers;
|
|
204
|
+
private emit;
|
|
205
|
+
get enabled(): boolean;
|
|
206
|
+
get context(): AnalyticsEventContext;
|
|
207
|
+
promptReceived(messages: readonly ModelMessage[], continuation: boolean): void;
|
|
208
|
+
turnCompleted(requestId: string, status: string, continuation: boolean, response: unknown): void;
|
|
209
|
+
feedbackSubmitted(messageId: string, rating: 1 | -1 | 0): void;
|
|
210
|
+
event(payload: AnalyticsEventPayload | (() => AnalyticsEventPayload)): void;
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
117
213
|
//#region src/server/agents/Agent.d.ts
|
|
118
214
|
/** What the model would see on its next step — returned by {@link Agent.inspectTurn}. */
|
|
119
215
|
interface TurnSnapshot {
|
|
@@ -305,6 +401,14 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
|
|
|
305
401
|
* Best-effort and non-blocking — never allowed to interfere with a turn.
|
|
306
402
|
*/
|
|
307
403
|
protected registerInstanceActivity(): Promise<void>;
|
|
404
|
+
protected readonly analytics: Analytics;
|
|
405
|
+
/**
|
|
406
|
+
* Additional product-analytics destinations for this agent. Analytics Engine
|
|
407
|
+
* remains enabled whenever `AGENTS_ANALYTICS` is bound.
|
|
408
|
+
*/
|
|
409
|
+
getAnalyticsHandlers(): readonly AnalyticsHandler[];
|
|
410
|
+
/** Business dimensions added to every analytics event. */
|
|
411
|
+
getAnalyticsAttributes(): AnalyticsAttributes;
|
|
308
412
|
observability?: Observability;
|
|
309
413
|
/**
|
|
310
414
|
* Resolves the analytics/telemetry agent name to the entry-point agent: the
|
|
@@ -455,4 +559,4 @@ declare function routeAgentRequest<Env>(request: Request, env: Env, options?: Ag
|
|
|
455
559
|
//#region src/server/index.d.ts
|
|
456
560
|
declare function getCurrentToolContext(): any;
|
|
457
561
|
//#endregion
|
|
458
|
-
export { type Action, type ActionContext, Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, Assistant, ChatAgent, type ExchangedToken, type JwtAuthConfig, type RegisteredAction, type Skill, type SkillSource, type TokenExchangeConfig, type TokenExchangeResult, type Tool, type ToolContext, type ToolSet, type TurnSnapshot, type UnauthorizedPolicy, type UnauthorizedToolPolicy, action, createJwtAuthConfig, exchangeToken, getCurrentToolContext, routeAgentRequest, skill, tool };
|
|
562
|
+
export { type Action, type ActionContext, Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, type AnalyticsAttribute, type AnalyticsAttributes, type AnalyticsEvent, type AnalyticsEventPayload, type AnalyticsHandler, type AnalyticsUsage, Assistant, ChatAgent, type ExchangedToken, type JwtAuthConfig, type RegisteredAction, type Skill, type SkillSource, type TokenExchangeConfig, type TokenExchangeResult, type Tool, type ToolContext, type ToolSet, type TurnSnapshot, type UnauthorizedPolicy, type UnauthorizedToolPolicy, action, createAnalyticsEngineHandler, createAnalyticsEvent, createJwtAuthConfig, dispatchAnalyticsEvent, exchangeToken, getCurrentToolContext, routeAgentRequest, skill, tool };
|
package/dist/index.mjs
CHANGED
|
@@ -510,94 +510,35 @@ async function handleAuditSpan(span, auditLogs, context) {
|
|
|
510
510
|
//#endregion
|
|
511
511
|
//#region src/server/features/telemetry/analytics.ts
|
|
512
512
|
const emittedToolCallIds = /* @__PURE__ */ new Set();
|
|
513
|
-
function
|
|
514
|
-
if (value === void 0) return void 0;
|
|
513
|
+
function serializedSize$1(value) {
|
|
515
514
|
try {
|
|
516
|
-
return JSON.stringify(value);
|
|
515
|
+
return JSON.stringify(value)?.length ?? 0;
|
|
517
516
|
} catch {
|
|
518
|
-
return;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
function writeAnalyticsDatapoint(analytics, dataPoint) {
|
|
522
|
-
if (!analytics) return;
|
|
523
|
-
try {
|
|
524
|
-
analytics.writeDataPoint(dataPoint);
|
|
525
|
-
} catch (error) {
|
|
526
|
-
console.error("[Agent] Failed to write analytics datapoint", error);
|
|
517
|
+
return 0;
|
|
527
518
|
}
|
|
528
519
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
* aggregated across all chats without fanning out to every chat DO.
|
|
532
|
-
*
|
|
533
|
-
* Emitted on every rating change; the dashboard takes the latest rating per
|
|
534
|
-
* `messageId` (blob4) so re-rates and clears are idempotent.
|
|
535
|
-
*/
|
|
536
|
-
function recordFeedbackAnalytics(analytics, context, messageId, rating) {
|
|
537
|
-
writeAnalyticsDatapoint(analytics, {
|
|
538
|
-
indexes: [context.actorId],
|
|
539
|
-
blobs: [
|
|
540
|
-
"feedback",
|
|
541
|
-
context.agentName,
|
|
542
|
-
context.durableObjectName,
|
|
543
|
-
messageId
|
|
544
|
-
],
|
|
545
|
-
doubles: [rating]
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
function recordPromptReceivedAnalytics(analytics, context, messages, continuation) {
|
|
549
|
-
if (!analytics) return;
|
|
550
|
-
writeAnalyticsDatapoint(analytics, {
|
|
551
|
-
indexes: [context.actorId],
|
|
552
|
-
blobs: [
|
|
553
|
-
"prompt_received",
|
|
554
|
-
context.agentName,
|
|
555
|
-
context.durableObjectName,
|
|
556
|
-
String(continuation)
|
|
557
|
-
],
|
|
558
|
-
doubles: [safeJsonString(messages)?.length ?? 0]
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
function recordTurnCompletedAnalytics(analytics, context, requestId, status, continuation, response) {
|
|
562
|
-
if (!analytics) return;
|
|
563
|
-
writeAnalyticsDatapoint(analytics, {
|
|
564
|
-
indexes: [context.actorId],
|
|
565
|
-
blobs: [
|
|
566
|
-
"turn_completed",
|
|
567
|
-
context.agentName,
|
|
568
|
-
context.durableObjectName,
|
|
569
|
-
requestId,
|
|
570
|
-
status,
|
|
571
|
-
String(continuation)
|
|
572
|
-
],
|
|
573
|
-
doubles: [safeJsonString(response)?.length ?? 0]
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
function handleAnalyticsSpan(span, analytics, context) {
|
|
520
|
+
function handleAnalyticsSpan(span, analytics) {
|
|
521
|
+
if (!analytics.enabled) return;
|
|
577
522
|
if (span.name === "ai.streamText.doStream") {
|
|
578
523
|
const promptMessages = parseJson(stringAttribute(span, "ai.prompt.messages"));
|
|
579
524
|
const responseText = stringAttribute(span, "ai.response.text") ?? "";
|
|
580
525
|
const responseToolCalls = parseJson(stringAttribute(span, "ai.response.toolCalls"));
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
numberAttribute(span, "ai.usage.
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
durationMs(span.duration),
|
|
598
|
-
promptCharCount(promptMessages ?? []),
|
|
599
|
-
responseText.length
|
|
600
|
-
]
|
|
526
|
+
analytics.event({
|
|
527
|
+
type: "llm.completed",
|
|
528
|
+
model: stringAttribute(span, "ai.model.id") ?? "",
|
|
529
|
+
provider: stringAttribute(span, "ai.model.provider") ?? "",
|
|
530
|
+
finishReason: stringAttribute(span, "ai.response.finishReason") ?? "",
|
|
531
|
+
usage: {
|
|
532
|
+
inputTokens: numberAttribute(span, "ai.usage.inputTokens") ?? 0,
|
|
533
|
+
outputTokens: numberAttribute(span, "ai.usage.outputTokens") ?? 0,
|
|
534
|
+
totalTokens: numberAttribute(span, "ai.usage.totalTokens") ?? 0,
|
|
535
|
+
cachedInputTokens: numberAttribute(span, "ai.usage.inputTokenDetails.cacheReadTokens") ?? void 0,
|
|
536
|
+
cacheWriteTokens: numberAttribute(span, "ai.usage.inputTokenDetails.cacheWriteTokens") ?? void 0,
|
|
537
|
+
reasoningTokens: numberAttribute(span, "ai.usage.reasoningTokens") ?? void 0
|
|
538
|
+
},
|
|
539
|
+
durationMs: durationMs(span.duration),
|
|
540
|
+
inputSize: promptCharCount(promptMessages ?? []),
|
|
541
|
+
responseSize: responseText.length
|
|
601
542
|
});
|
|
602
543
|
if (Array.isArray(responseToolCalls)) for (const value of responseToolCalls) {
|
|
603
544
|
if (!value || typeof value !== "object") continue;
|
|
@@ -607,70 +548,39 @@ function handleAnalyticsSpan(span, analytics, context) {
|
|
|
607
548
|
const toolName = typeof toolCall.toolName === "string" ? toolCall.toolName : void 0;
|
|
608
549
|
if (!toolName) continue;
|
|
609
550
|
const input = toolCall.input;
|
|
610
|
-
const argsRaw = safeJsonString(input);
|
|
611
|
-
const success = span.status.code === 0;
|
|
612
551
|
const activatedSkills = extractSkillNames(toolName, input);
|
|
613
|
-
const skillNames = activatedSkills.length ? activatedSkills : [currentSkillByChat.get(context.durableObjectName) ?? ""];
|
|
552
|
+
const skillNames = activatedSkills.length ? activatedSkills : [currentSkillByChat.get(analytics.context.durableObjectName) ?? ""];
|
|
614
553
|
if (toolCallId) emittedToolCallIds.add(toolCallId);
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
],
|
|
625
|
-
doubles: [
|
|
626
|
-
0,
|
|
627
|
-
success ? 1 : 0,
|
|
628
|
-
argsRaw?.length ?? 0,
|
|
629
|
-
0,
|
|
630
|
-
0,
|
|
631
|
-
0,
|
|
632
|
-
0,
|
|
633
|
-
0
|
|
634
|
-
]
|
|
554
|
+
analytics.event({
|
|
555
|
+
type: "tool.completed",
|
|
556
|
+
toolCallId,
|
|
557
|
+
toolName,
|
|
558
|
+
skillNames,
|
|
559
|
+
success: span.status.code === 0,
|
|
560
|
+
durationMs: 0,
|
|
561
|
+
inputSize: serializedSize$1(input),
|
|
562
|
+
outputSize: 0
|
|
635
563
|
});
|
|
636
564
|
}
|
|
637
565
|
return;
|
|
638
566
|
}
|
|
639
|
-
if (span.name
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
context.agentName,
|
|
657
|
-
context.durableObjectName,
|
|
658
|
-
toolName ?? "",
|
|
659
|
-
skillName,
|
|
660
|
-
success ? "success" : "error"
|
|
661
|
-
],
|
|
662
|
-
doubles: [
|
|
663
|
-
duration,
|
|
664
|
-
success ? 1 : 0,
|
|
665
|
-
argsSize,
|
|
666
|
-
resultSize,
|
|
667
|
-
0,
|
|
668
|
-
0,
|
|
669
|
-
0,
|
|
670
|
-
0
|
|
671
|
-
]
|
|
672
|
-
});
|
|
673
|
-
}
|
|
567
|
+
if (span.name !== "ai.toolCall") return;
|
|
568
|
+
const toolCallId = stringAttribute(span, "ai.toolCall.id");
|
|
569
|
+
if (toolCallId && emittedToolCallIds.has(toolCallId)) return;
|
|
570
|
+
if (toolCallId) emittedToolCallIds.add(toolCallId);
|
|
571
|
+
const toolName = stringAttribute(span, "ai.toolCall.name") ?? "";
|
|
572
|
+
const argsRaw = stringAttribute(span, "ai.toolCall.args");
|
|
573
|
+
const activatedSkills = extractSkillNames(toolName, parseJson(argsRaw));
|
|
574
|
+
analytics.event({
|
|
575
|
+
type: "tool.completed",
|
|
576
|
+
toolCallId,
|
|
577
|
+
toolName,
|
|
578
|
+
skillNames: activatedSkills.length ? activatedSkills : [currentSkillByChat.get(analytics.context.durableObjectName) ?? ""],
|
|
579
|
+
success: span.status.code === 0,
|
|
580
|
+
durationMs: durationMs(span.duration),
|
|
581
|
+
inputSize: argsRaw?.length ?? 0,
|
|
582
|
+
outputSize: stringAttribute(span, "ai.toolCall.result")?.length ?? 0
|
|
583
|
+
});
|
|
674
584
|
}
|
|
675
585
|
//#endregion
|
|
676
586
|
//#region src/server/features/observability/index.ts
|
|
@@ -692,6 +602,36 @@ function writeOperationalLog(record, logger = console) {
|
|
|
692
602
|
else logger.log(message);
|
|
693
603
|
} catch {}
|
|
694
604
|
}
|
|
605
|
+
function errorAttributes(error) {
|
|
606
|
+
if (!(error instanceof Error)) return { error: String(error) };
|
|
607
|
+
const causes = [];
|
|
608
|
+
let cause = error.cause;
|
|
609
|
+
while (cause !== void 0 && causes.length < 5) {
|
|
610
|
+
causes.push(cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause));
|
|
611
|
+
cause = cause instanceof Error ? cause.cause : void 0;
|
|
612
|
+
}
|
|
613
|
+
return {
|
|
614
|
+
error: error.message,
|
|
615
|
+
errorType: error.name,
|
|
616
|
+
stack: error.stack,
|
|
617
|
+
...causes.length ? { causes } : {}
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function logOperationalError(event, error, context = {}) {
|
|
621
|
+
writeOperationalLog({
|
|
622
|
+
source: "@economic/agents",
|
|
623
|
+
event,
|
|
624
|
+
level: "error",
|
|
625
|
+
timestamp: Date.now(),
|
|
626
|
+
agentName: context.agentName,
|
|
627
|
+
agentClass: context.agentClass,
|
|
628
|
+
durableObjectName: context.durableObjectName,
|
|
629
|
+
attributes: {
|
|
630
|
+
...context.attributes,
|
|
631
|
+
...errorAttributes(error)
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
}
|
|
695
635
|
function isFailure(event) {
|
|
696
636
|
return event.type.endsWith("error") || event.type.endsWith("failed") || event.type.endsWith("exhausted") || "error" in event.payload && Boolean(event.payload.error);
|
|
697
637
|
}
|
|
@@ -793,11 +733,11 @@ var AgentSpanExporter = class {
|
|
|
793
733
|
if (span.name === "ai.streamText.doStream") {
|
|
794
734
|
rememberDoStream(span, this.context.durableObjectName);
|
|
795
735
|
attachToolCallsToChat(span, this.context.durableObjectName);
|
|
796
|
-
handleAnalyticsSpan(span, this.analytics
|
|
736
|
+
handleAnalyticsSpan(span, this.analytics);
|
|
797
737
|
} else if (span.name === "ai.streamText") await handleAuditSpan(span, this.auditLogs, this.context);
|
|
798
738
|
else if (span.name === "ai.toolCall") {
|
|
799
739
|
rememberToolCall(span);
|
|
800
|
-
handleAnalyticsSpan(span, this.analytics
|
|
740
|
+
handleAnalyticsSpan(span, this.analytics);
|
|
801
741
|
}
|
|
802
742
|
}
|
|
803
743
|
resultCallback({ code: 0 });
|
|
@@ -815,6 +755,254 @@ function createAgentTracer(auditLogs, analytics, context) {
|
|
|
815
755
|
return new BasicTracerProvider({ spanProcessors: [new SimpleSpanProcessor(new AgentSpanExporter(auditLogs, analytics, context))] }).getTracer("@economic/agents");
|
|
816
756
|
}
|
|
817
757
|
//#endregion
|
|
758
|
+
//#region src/server/features/analytics/utils.ts
|
|
759
|
+
function serializedSize(value) {
|
|
760
|
+
try {
|
|
761
|
+
return JSON.stringify(value)?.length ?? 0;
|
|
762
|
+
} catch {
|
|
763
|
+
return 0;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
//#endregion
|
|
767
|
+
//#region src/server/features/analytics/analytics-engine.ts
|
|
768
|
+
const MAX_INDEX_BYTES = 96;
|
|
769
|
+
const MAX_BLOB_BYTES = 16 * 1024;
|
|
770
|
+
const encoder = new TextEncoder();
|
|
771
|
+
/**
|
|
772
|
+
* Creates a Cloudflare Analytics Engine destination for SDK analytics events.
|
|
773
|
+
* It preserves the SDK v2 positional schema and never writes prompt content.
|
|
774
|
+
*/
|
|
775
|
+
function createAnalyticsEngineHandler(dataset) {
|
|
776
|
+
return {
|
|
777
|
+
name: "Cloudflare Analytics Engine",
|
|
778
|
+
async handle(event) {
|
|
779
|
+
for (const point of toAnalyticsEnginePoints(event)) dataset.writeDataPoint(await boundAnalyticsPoint(point));
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
async function boundAnalyticsPoint(point) {
|
|
784
|
+
return {
|
|
785
|
+
...point,
|
|
786
|
+
indexes: await Promise.all(point.indexes.map(boundIndex)),
|
|
787
|
+
blobs: boundBlobs(point.blobs)
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
async function boundIndex(value) {
|
|
791
|
+
if (byteLength(value) <= MAX_INDEX_BYTES) return value;
|
|
792
|
+
const digest = await crypto.subtle.digest("SHA-256", encoder.encode(value));
|
|
793
|
+
const suffix = `:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
794
|
+
return `${truncateUtf8(value, MAX_INDEX_BYTES - byteLength(suffix))}${suffix}`;
|
|
795
|
+
}
|
|
796
|
+
function boundBlobs(values) {
|
|
797
|
+
const blobs = [...values];
|
|
798
|
+
let sizes = blobs.map(byteLength);
|
|
799
|
+
let total = sizes.reduce((sum, size) => sum + size, 0);
|
|
800
|
+
if (total <= MAX_BLOB_BYTES) return blobs;
|
|
801
|
+
const attributesIndex = blobs.length - 2;
|
|
802
|
+
blobs[attributesIndex] = "{}";
|
|
803
|
+
sizes = blobs.map(byteLength);
|
|
804
|
+
total = sizes.reduce((sum, size) => sum + size, 0);
|
|
805
|
+
while (total > MAX_BLOB_BYTES) {
|
|
806
|
+
const largestSize = Math.max(...sizes);
|
|
807
|
+
const largestIndex = sizes.indexOf(largestSize);
|
|
808
|
+
const value = truncateUtf8(blobs[largestIndex] ?? "", largestSize - (total - MAX_BLOB_BYTES));
|
|
809
|
+
const nextSize = byteLength(value);
|
|
810
|
+
blobs[largestIndex] = value;
|
|
811
|
+
sizes[largestIndex] = nextSize;
|
|
812
|
+
total -= largestSize - nextSize;
|
|
813
|
+
}
|
|
814
|
+
return blobs;
|
|
815
|
+
}
|
|
816
|
+
function truncateUtf8(value, maxBytes) {
|
|
817
|
+
let bytes = 0;
|
|
818
|
+
let end = 0;
|
|
819
|
+
for (const character of value) {
|
|
820
|
+
const characterBytes = byteLength(character);
|
|
821
|
+
if (bytes + characterBytes > maxBytes) break;
|
|
822
|
+
bytes += characterBytes;
|
|
823
|
+
end += character.length;
|
|
824
|
+
}
|
|
825
|
+
return value.slice(0, end);
|
|
826
|
+
}
|
|
827
|
+
function byteLength(value) {
|
|
828
|
+
return encoder.encode(value).byteLength;
|
|
829
|
+
}
|
|
830
|
+
function toAnalyticsEnginePoints(event) {
|
|
831
|
+
const common = [
|
|
832
|
+
event.eventId,
|
|
833
|
+
JSON.stringify(event.attributes),
|
|
834
|
+
String(event.schemaVersion)
|
|
835
|
+
];
|
|
836
|
+
const indexes = [event.actorId];
|
|
837
|
+
switch (event.type) {
|
|
838
|
+
case "prompt.received": return [{
|
|
839
|
+
indexes,
|
|
840
|
+
blobs: [
|
|
841
|
+
"prompt_received",
|
|
842
|
+
event.agentName,
|
|
843
|
+
event.durableObjectName,
|
|
844
|
+
String(event.continuation),
|
|
845
|
+
...common
|
|
846
|
+
],
|
|
847
|
+
doubles: [serializedSize(event.messages)]
|
|
848
|
+
}];
|
|
849
|
+
case "turn.completed": return [{
|
|
850
|
+
indexes,
|
|
851
|
+
blobs: [
|
|
852
|
+
"turn_completed",
|
|
853
|
+
event.agentName,
|
|
854
|
+
event.durableObjectName,
|
|
855
|
+
event.requestId,
|
|
856
|
+
event.status,
|
|
857
|
+
String(event.continuation),
|
|
858
|
+
...common
|
|
859
|
+
],
|
|
860
|
+
doubles: [event.responseSize]
|
|
861
|
+
}];
|
|
862
|
+
case "llm.completed": return [{
|
|
863
|
+
indexes,
|
|
864
|
+
blobs: [
|
|
865
|
+
"llm_call",
|
|
866
|
+
event.agentName,
|
|
867
|
+
event.durableObjectName,
|
|
868
|
+
event.model,
|
|
869
|
+
event.provider,
|
|
870
|
+
event.finishReason,
|
|
871
|
+
...common
|
|
872
|
+
],
|
|
873
|
+
doubles: [
|
|
874
|
+
event.usage.inputTokens,
|
|
875
|
+
event.usage.outputTokens,
|
|
876
|
+
event.usage.totalTokens,
|
|
877
|
+
event.usage.cachedInputTokens ?? 0,
|
|
878
|
+
event.usage.cacheWriteTokens ?? 0,
|
|
879
|
+
event.durationMs,
|
|
880
|
+
event.inputSize,
|
|
881
|
+
event.responseSize,
|
|
882
|
+
event.usage.reasoningTokens ?? 0
|
|
883
|
+
]
|
|
884
|
+
}];
|
|
885
|
+
case "tool.completed": return (event.skillNames.length ? event.skillNames : [""]).map((skillName) => ({
|
|
886
|
+
indexes,
|
|
887
|
+
blobs: [
|
|
888
|
+
"tool_call",
|
|
889
|
+
event.agentName,
|
|
890
|
+
event.durableObjectName,
|
|
891
|
+
event.toolName,
|
|
892
|
+
skillName,
|
|
893
|
+
event.success ? "success" : "error",
|
|
894
|
+
event.toolCallId ?? "",
|
|
895
|
+
...common
|
|
896
|
+
],
|
|
897
|
+
doubles: [
|
|
898
|
+
event.durationMs,
|
|
899
|
+
event.success ? 1 : 0,
|
|
900
|
+
event.inputSize,
|
|
901
|
+
event.outputSize,
|
|
902
|
+
0,
|
|
903
|
+
0,
|
|
904
|
+
0,
|
|
905
|
+
0
|
|
906
|
+
]
|
|
907
|
+
}));
|
|
908
|
+
case "feedback.submitted": return [{
|
|
909
|
+
indexes,
|
|
910
|
+
blobs: [
|
|
911
|
+
"feedback",
|
|
912
|
+
event.agentName,
|
|
913
|
+
event.durableObjectName,
|
|
914
|
+
event.messageId,
|
|
915
|
+
...common
|
|
916
|
+
],
|
|
917
|
+
doubles: [event.rating]
|
|
918
|
+
}];
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
//#endregion
|
|
922
|
+
//#region src/server/features/analytics/dispatcher.ts
|
|
923
|
+
function createAnalyticsEvent(context, payload) {
|
|
924
|
+
return {
|
|
925
|
+
...payload,
|
|
926
|
+
schemaVersion: 1,
|
|
927
|
+
eventId: crypto.randomUUID(),
|
|
928
|
+
timestamp: Date.now(),
|
|
929
|
+
agentName: context.agentName,
|
|
930
|
+
durableObjectName: context.durableObjectName,
|
|
931
|
+
actorId: context.actorId,
|
|
932
|
+
attributes: context.attributes ?? {}
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
async function dispatchAnalyticsEvent(handlers, event) {
|
|
936
|
+
await Promise.all(handlers.map(async (handler) => {
|
|
937
|
+
try {
|
|
938
|
+
await handler.handle(event);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
writeOperationalLog({
|
|
941
|
+
source: "@economic/agents",
|
|
942
|
+
event: "agent.analytics.handler.failed",
|
|
943
|
+
level: "error",
|
|
944
|
+
timestamp: Date.now(),
|
|
945
|
+
agentName: event.agentName,
|
|
946
|
+
durableObjectName: event.durableObjectName,
|
|
947
|
+
attributes: {
|
|
948
|
+
handler: handler.name ?? "handler",
|
|
949
|
+
error: error instanceof Error ? error.message : String(error)
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
}));
|
|
954
|
+
}
|
|
955
|
+
//#endregion
|
|
956
|
+
//#region src/server/features/analytics/emitter.ts
|
|
957
|
+
var Analytics = class {
|
|
958
|
+
options;
|
|
959
|
+
handlers;
|
|
960
|
+
constructor(options) {
|
|
961
|
+
this.options = options;
|
|
962
|
+
}
|
|
963
|
+
getHandlers() {
|
|
964
|
+
return this.handlers ??= this.options.getHandlers();
|
|
965
|
+
}
|
|
966
|
+
emit(payload) {
|
|
967
|
+
const handlers = this.getHandlers();
|
|
968
|
+
if (handlers.length === 0) return;
|
|
969
|
+
const eventPayload = typeof payload === "function" ? payload() : payload;
|
|
970
|
+
this.options.keepAlive(() => dispatchAnalyticsEvent(handlers, createAnalyticsEvent(this.context, eventPayload)));
|
|
971
|
+
}
|
|
972
|
+
get enabled() {
|
|
973
|
+
return this.getHandlers().length > 0;
|
|
974
|
+
}
|
|
975
|
+
get context() {
|
|
976
|
+
return this.options.getContext();
|
|
977
|
+
}
|
|
978
|
+
promptReceived(messages, continuation) {
|
|
979
|
+
this.emit({
|
|
980
|
+
type: "prompt.received",
|
|
981
|
+
messages,
|
|
982
|
+
continuation
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
turnCompleted(requestId, status, continuation, response) {
|
|
986
|
+
this.emit(() => ({
|
|
987
|
+
type: "turn.completed",
|
|
988
|
+
requestId,
|
|
989
|
+
status,
|
|
990
|
+
continuation,
|
|
991
|
+
responseSize: serializedSize(response)
|
|
992
|
+
}));
|
|
993
|
+
}
|
|
994
|
+
feedbackSubmitted(messageId, rating) {
|
|
995
|
+
this.emit({
|
|
996
|
+
type: "feedback.submitted",
|
|
997
|
+
messageId,
|
|
998
|
+
rating
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
event(payload) {
|
|
1002
|
+
this.emit(payload);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
//#endregion
|
|
818
1006
|
//#region src/server/features/registry.ts
|
|
819
1007
|
/**
|
|
820
1008
|
* Registers a top-level DO in the global registry.
|
|
@@ -964,11 +1152,7 @@ var Agent = class extends Think {
|
|
|
964
1152
|
* `returned.tools` into your own `TurnConfig.tools` if you return tools.
|
|
965
1153
|
*/
|
|
966
1154
|
async beforeTurn(ctx) {
|
|
967
|
-
|
|
968
|
-
agentName: this.getTelemetryAgentName(),
|
|
969
|
-
durableObjectName: this.name,
|
|
970
|
-
actorId: this.getTelemetryActorId()
|
|
971
|
-
}, ctx.messages, ctx.continuation);
|
|
1155
|
+
this.analytics.promptReceived(ctx.messages, ctx.continuation);
|
|
972
1156
|
this.registerInstanceActivity();
|
|
973
1157
|
const body = await this._applyTokenExchange(ctx.body);
|
|
974
1158
|
this._turn.context = this.getToolContextForCurrentTurn(body);
|
|
@@ -987,7 +1171,7 @@ var Agent = class extends Think {
|
|
|
987
1171
|
experimental_transform: buildSourcesTransform(),
|
|
988
1172
|
experimental_telemetry: {
|
|
989
1173
|
isEnabled: true,
|
|
990
|
-
tracer: createAgentTracer(this.env.AGENTS_AUDIT_LOGS, this.
|
|
1174
|
+
tracer: createAgentTracer(this.env.AGENTS_AUDIT_LOGS, this.analytics, {
|
|
991
1175
|
agentName: this.getTelemetryAgentName(),
|
|
992
1176
|
agentClass: this.constructor.name,
|
|
993
1177
|
durableObjectName: this.name,
|
|
@@ -1346,7 +1530,12 @@ var Agent = class extends Think {
|
|
|
1346
1530
|
try {
|
|
1347
1531
|
result = await verifyJwt(request, config);
|
|
1348
1532
|
} catch (error) {
|
|
1349
|
-
|
|
1533
|
+
logOperationalError("agent.authentication.failed", error, {
|
|
1534
|
+
agentName: this.getTelemetryAgentName(),
|
|
1535
|
+
agentClass: this.constructor.name,
|
|
1536
|
+
durableObjectName: this.name,
|
|
1537
|
+
attributes: { stage: "jwt-verification" }
|
|
1538
|
+
});
|
|
1350
1539
|
return {
|
|
1351
1540
|
success: false,
|
|
1352
1541
|
status: 401,
|
|
@@ -1369,7 +1558,12 @@ var Agent = class extends Think {
|
|
|
1369
1558
|
try {
|
|
1370
1559
|
exchanged = await exchangeToken(token, exchangeConfig);
|
|
1371
1560
|
} catch (error) {
|
|
1372
|
-
|
|
1561
|
+
logOperationalError("agent.authentication.failed", error, {
|
|
1562
|
+
agentName: this.getTelemetryAgentName(),
|
|
1563
|
+
agentClass: this.constructor.name,
|
|
1564
|
+
durableObjectName: this.name,
|
|
1565
|
+
attributes: { stage: "token-exchange" }
|
|
1566
|
+
});
|
|
1373
1567
|
return {
|
|
1374
1568
|
success: false,
|
|
1375
1569
|
status: 500,
|
|
@@ -1377,7 +1571,12 @@ var Agent = class extends Think {
|
|
|
1377
1571
|
};
|
|
1378
1572
|
}
|
|
1379
1573
|
if (!exchanged.success) {
|
|
1380
|
-
|
|
1574
|
+
logOperationalError("agent.authentication.failed", new Error(exchanged.message), {
|
|
1575
|
+
agentName: this.getTelemetryAgentName(),
|
|
1576
|
+
agentClass: this.constructor.name,
|
|
1577
|
+
durableObjectName: this.name,
|
|
1578
|
+
attributes: { stage: "token-exchange" }
|
|
1579
|
+
});
|
|
1381
1580
|
return {
|
|
1382
1581
|
success: false,
|
|
1383
1582
|
status: exchanged.subjectTokenRejected ? 401 : 500,
|
|
@@ -1395,7 +1594,12 @@ var Agent = class extends Think {
|
|
|
1395
1594
|
userContext: this.userContext
|
|
1396
1595
|
};
|
|
1397
1596
|
} catch (error) {
|
|
1398
|
-
|
|
1597
|
+
logOperationalError("agent.authentication.failed", error, {
|
|
1598
|
+
agentName: this.getTelemetryAgentName(),
|
|
1599
|
+
agentClass: this.constructor.name,
|
|
1600
|
+
durableObjectName: this.name,
|
|
1601
|
+
attributes: { stage: "user-context" }
|
|
1602
|
+
});
|
|
1399
1603
|
const closeCode = getConnectCloseCode(error);
|
|
1400
1604
|
return {
|
|
1401
1605
|
success: false,
|
|
@@ -1459,7 +1663,11 @@ var Agent = class extends Think {
|
|
|
1459
1663
|
createdAt: Date.now()
|
|
1460
1664
|
});
|
|
1461
1665
|
} catch (error) {
|
|
1462
|
-
|
|
1666
|
+
logOperationalError("agent.registry.registration.failed", error, {
|
|
1667
|
+
agentName: this.getTelemetryAgentName(),
|
|
1668
|
+
agentClass: this.constructor.name,
|
|
1669
|
+
durableObjectName: this.name
|
|
1670
|
+
});
|
|
1463
1671
|
}
|
|
1464
1672
|
}
|
|
1465
1673
|
/**
|
|
@@ -1485,9 +1693,34 @@ var Agent = class extends Think {
|
|
|
1485
1693
|
updatedAt: Date.now()
|
|
1486
1694
|
});
|
|
1487
1695
|
} catch (error) {
|
|
1488
|
-
|
|
1696
|
+
logOperationalError("agent.registry.activity.failed", error, {
|
|
1697
|
+
agentName: this.getTelemetryAgentName(),
|
|
1698
|
+
agentClass: this.constructor.name,
|
|
1699
|
+
durableObjectName: this.name
|
|
1700
|
+
});
|
|
1489
1701
|
}
|
|
1490
1702
|
}
|
|
1703
|
+
analytics = new Analytics({
|
|
1704
|
+
getContext: () => ({
|
|
1705
|
+
agentName: this.getTelemetryAgentName(),
|
|
1706
|
+
durableObjectName: this.name,
|
|
1707
|
+
actorId: this.getTelemetryActorId(),
|
|
1708
|
+
attributes: this.getAnalyticsAttributes()
|
|
1709
|
+
}),
|
|
1710
|
+
getHandlers: () => [...this.env.AGENTS_ANALYTICS ? [createAnalyticsEngineHandler(this.env.AGENTS_ANALYTICS)] : [], ...this.getAnalyticsHandlers()],
|
|
1711
|
+
keepAlive: (callback) => this.keepAliveWhile(callback)
|
|
1712
|
+
});
|
|
1713
|
+
/**
|
|
1714
|
+
* Additional product-analytics destinations for this agent. Analytics Engine
|
|
1715
|
+
* remains enabled whenever `AGENTS_ANALYTICS` is bound.
|
|
1716
|
+
*/
|
|
1717
|
+
getAnalyticsHandlers() {
|
|
1718
|
+
return [];
|
|
1719
|
+
}
|
|
1720
|
+
/** Business dimensions added to every analytics event. */
|
|
1721
|
+
getAnalyticsAttributes() {
|
|
1722
|
+
return {};
|
|
1723
|
+
}
|
|
1491
1724
|
observability = createWorkerObservability({ getIdentity: () => ({
|
|
1492
1725
|
agentName: this.getTelemetryAgentName(),
|
|
1493
1726
|
agentClass: this.constructor.name
|
|
@@ -1884,7 +2117,12 @@ var Assistant = class extends Agent$1 {
|
|
|
1884
2117
|
try {
|
|
1885
2118
|
result = await verifyJwt(request, config);
|
|
1886
2119
|
} catch (error) {
|
|
1887
|
-
|
|
2120
|
+
logOperationalError("agent.authentication.failed", error, {
|
|
2121
|
+
agentName: this.constructor.name,
|
|
2122
|
+
agentClass: this.constructor.name,
|
|
2123
|
+
durableObjectName: this.name,
|
|
2124
|
+
attributes: { stage: "jwt-verification" }
|
|
2125
|
+
});
|
|
1888
2126
|
return {
|
|
1889
2127
|
success: false,
|
|
1890
2128
|
status: 401,
|
|
@@ -1896,13 +2134,18 @@ var Assistant = class extends Agent$1 {
|
|
|
1896
2134
|
durableObjectName: this.name,
|
|
1897
2135
|
parentPath: this.parentPath
|
|
1898
2136
|
})) {
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2137
|
+
logOperationalError("agent.authentication.failed", /* @__PURE__ */ new Error("Authenticated actor does not own the requested assistant"), {
|
|
2138
|
+
agentName: this.constructor.name,
|
|
2139
|
+
agentClass: this.constructor.name,
|
|
2140
|
+
durableObjectName: this.name,
|
|
2141
|
+
attributes: {
|
|
2142
|
+
stage: "actor-authorization",
|
|
2143
|
+
authenticatedActorId: config.getActorId(result.claims),
|
|
2144
|
+
requiredActorId: getTargetActorId({
|
|
2145
|
+
durableObjectName: this.name,
|
|
2146
|
+
parentPath: this.parentPath
|
|
2147
|
+
})
|
|
2148
|
+
}
|
|
1906
2149
|
});
|
|
1907
2150
|
return {
|
|
1908
2151
|
success: false,
|
|
@@ -1940,9 +2183,11 @@ var Assistant = class extends Agent$1 {
|
|
|
1940
2183
|
try {
|
|
1941
2184
|
await this.deleteSubAgent(this.agent, id);
|
|
1942
2185
|
} catch (cleanupError) {
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2186
|
+
logOperationalError("assistant.chat.cleanup.failed", cleanupError, {
|
|
2187
|
+
agentName: this.constructor.name,
|
|
2188
|
+
agentClass: this.constructor.name,
|
|
2189
|
+
durableObjectName: this.name,
|
|
2190
|
+
attributes: { chatName: id }
|
|
1946
2191
|
});
|
|
1947
2192
|
}
|
|
1948
2193
|
throw error;
|
|
@@ -1973,16 +2218,20 @@ var Assistant = class extends Agent$1 {
|
|
|
1973
2218
|
touchChat(this.sql.bind(this), durableObjectName);
|
|
1974
2219
|
this.keepAliveWhile(async () => {
|
|
1975
2220
|
await Promise.all([summariseChatWithAI(this.sql.bind(this), durableObjectName, messages, this.fastModel), this.scheduleChatForAutoDeletion(durableObjectName).catch((error) => {
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
2221
|
+
logOperationalError("assistant.chat.reschedule.failed", error, {
|
|
2222
|
+
agentName: this.constructor.name,
|
|
2223
|
+
agentClass: this.constructor.name,
|
|
2224
|
+
durableObjectName: this.name,
|
|
2225
|
+
attributes: { chatName: durableObjectName }
|
|
1979
2226
|
});
|
|
1980
2227
|
})]);
|
|
1981
2228
|
await this.syncChatToGlobalList(durableObjectName);
|
|
1982
2229
|
}).catch((error) => {
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
2230
|
+
logOperationalError("assistant.chat.metadata.failed", error, {
|
|
2231
|
+
agentName: this.constructor.name,
|
|
2232
|
+
agentClass: this.constructor.name,
|
|
2233
|
+
durableObjectName: this.name,
|
|
2234
|
+
attributes: { chatName: durableObjectName }
|
|
1986
2235
|
});
|
|
1987
2236
|
});
|
|
1988
2237
|
}
|
|
@@ -2024,7 +2273,11 @@ var Assistant = class extends Agent$1 {
|
|
|
2024
2273
|
createdAt: Date.now()
|
|
2025
2274
|
});
|
|
2026
2275
|
} catch (error) {
|
|
2027
|
-
|
|
2276
|
+
logOperationalError("agent.registry.registration.failed", error, {
|
|
2277
|
+
agentName: this.constructor.name,
|
|
2278
|
+
agentClass: this.constructor.name,
|
|
2279
|
+
durableObjectName: this.name
|
|
2280
|
+
});
|
|
2028
2281
|
}
|
|
2029
2282
|
}
|
|
2030
2283
|
/**
|
|
@@ -2041,7 +2294,11 @@ var Assistant = class extends Agent$1 {
|
|
|
2041
2294
|
updatedAt
|
|
2042
2295
|
});
|
|
2043
2296
|
} catch (error) {
|
|
2044
|
-
|
|
2297
|
+
logOperationalError("agent.registry.activity.failed", error, {
|
|
2298
|
+
agentName: this.constructor.name,
|
|
2299
|
+
agentClass: this.constructor.name,
|
|
2300
|
+
durableObjectName: this.name
|
|
2301
|
+
});
|
|
2045
2302
|
}
|
|
2046
2303
|
}
|
|
2047
2304
|
async syncChatToGlobalList(durableObjectName) {
|
|
@@ -2443,11 +2700,7 @@ var ChatAgent = class extends Agent {
|
|
|
2443
2700
|
return config;
|
|
2444
2701
|
}
|
|
2445
2702
|
async onChatResponse(result) {
|
|
2446
|
-
|
|
2447
|
-
agentName: this.getTelemetryAgentName(),
|
|
2448
|
-
durableObjectName: this.name,
|
|
2449
|
-
actorId: this.getTelemetryActorId()
|
|
2450
|
-
}, result.requestId, result.status, result.continuation, result.message.parts);
|
|
2703
|
+
this.analytics.turnCompleted(result.requestId, result.status, result.continuation, result.message.parts);
|
|
2451
2704
|
const parent = await this.getParentAgent();
|
|
2452
2705
|
if (parent?.recordChatTurn) await parent.recordChatTurn(this.name, this.messages);
|
|
2453
2706
|
}
|
|
@@ -2519,18 +2772,15 @@ var ChatAgent = class extends Agent {
|
|
|
2519
2772
|
async submitMessageFeedback(messageId, rating, comment) {
|
|
2520
2773
|
const result = submitMessageFeedback(this.sql.bind(this), messageId, rating, comment);
|
|
2521
2774
|
const parent = await this.getParentAgent();
|
|
2522
|
-
|
|
2523
|
-
agentName: this.getTelemetryAgentName(),
|
|
2524
|
-
durableObjectName: this.name,
|
|
2525
|
-
actorId: this.getTelemetryActorId()
|
|
2526
|
-
}, messageId, rating);
|
|
2775
|
+
if (rating === 1 || rating === -1 || rating === 0) this.analytics.feedbackSubmitted(messageId, rating);
|
|
2527
2776
|
if (parent?.recordChatFeedback) try {
|
|
2528
2777
|
await parent.recordChatFeedback(this.name, messageId, rating);
|
|
2529
2778
|
} catch (error) {
|
|
2530
|
-
|
|
2779
|
+
logOperationalError("agent.feedback.summary.failed", error, {
|
|
2780
|
+
agentName: this.getTelemetryAgentName(),
|
|
2781
|
+
agentClass: this.constructor.name,
|
|
2531
2782
|
durableObjectName: this.name,
|
|
2532
|
-
messageId
|
|
2533
|
-
error
|
|
2783
|
+
attributes: { messageId }
|
|
2534
2784
|
});
|
|
2535
2785
|
}
|
|
2536
2786
|
return result;
|
|
@@ -2620,4 +2870,4 @@ function getCurrentToolContext() {
|
|
|
2620
2870
|
return getCurrentAgent().agent._lastBody;
|
|
2621
2871
|
}
|
|
2622
2872
|
//#endregion
|
|
2623
|
-
export { Agent, Assistant, ChatAgent, action, createJwtAuthConfig, exchangeToken, getCurrentToolContext, routeAgentRequest, skill, tool };
|
|
2873
|
+
export { Agent, Assistant, ChatAgent, action, createAnalyticsEngineHandler, createAnalyticsEvent, createJwtAuthConfig, dispatchAnalyticsEvent, exchangeToken, getCurrentToolContext, routeAgentRequest, skill, tool };
|