@economic/agents 2.3.17 → 2.3.19

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/dist/index.d.mts CHANGED
@@ -23,7 +23,7 @@ interface AgentEnv {
23
23
  LOCAL_AGENT_DB?: D1Database;
24
24
  }
25
25
  type SqlFn = InstanceType<typeof Agent$1>["sql"];
26
- type AgentConnectionStatus = "connecting" | "connected" | "disconnected" | "unauthorized";
26
+ type AgentConnectionStatus = "connecting" | "connected" | "disconnected" | "unauthorized" | "error";
27
27
  type AgentConnectionType = "agent" | "chat" | "assistant";
28
28
  //#endregion
29
29
  //#region src/server/util/tools.d.ts
@@ -114,6 +114,17 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
114
114
  * cold start, so registration is not allowed to block the connection.
115
115
  */
116
116
  protected registerInstance(): Promise<void>;
117
+ /**
118
+ * Resolves the analytics/telemetry agent name to the entry-point agent: the
119
+ * top-level DO registered in the `agent` catalog table.
120
+ *
121
+ * `parentPath` is root-first and empty for top-level DOs, so:
122
+ * - chat agent running under an Assistant → the Assistant's class name
123
+ * (e.g. `EvaAssistant`), since the Assistant is the catalog entry point;
124
+ * - standalone chat agent → its own class name (e.g. `EvaAgent`).
125
+ */
126
+ protected getTelemetryAgentName(): string;
127
+ protected getTelemetryActorId(): string;
117
128
  }
118
129
  //#endregion
119
130
  //#region src/server/features/messages.d.ts
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as verifyJwt, n as createAgentTracer, r as extractTokenFromConnectRequest, t as routeAgentRequest } from "./route-agent-request-lVm3eus2.mjs";
1
+ import { a as verifyJwt, i as extractTokenFromConnectRequest, n as createAgentTracer, r as recordFeedbackAnalytics, t as routeAgentRequest } from "./route-agent-request-sspiKVkm.mjs";
2
2
  import { Agent as Agent$1, callable, getCurrentAgent } from "agents";
3
3
  import { Think, skills } from "@cloudflare/think";
4
4
  import { Output, convertToModelMessages, generateText, jsonSchema, pruneMessages, tool as tool$1 } from "ai";
@@ -195,17 +195,17 @@ var Agent = class extends Think {
195
195
  experimental_telemetry: {
196
196
  isEnabled: true,
197
197
  tracer: createAgentTracer(this.env.AGENTS_AUDIT_LOGS, this.env.AGENTS_ANALYTICS, {
198
- agentName: this.constructor.name,
198
+ agentName: this.getTelemetryAgentName(),
199
199
  durableObjectName: this.name,
200
- actorId: this.getActorIdFromDurableObjectName(),
200
+ actorId: this.getTelemetryActorId(),
201
201
  clientIp: this.clientIp,
202
202
  forwardedFor: this.forwardedFor
203
203
  }),
204
204
  metadata: {
205
- agentName: this.constructor.name,
205
+ agentName: this.getTelemetryAgentName(),
206
206
  version: "v2",
207
207
  durableObjectName: this.name,
208
- actorId: this.getActorIdFromDurableObjectName()
208
+ actorId: this.getTelemetryActorId()
209
209
  }
210
210
  }
211
211
  };
@@ -312,6 +312,21 @@ var Agent = class extends Think {
312
312
  console.error("[Agent] Failed to register in agent_registry", error);
313
313
  }
314
314
  }
315
+ /**
316
+ * Resolves the analytics/telemetry agent name to the entry-point agent: the
317
+ * top-level DO registered in the `agent` catalog table.
318
+ *
319
+ * `parentPath` is root-first and empty for top-level DOs, so:
320
+ * - chat agent running under an Assistant → the Assistant's class name
321
+ * (e.g. `EvaAssistant`), since the Assistant is the catalog entry point;
322
+ * - standalone chat agent → its own class name (e.g. `EvaAgent`).
323
+ */
324
+ getTelemetryAgentName() {
325
+ return this.parentPath[0]?.className ?? this.constructor.name;
326
+ }
327
+ getTelemetryActorId() {
328
+ return this.parentPath[0]?.name ?? this.getActorIdFromDurableObjectName();
329
+ }
315
330
  };
316
331
  //#endregion
317
332
  //#region src/server/features/chats.ts
