@economic/agents 2.3.19 → 2.3.21
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
|
@@ -114,6 +114,21 @@ 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
|
+
* The `(agent_name, durable_object_name)` key of the registered row for this
|
|
119
|
+
* DO. For a parented (facet) agent this resolves to the top-level parent's
|
|
120
|
+
* row, since facets are not registered themselves.
|
|
121
|
+
*/
|
|
122
|
+
protected getRegisteredInstanceKey(): {
|
|
123
|
+
agentName: string;
|
|
124
|
+
durableObjectName: string;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Records activity against this DO's registered row by advancing its
|
|
128
|
+
* `updated_at`, so instances can be ordered by recency of activity.
|
|
129
|
+
* Best-effort and non-blocking — never allowed to interfere with a turn.
|
|
130
|
+
*/
|
|
131
|
+
protected touchInstance(): Promise<void>;
|
|
117
132
|
/**
|
|
118
133
|
* Resolves the analytics/telemetry agent name to the entry-point agent: the
|
|
119
134
|
* top-level DO registered in the `agent` catalog table.
|
|
@@ -249,6 +264,13 @@ declare abstract class Assistant<State = unknown> extends Agent$1<Cloudflare.Env
|
|
|
249
264
|
* Best-effort and idempotent: no-ops on conflict, retried on the next start.
|
|
250
265
|
*/
|
|
251
266
|
private registerInstance;
|
|
267
|
+
/**
|
|
268
|
+
* Records activity against this Assistant's registry row by advancing its
|
|
269
|
+
* `updated_at`, so instances can be ordered by recency of activity. An
|
|
270
|
+
* Assistant is a top-level DO, so its row is keyed by its own class + name.
|
|
271
|
+
* Best-effort and non-blocking.
|
|
272
|
+
*/
|
|
273
|
+
private touchInstance;
|
|
252
274
|
/**
|
|
253
275
|
* Binding of the legacy v1 chat Durable Object class, used to migrate a
|
|
254
276
|
* user's v1 chats into facets the first time they connect. Set this on the
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as verifyJwt, i as extractTokenFromConnectRequest, n as createAgentTracer, r as recordFeedbackAnalytics, t as routeAgentRequest } from "./route-agent-request-
|
|
1
|
+
import { a as verifyJwt, i as extractTokenFromConnectRequest, n as createAgentTracer, r as recordFeedbackAnalytics, t as routeAgentRequest } from "./route-agent-request-GWXHyI2L.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";
|
|
@@ -28,12 +28,31 @@ const TURN_PROTOCOL_RULES_PROMPT = `These rules are specific for responding to u
|
|
|
28
28
|
* Registers a top-level DO in the global registry.
|
|
29
29
|
*
|
|
30
30
|
* Idempotent: keyed on `(agent_name, durable_object_name)`, so repeated calls
|
|
31
|
-
* across cold starts no-op and
|
|
31
|
+
* across cold starts no-op and timestamps reflect the first registration.
|
|
32
|
+
* `updated_at` is seeded to `created_at`; ongoing activity is recorded
|
|
33
|
+
* separately via {@link touchAgentInstance} so cold-start re-registration
|
|
34
|
+
* never inflates the activity timestamp.
|
|
32
35
|
*/
|
|
33
36
|
async function registerAgentInstance(db, input) {
|
|
34
|
-
await db.prepare(`INSERT INTO agent_registry (agent_name, durable_object_name, actor_id, created_at)
|
|
35
|
-
VALUES (?, ?, ?, ?)
|
|
36
|
-
ON CONFLICT (agent_name, durable_object_name) DO NOTHING`).bind(input.agentName, input.durableObjectName, input.actorId, input.createdAt).run();
|
|
37
|
+
await db.prepare(`INSERT INTO agent_registry (agent_name, durable_object_name, actor_id, created_at, updated_at)
|
|
38
|
+
VALUES (?, ?, ?, ?, ?)
|
|
39
|
+
ON CONFLICT (agent_name, durable_object_name) DO NOTHING`).bind(input.agentName, input.durableObjectName, input.actorId, input.createdAt, input.createdAt).run();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Records activity on a registered top-level DO by advancing its `updated_at`.
|
|
43
|
+
*
|
|
44
|
+
* Used to order instances by recency of activity. Keyed on
|
|
45
|
+
* `(agent_name, durable_object_name)` to target the exact registered row —
|
|
46
|
+
* for a parented (facet) agent this is the top-level parent's row, since
|
|
47
|
+
* facets are not registered themselves.
|
|
48
|
+
*
|
|
49
|
+
* Best-effort: a no-op if the row does not yet exist (registration is
|
|
50
|
+
* retried on the next cold start).
|
|
51
|
+
*/
|
|
52
|
+
async function touchAgentInstance(db, input) {
|
|
53
|
+
await db.prepare(`UPDATE agent_registry
|
|
54
|
+
SET updated_at = ?
|
|
55
|
+
WHERE agent_name = ? AND durable_object_name = ?`).bind(input.updatedAt, input.agentName, input.durableObjectName).run();
|
|
37
56
|
}
|
|
38
57
|
//#endregion
|
|
39
58
|
//#region src/server/util/agent.ts
|
|
@@ -172,6 +191,7 @@ var Agent = class extends Think {
|
|
|
172
191
|
* `returned.tools` into your own `TurnConfig.tools` if you return tools.
|
|
173
192
|
*/
|
|
174
193
|
async beforeTurn(ctx) {
|
|
194
|
+
this.touchInstance();
|
|
175
195
|
this._toolContextForCurrentTurn = this.getToolContextForCurrentTurn(ctx.body);
|
|
176
196
|
this._toolsForCurrentTurn = ctx.tools;
|
|
177
197
|
const activeSkillName = this._getLastActivatedSkillName(ctx.messages);
|
|
@@ -313,6 +333,32 @@ var Agent = class extends Think {
|
|
|
313
333
|
}
|
|
314
334
|
}
|
|
315
335
|
/**
|
|
336
|
+
* The `(agent_name, durable_object_name)` key of the registered row for this
|
|
337
|
+
* DO. For a parented (facet) agent this resolves to the top-level parent's
|
|
338
|
+
* row, since facets are not registered themselves.
|
|
339
|
+
*/
|
|
340
|
+
getRegisteredInstanceKey() {
|
|
341
|
+
return {
|
|
342
|
+
agentName: this.parentPath[0]?.className ?? this.constructor.name,
|
|
343
|
+
durableObjectName: this.parentPath[0]?.name ?? this.name
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Records activity against this DO's registered row by advancing its
|
|
348
|
+
* `updated_at`, so instances can be ordered by recency of activity.
|
|
349
|
+
* Best-effort and non-blocking — never allowed to interfere with a turn.
|
|
350
|
+
*/
|
|
351
|
+
async touchInstance() {
|
|
352
|
+
try {
|
|
353
|
+
await touchAgentInstance(this.env.AGENTS_DB, {
|
|
354
|
+
...this.getRegisteredInstanceKey(),
|
|
355
|
+
updatedAt: Date.now()
|
|
356
|
+
});
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error("[Agent] Failed to update agent_registry activity", error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
316
362
|
* Resolves the analytics/telemetry agent name to the entry-point agent: the
|
|
317
363
|
* top-level DO registered in the `agent` catalog table.
|
|
318
364
|
*
|
|
@@ -718,6 +764,7 @@ var Assistant = class extends Agent$1 {
|
|
|
718
764
|
const now = Date.now();
|
|
719
765
|
await this.subAgent(this.agent, id);
|
|
720
766
|
registerChat(this.sql.bind(this), id, now);
|
|
767
|
+
this.touchInstance(now);
|
|
721
768
|
return id;
|
|
722
769
|
}
|
|
723
770
|
async deleteChat(id) {
|
|
@@ -762,6 +809,23 @@ var Assistant = class extends Agent$1 {
|
|
|
762
809
|
}
|
|
763
810
|
}
|
|
764
811
|
/**
|
|
812
|
+
* Records activity against this Assistant's registry row by advancing its
|
|
813
|
+
* `updated_at`, so instances can be ordered by recency of activity. An
|
|
814
|
+
* Assistant is a top-level DO, so its row is keyed by its own class + name.
|
|
815
|
+
* Best-effort and non-blocking.
|
|
816
|
+
*/
|
|
817
|
+
async touchInstance(updatedAt) {
|
|
818
|
+
try {
|
|
819
|
+
await touchAgentInstance(this.env.AGENTS_DB, {
|
|
820
|
+
agentName: this.constructor.name,
|
|
821
|
+
durableObjectName: this.name,
|
|
822
|
+
updatedAt
|
|
823
|
+
});
|
|
824
|
+
} catch (error) {
|
|
825
|
+
console.error("[Assistant] Failed to update agent_registry activity", error);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
765
829
|
* Binding of the legacy v1 chat Durable Object class, used to migrate a
|
|
766
830
|
* user's v1 chats into facets the first time they connect. Set this on the
|
|
767
831
|
* concrete subclass to enable lazy v1 -> v2 migration; leave undefined to
|
|
@@ -277,6 +277,15 @@ async function handleAuditSpan(span, auditLogs, context) {
|
|
|
277
277
|
}
|
|
278
278
|
//#endregion
|
|
279
279
|
//#region src/server/features/telemetry/analytics.ts
|
|
280
|
+
const emittedToolCallIds = /* @__PURE__ */ new Set();
|
|
281
|
+
function safeJsonString(value) {
|
|
282
|
+
if (value === void 0) return void 0;
|
|
283
|
+
try {
|
|
284
|
+
return JSON.stringify(value);
|
|
285
|
+
} catch {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
280
289
|
function writeAnalyticsDatapoint(analytics, dataPoint) {
|
|
281
290
|
if (!analytics) return;
|
|
282
291
|
try {
|
|
@@ -308,6 +317,7 @@ function handleAnalyticsSpan(span, analytics, context) {
|
|
|
308
317
|
if (span.name === "ai.streamText.doStream") {
|
|
309
318
|
const promptMessages = parseJson(stringAttribute(span, "ai.prompt.messages"));
|
|
310
319
|
const responseText = stringAttribute(span, "ai.response.text") ?? "";
|
|
320
|
+
const responseToolCalls = parseJson(stringAttribute(span, "ai.response.toolCalls"));
|
|
311
321
|
writeAnalyticsDatapoint(analytics, {
|
|
312
322
|
indexes: [context.actorId],
|
|
313
323
|
blobs: [
|
|
@@ -329,10 +339,48 @@ function handleAnalyticsSpan(span, analytics, context) {
|
|
|
329
339
|
responseText.length
|
|
330
340
|
]
|
|
331
341
|
});
|
|
342
|
+
if (Array.isArray(responseToolCalls)) for (const value of responseToolCalls) {
|
|
343
|
+
if (!value || typeof value !== "object") continue;
|
|
344
|
+
const toolCall = value;
|
|
345
|
+
const toolCallId = typeof toolCall.toolCallId === "string" ? toolCall.toolCallId : void 0;
|
|
346
|
+
if (toolCallId && emittedToolCallIds.has(toolCallId)) continue;
|
|
347
|
+
const toolName = typeof toolCall.toolName === "string" ? toolCall.toolName : void 0;
|
|
348
|
+
if (!toolName) continue;
|
|
349
|
+
const input = toolCall.input;
|
|
350
|
+
const argsRaw = safeJsonString(input);
|
|
351
|
+
const success = span.status.code === 0;
|
|
352
|
+
const activatedSkills = extractSkillNames(toolName, input);
|
|
353
|
+
const skillNames = activatedSkills.length ? activatedSkills : [currentSkillByChat.get(context.durableObjectName) ?? ""];
|
|
354
|
+
if (toolCallId) emittedToolCallIds.add(toolCallId);
|
|
355
|
+
for (const skillName of skillNames) writeAnalyticsDatapoint(analytics, {
|
|
356
|
+
indexes: [context.actorId],
|
|
357
|
+
blobs: [
|
|
358
|
+
"tool_call",
|
|
359
|
+
context.agentName,
|
|
360
|
+
context.durableObjectName,
|
|
361
|
+
toolName,
|
|
362
|
+
skillName,
|
|
363
|
+
success ? "success" : "error"
|
|
364
|
+
],
|
|
365
|
+
doubles: [
|
|
366
|
+
0,
|
|
367
|
+
success ? 1 : 0,
|
|
368
|
+
argsRaw?.length ?? 0,
|
|
369
|
+
0,
|
|
370
|
+
0,
|
|
371
|
+
0,
|
|
372
|
+
0,
|
|
373
|
+
0
|
|
374
|
+
]
|
|
375
|
+
});
|
|
376
|
+
}
|
|
332
377
|
return;
|
|
333
378
|
}
|
|
334
379
|
if (span.name === "ai.toolCall") {
|
|
335
380
|
const toolName = stringAttribute(span, "ai.toolCall.name");
|
|
381
|
+
const toolCallId = stringAttribute(span, "ai.toolCall.id");
|
|
382
|
+
if (toolCallId && emittedToolCallIds.has(toolCallId)) return;
|
|
383
|
+
if (toolCallId) emittedToolCallIds.add(toolCallId);
|
|
336
384
|
const argsRaw = stringAttribute(span, "ai.toolCall.args");
|
|
337
385
|
const toolInput = parseJson(argsRaw);
|
|
338
386
|
const success = span.status.code === 0;
|
package/dist/v1.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as verifyJwt, i as extractTokenFromConnectRequest, n as createAgentTracer, t as routeAgentRequest } from "./route-agent-request-
|
|
1
|
+
import { a as verifyJwt, i as extractTokenFromConnectRequest, n as createAgentTracer, t as routeAgentRequest } from "./route-agent-request-GWXHyI2L.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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- ─── agent_registry.updated_at ────────────────────────────────────────────────────
|
|
2
|
+
-- Adds an activity timestamp to the registry so top-level DOs (one row per
|
|
3
|
+
-- Assistant, i.e. per user) can be ordered by recency of activity. Bumped by
|
|
4
|
+
-- the owning DO whenever a chat is created or has a turn.
|
|
5
|
+
--
|
|
6
|
+
-- Existing rows are backfilled to created_at so ordering remains sensible
|
|
7
|
+
-- before any new activity updates the column.
|
|
8
|
+
|
|
9
|
+
ALTER TABLE agent_registry ADD COLUMN updated_at INTEGER;
|
|
10
|
+
|
|
11
|
+
UPDATE agent_registry SET updated_at = created_at WHERE updated_at IS NULL;
|
|
12
|
+
|
|
13
|
+
CREATE INDEX IF NOT EXISTS agent_registry_updated ON agent_registry(updated_at);
|