@@ -1012,7 +1027,13 @@ var ChatAgent = class extends Agent {
1012
1027
  * @returns The message id and the rating.
1013
1028
  */
1014
1029
  async submitMessageFeedback(messageId, rating, comment) {
1015
- return submitMessageFeedback(this.sql.bind(this), messageId, rating, comment);
1030
+ const result = submitMessageFeedback(this.sql.bind(this), messageId, rating, comment);
1031
+ recordFeedbackAnalytics(this.env.AGENTS_ANALYTICS, {
1032
+ agentName: this.getTelemetryAgentName(),
1033
+ durableObjectName: this.name,
1034
+ actorId: this.getTelemetryActorId()
1035
+ }, messageId, rating);
1036
+ return result;
1016
1037
  }
1017
1038
  /**
1018
1039
  * Returns all message feedback for the current chat.
@@ -101,6 +101,27 @@ async function verifyJwt(request, config) {
101
101
  };
102
102
  }
103
103
  //#endregion
104
+ //#region src/server/features/telemetry/skills.ts
105
+ /**
106
+ * Extracts the skill names loaded by an `activate_skill` tool call.
107
+ *
108
+ * v2 `activate_skill` input is `{ skills: string[] }` — a single call can load
109
+ * multiple skills, so this returns every requested skill name.
110
+ */
111
+ function extractSkillNames(toolName, input) {
112
+ if (toolName !== "activate_skill" || !input || typeof input !== "object") return [];
113
+ const { skills } = input;
114
+ if (!Array.isArray(skills)) return [];
115
+ return skills.filter((skill) => typeof skill === "string");
116
+ }
117
+ /**
118
+ * Single-skill variant used where one representative skill name is sufficient
119
+ * (e.g. audit-log attribution and current-skill tracking).
120
+ */
121
+ function extractSkillName(toolName, input) {
122
+ return extractSkillNames(toolName, input)[0];
123
+ }
124
+ //#endregion
104
125
  //#region src/server/features/telemetry/utils.ts
105
126
  function durationMs(duration) {
106
127
  return duration[0] * 1e3 + duration[1] / 1e6;
@@ -169,18 +190,6 @@ function extractTools(messages) {
169
190
  }
170
191
  return tools;
171
192
  }
172
- function extractSkillName(toolName, input) {
173
- if (!input || typeof input !== "object") return;
174
- const record = input;
175
- if (toolName === "load_context") {
176
- const key = record.key;
177
- return typeof key === "string" ? key : void 0;
178
- }
179
- if (toolName === "activate_skill") {
180
- const skill = record.skill ?? record.name ?? record.key;
181
- return typeof skill === "string" ? skill : void 0;
182
- }
183
- }
184
193
  function pushToolCall(map, key, toolCall) {
185
194
  const existing = map.get(key);
186
195
  if (existing) existing.push(toolCall);
@@ -276,16 +285,35 @@ function writeAnalyticsDatapoint(analytics, dataPoint) {
276
285
  console.error("[Agent] Failed to write analytics datapoint", error);
277
286
  }
278
287
  }
279
- function handleAnalyticsSpan(span, analytics) {
288
+ /**
289
+ * Writes a message-feedback rating to Analytics Engine so sentiment can be
290
+ * aggregated across all chats without fanning out to every chat DO.
291
+ *
292
+ * Emitted on every rating change; the dashboard takes the latest rating per
293
+ * `messageId` (blob4) so re-rates and clears are idempotent.
294
+ */
295
+ function recordFeedbackAnalytics(analytics, context, messageId, rating) {
296
+ writeAnalyticsDatapoint(analytics, {
297
+ indexes: [context.actorId],
298
+ blobs: [
299
+ "feedback",
300
+ context.agentName,
301
+ context.durableObjectName,
302
+ messageId
303
+ ],
304
+ doubles: [rating]
305
+ });
306
+ }
307
+ function handleAnalyticsSpan(span, analytics, context) {
280
308
  if (span.name === "ai.streamText.doStream") {
281
309
  const promptMessages = parseJson(stringAttribute(span, "ai.prompt.messages"));
282
310
  const responseText = stringAttribute(span, "ai.response.text") ?? "";
283
311
  writeAnalyticsDatapoint(analytics, {
284
- indexes: [stringAttribute(span, "ai.telemetry.metadata.actorId") ?? ""],
312
+ indexes: [context.actorId],
285
313
  blobs: [
286
314
  "llm_call",
287
- stringAttribute(span, "ai.telemetry.metadata.agentName") ?? "",
288
- stringAttribute(span, "ai.telemetry.metadata.durableObjectName") ?? "",
315
+ context.agentName,
316
+ context.durableObjectName,
289
317
  stringAttribute(span, "ai.model.id") ?? "",
290
318
  stringAttribute(span, "ai.model.provider") ?? "",
291
319
  stringAttribute(span, "ai.response.finishReason") ?? ""
@@ -305,25 +333,29 @@ function handleAnalyticsSpan(span, analytics) {
305
333
  }
306
334
  if (span.name === "ai.toolCall") {
307
335
  const toolName = stringAttribute(span, "ai.toolCall.name");
308
- const toolInput = parseJson(stringAttribute(span, "ai.toolCall.args"));
309
- const durableObjectName = stringAttribute(span, "ai.telemetry.metadata.durableObjectName") ?? "";
310
- const skillName = extractSkillName(toolName, toolInput) ?? currentSkillByChat.get(durableObjectName) ?? "";
336
+ const argsRaw = stringAttribute(span, "ai.toolCall.args");
337
+ const toolInput = parseJson(argsRaw);
311
338
  const success = span.status.code === 0;
312
- writeAnalyticsDatapoint(analytics, {
313
- indexes: [stringAttribute(span, "ai.telemetry.metadata.actorId") ?? ""],
339
+ const duration = durationMs(span.duration);
340
+ const argsSize = argsRaw?.length ?? 0;
341
+ const resultSize = stringAttribute(span, "ai.toolCall.result")?.length ?? 0;
342
+ const activatedSkills = extractSkillNames(toolName, toolInput);
343
+ const skillNames = activatedSkills.length ? activatedSkills : [currentSkillByChat.get(context.durableObjectName) ?? ""];
344
+ for (const skillName of skillNames) writeAnalyticsDatapoint(analytics, {
345
+ indexes: [context.actorId],
314
346
  blobs: [
315
347
  "tool_call",
316
- stringAttribute(span, "ai.telemetry.metadata.agentName") ?? "",
317
- durableObjectName,
348
+ context.agentName,
349
+ context.durableObjectName,
318
350
  toolName ?? "",
319
351
  skillName,
320
352
  success ? "success" : "error"
321
353
  ],
322
354
  doubles: [
323
- durationMs(span.duration),
355
+ duration,
324
356
  success ? 1 : 0,
325
- 0,
326
- 0,
357
+ argsSize,
358
+ resultSize,
327
359
  0,
328
360
  0,
329
361
  0,
@@ -349,11 +381,11 @@ var AgentSpanExporter = class {
349
381
  for (const span of spans) if (span.name === "ai.streamText.doStream") {
350
382
  rememberDoStream(span, this.context.durableObjectName);
351
383
  attachToolCallsToChat(span, this.context.durableObjectName);
352
- handleAnalyticsSpan(span, this.analytics);
384
+ handleAnalyticsSpan(span, this.analytics, this.context);
353
385
  } else if (span.name === "ai.streamText") await handleAuditSpan(span, this.auditLogs, this.context);
354
386
  else if (span.name === "ai.toolCall") {
355
387
  rememberToolCall(span);
356
- handleAnalyticsSpan(span, this.analytics);
388
+ handleAnalyticsSpan(span, this.analytics, this.context);
357
389
  }
358
390
  resultCallback({ code: 0 });
359
391
  } catch (error) {
@@ -383,4 +415,4 @@ async function routeAgentRequest$1(request, env, options) {
383
415
  return response;
384
416
  }
385
417
  //#endregion
386
- export { verifyJwt as i, createAgentTracer as n, extractTokenFromConnectRequest as r, routeAgentRequest$1 as t };
418
+ export { verifyJwt as a, extractTokenFromConnectRequest as i, createAgentTracer as n, recordFeedbackAnalytics as r, routeAgentRequest$1 as t };
package/dist/v1.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as verifyJwt, n as createAgentTracer, r as extractTokenFromConnectRequest, t as routeAgentRequest } from "./route-agent-request-lVm3eus2.mjs";
1
+ import { a as verifyJwt, i as extractTokenFromConnectRequest, n as createAgentTracer, t as routeAgentRequest } from "./route-agent-request-sspiKVkm.mjs";
2
2
  import { Agent as Agent$1, callable, getCurrentAgent } from "agents";
3
3
  import { Output, convertToModelMessages, generateText, jsonSchema, stepCountIs, streamText, tool } from "ai";
4
4
  import { AIChatAgent } from "@cloudflare/ai-chat";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@economic/agents",
3
- "version": "2.3.17",
3
+ "version": "2.3.19",
4
4
  "description": "A starter for creating a TypeScript package.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -26,9 +26,9 @@
26
26
  "@ai-sdk/anthropic": "^3.0.77",
27
27
  "@ai-sdk/google": "^3.0.73",
28
28
  "@cloudflare/ai-chat": "^0.8.5",
29
- "@cloudflare/think": "^0.9.0",
30
- "@opentelemetry/sdk-trace-base": "^2.7.1",
31
- "agents": "^0.16.0",
29
+ "@cloudflare/think": ">=0.9.0",
30
+ "@opentelemetry/sdk-trace-base": "^2.8.0",
31
+ "agents": ">=0.16.0 <1.0.0",
32
32
  "ai": "^6.0.197",
33
33
  "jose": "^6.2.3",
34
34
  "nanoid": "^5.1.11"
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@cloudflare/think": ">=0.9.0",
49
- "@cloudflare/vite-plugin": ">=1.40.2",
49
+ "@cloudflare/vite-plugin": "^1.42.0",
50
50
  "@cloudflare/worker-bundler": ">=0.2.1",
51
51
  "agents": ">=0.16.0 <1.0.0",
52
52
  "vite": ">=8.0.0"