@economic/agents 1.6.2 → 1.6.3

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
@@ -1,7 +1,7 @@
1
1
  import { LanguageModel, StreamTextOnFinishCallback, ToolSet, UIMessage, generateText, streamText } from "ai";
2
2
  import { Agent as Agent$1, AgentOptions, Connection, ConnectionContext } from "agents";
3
- import { JWTPayload } from "jose";
4
3
  import { AIChatAgent, ChatResponseResult, OnChatMessageOptions } from "@cloudflare/ai-chat";
4
+ import { JWTPayload } from "jose";
5
5
 
6
6
  //#region src/server/shared/features/skills/index.d.ts
7
7
  /**
@@ -83,7 +83,6 @@ interface JwtAuthConfig<TClaims extends Record<string, unknown> = Record<string,
83
83
  */
84
84
  getClaims: (payload: JWTPayload) => TClaims;
85
85
  }
86
- declare function extractTokenFromConnectRequest(request: Request): string | null;
87
86
  //#endregion
88
87
  //#region src/server/agent/Agent.d.ts
89
88
  /**
@@ -153,7 +152,7 @@ interface MessageRating {
153
152
  * Skill loading, compaction, and LLM calls use `buildLLMParams` from
154
153
  * `@economic/agents` inside `onChatMessage`.
155
154
  */
156
- declare abstract class ChatAgent<Env extends Cloudflare.Env = Cloudflare.Env> extends AIChatAgent<Env & ChatAgentEnv> {
155
+ declare abstract class ChatAgent<Env extends Cloudflare.Env = Cloudflare.Env, TSessionIdentity extends Record<string, unknown> = Record<string, unknown>> extends AIChatAgent<Env & ChatAgentEnv> {
157
156
  /**
158
157
  * The binding of the Durable Object instance for this agent.
159
158
  */
@@ -202,6 +201,17 @@ declare abstract class ChatAgent<Env extends Cloudflare.Env = Cloudflare.Env> ex
202
201
  * @returns JWT auth config or undefined to skip authentication
203
202
  */
204
203
  protected getJwtAuthConfig?(request: Request): JwtAuthConfig<Record<string, unknown>> | undefined;
204
+ /**
205
+ * The identity associated with the session.
206
+ * Define getIdentity to return the identity from the request.
207
+ */
208
+ protected identity: TSessionIdentity;
209
+ /**
210
+ * Returns the identity from the request.
211
+ * @returns The identity from the request.
212
+ * @param token - The token from the request.
213
+ */
214
+ protected getIdentity(_token: string): Promise<TSessionIdentity>;
205
215
  /**
206
216
  * Returns the user ID from the durable object name.
207
217
  */
@@ -244,7 +254,7 @@ declare abstract class ChatAgent<Env extends Cloudflare.Env = Cloudflare.Env> ex
244
254
  }
245
255
  //#endregion
246
256
  //#region src/server/agent-chat/ChatAgentHarness.d.ts
247
- declare abstract class ChatAgentHarness<Env extends Cloudflare.Env, RequestBody extends Record<string, unknown> = Record<string, unknown>> extends ChatAgent<Env> {
257
+ declare abstract class ChatAgentHarness<Env extends Cloudflare.Env, RequestBody extends Record<string, unknown> = Record<string, unknown>, SessionIdentity extends Record<string, unknown> = Record<string, unknown>> extends ChatAgent<Env, SessionIdentity> {
248
258
  get binding(): {
249
259
  getByName(name: string): {
250
260
  destroy(): Promise<void>;
@@ -278,4 +288,4 @@ declare abstract class ChatAgentHarness<Env extends Cloudflare.Env, RequestBody
278
288
  onChatMessage(onFinish: StreamTextOnFinishCallback<ToolSet>, options?: OnChatMessageOptions): Promise<Response>;
279
289
  }
280
290
  //#endregion
281
- export { Agent, type AgentToolContext, type BuildLLMParamsConfig, ChatAgent, ChatAgentHarness, type Skill, buildLLMParams, extractTokenFromConnectRequest, routeAgentRequest };
291
+ export { Agent, type AgentToolContext, type BuildLLMParamsConfig, ChatAgent, ChatAgentHarness, type Skill, buildLLMParams, routeAgentRequest };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Output, convertToModelMessages, generateText, jsonSchema, stepCountIs, streamText, tool } from "ai";
2
2
  import { Agent as Agent$1, callable, routeAgentRequest as routeAgentRequest$1 } from "agents";
3
- import { createRemoteJWKSet, decodeJwt, errors, jwtVerify } from "jose";
4
3
  import { AIChatAgent } from "@cloudflare/ai-chat";
4
+ import { createRemoteJWKSet, decodeJwt, errors, jwtVerify } from "jose";
5
5
  //#region src/server/shared/features/skills/index.ts
6
6
  const TOOL_NAME_ACTIVATE_SKILL = "activate_skill";
7
7
  const TOOL_NAME_LIST_CAPABILITIES = "list_capabilities";
@@ -269,6 +269,98 @@ async function routeAgentRequest(request, env, options) {
269
269
  return response;
270
270
  }
271
271
  //#endregion
272
+ //#region src/server/shared/features/audit/audit.ts
273
+ /**
274
+ * Inserts a single audit event row into the shared `audit_events` D1 table.
275
+ *
276
+ * Called by `ChatAgentHarness.logEvent()` (and `AgentHarness.logEvent()`). Not intended for direct use.
277
+ */
278
+ const SENSITIVE_KEYS = /^(password|token|secret|api_key|apikey|authorization|credentials)$/i;
279
+ const REDACTED = "[REDACTED]";
280
+ /** Deep-clone and redact values for keys that look like secrets (for audit logging). */
281
+ function sanitizePayload(value) {
282
+ if (value === null || value === void 0) return value;
283
+ if (Array.isArray(value)) return value.map(sanitizePayload);
284
+ if (typeof value === "object") {
285
+ const result = {};
286
+ for (const [key, val] of Object.entries(value)) result[key] = SENSITIVE_KEYS.test(key) ? REDACTED : sanitizePayload(val);
287
+ return result;
288
+ }
289
+ return value;
290
+ }
291
+ async function insertAuditEvent(db, durableObjectName, message, payload) {
292
+ await db.prepare(`INSERT INTO audit_events (id, durable_object_name, message, payload, created_at)
293
+ VALUES (?, ?, ?, ?, ?)`).bind(crypto.randomUUID(), durableObjectName, message, payload ? JSON.stringify(sanitizePayload(payload)) : null, (/* @__PURE__ */ new Date()).toISOString()).run();
294
+ }
295
+ function stringifyForSkillScan(output) {
296
+ if (typeof output === "string") return output;
297
+ if (output === null || output === void 0) return "";
298
+ try {
299
+ return JSON.stringify(output);
300
+ } catch {
301
+ return "";
302
+ }
303
+ }
304
+ function forEachStep(event, fn) {
305
+ if (event.steps.length > 0) for (const step of event.steps) fn(step);
306
+ else fn(event);
307
+ }
308
+ /**
309
+ * User text from provider request body (`contents` is e.g. Gemini format).
310
+ */
311
+ function extractUserInputFromRequestBody(body) {
312
+ const firstContent = body?.contents?.[0];
313
+ if (firstContent?.role !== "user" || !firstContent.parts?.length) return "";
314
+ return firstContent.parts.map((p) => p.text).filter((t) => typeof t === "string").join(" ").trim();
315
+ }
316
+ /**
317
+ * Builds the payload for a "Turn completed" audit event from the AI SDK
318
+ * `OnFinishEvent`.
319
+ *
320
+ * Returns:
321
+ * - `input`: user message text from `request.body.contents[0]` (Gemini-style)
322
+ * - `output`: assistant response text (truncated to 200 chars)
323
+ * - `toolCalls`: array of { toolName, toolInput, toolOutput }
324
+ * - `loadedSkills`: skill names extracted from activate_skill results
325
+ */
326
+ function buildTurnLogPayload(event) {
327
+ const toolCalls = [];
328
+ let latestSkills;
329
+ const toolOutputs = /* @__PURE__ */ new Map();
330
+ forEachStep(event, (step) => {
331
+ for (const tr of step.toolResults) toolOutputs.set(tr.toolCallId, tr.output);
332
+ });
333
+ forEachStep(event, (step) => {
334
+ for (const tc of step.toolCalls) toolCalls.push({
335
+ name: tc.toolName,
336
+ input: tc.input,
337
+ output: toolOutputs.get(tc.toolCallId)
338
+ });
339
+ const considerToolResultForSkills = (toolName, output) => {
340
+ if (toolName !== "activate_skill") return;
341
+ const s = stringifyForSkillScan(output);
342
+ const sentinelIdx = s.indexOf(SKILL_STATE_SENTINEL);
343
+ if (sentinelIdx === -1) return;
344
+ try {
345
+ const stateJson = s.slice(sentinelIdx + 18);
346
+ latestSkills = JSON.parse(stateJson);
347
+ } catch {}
348
+ };
349
+ for (const tr of step.toolResults) considerToolResultForSkills(tr.toolName, tr.output);
350
+ });
351
+ const input = extractUserInputFromRequestBody(event.request?.body);
352
+ return {
353
+ detail: {
354
+ model: event.model.modelId,
355
+ tokens: event.usage?.totalTokens
356
+ },
357
+ loadedSkills: latestSkills ?? [],
358
+ toolCalls,
359
+ input: input.slice(0, 200),
360
+ output: (event.text ?? "").slice(0, 200)
361
+ };
362
+ }
363
+ //#endregion
272
364
  //#region src/server/shared/features/auth/index.ts
273
365
  const jwksByIssuer = /* @__PURE__ */ new Map();
274
366
  function getJwksForIssuer(issuer) {
@@ -369,98 +461,6 @@ async function verifyJwt(request, config) {
369
461
  };
370
462
  }
371
463
  //#endregion
372
- //#region src/server/shared/features/audit/audit.ts
373
- /**
374
- * Inserts a single audit event row into the shared `audit_events` D1 table.
375
- *
376
- * Called by `ChatAgentHarness.logEvent()` (and `AgentHarness.logEvent()`). Not intended for direct use.
377
- */
378
- const SENSITIVE_KEYS = /^(password|token|secret|api_key|apikey|authorization|credentials)$/i;
379
- const REDACTED = "[REDACTED]";
380
- /** Deep-clone and redact values for keys that look like secrets (for audit logging). */
381
- function sanitizePayload(value) {
382
- if (value === null || value === void 0) return value;
383
- if (Array.isArray(value)) return value.map(sanitizePayload);
384
- if (typeof value === "object") {
385
- const result = {};
386
- for (const [key, val] of Object.entries(value)) result[key] = SENSITIVE_KEYS.test(key) ? REDACTED : sanitizePayload(val);
387
- return result;
388
- }
389
- return value;
390
- }
391
- async function insertAuditEvent(db, durableObjectName, message, payload) {
392
- await db.prepare(`INSERT INTO audit_events (id, durable_object_name, message, payload, created_at)
393
- VALUES (?, ?, ?, ?, ?)`).bind(crypto.randomUUID(), durableObjectName, message, payload ? JSON.stringify(sanitizePayload(payload)) : null, (/* @__PURE__ */ new Date()).toISOString()).run();
394
- }
395
- function stringifyForSkillScan(output) {
396
- if (typeof output === "string") return output;
397
- if (output === null || output === void 0) return "";
398
- try {
399
- return JSON.stringify(output);
400
- } catch {
401
- return "";
402
- }
403
- }
404
- function forEachStep(event, fn) {
405
- if (event.steps.length > 0) for (const step of event.steps) fn(step);
406
- else fn(event);
407
- }
408
- /**
409
- * User text from provider request body (`contents` is e.g. Gemini format).
410
- */
411
- function extractUserInputFromRequestBody(body) {
412
- const firstContent = body?.contents?.[0];
413
- if (firstContent?.role !== "user" || !firstContent.parts?.length) return "";
414
- return firstContent.parts.map((p) => p.text).filter((t) => typeof t === "string").join(" ").trim();
415
- }
416
- /**
417
- * Builds the payload for a "Turn completed" audit event from the AI SDK
418
- * `OnFinishEvent`.
419
- *
420
- * Returns:
421
- * - `input`: user message text from `request.body.contents[0]` (Gemini-style)
422
- * - `output`: assistant response text (truncated to 200 chars)
423
- * - `toolCalls`: array of { toolName, toolInput, toolOutput }
424
- * - `loadedSkills`: skill names extracted from activate_skill results
425
- */
426
- function buildTurnLogPayload(event) {
427
- const toolCalls = [];
428
- let latestSkills;
429
- const toolOutputs = /* @__PURE__ */ new Map();
430
- forEachStep(event, (step) => {
431
- for (const tr of step.toolResults) toolOutputs.set(tr.toolCallId, tr.output);
432
- });
433
- forEachStep(event, (step) => {
434
- for (const tc of step.toolCalls) toolCalls.push({
435
- name: tc.toolName,
436
- input: tc.input,
437
- output: toolOutputs.get(tc.toolCallId)
438
- });
439
- const considerToolResultForSkills = (toolName, output) => {
440
- if (toolName !== "activate_skill") return;
441
- const s = stringifyForSkillScan(output);
442
- const sentinelIdx = s.indexOf(SKILL_STATE_SENTINEL);
443
- if (sentinelIdx === -1) return;
444
- try {
445
- const stateJson = s.slice(sentinelIdx + 18);
446
- latestSkills = JSON.parse(stateJson);
447
- } catch {}
448
- };
449
- for (const tr of step.toolResults) considerToolResultForSkills(tr.toolName, tr.output);
450
- });
451
- const input = extractUserInputFromRequestBody(event.request?.body);
452
- return {
453
- detail: {
454
- model: event.model.modelId,
455
- tokens: event.usage?.totalTokens
456
- },
457
- loadedSkills: latestSkills ?? [],
458
- toolCalls,
459
- input: input.slice(0, 200),
460
- output: (event.text ?? "").slice(0, 200)
461
- };
462
- }
463
- //#endregion
464
464
  //#region src/server/agent/Agent.ts
465
465
  /**
466
466
  * Base agent for Cloudflare Agents SDK Durable Objects with lazy skill loading,
@@ -849,6 +849,19 @@ var ChatAgent = class extends AIChatAgent {
849
849
  */
850
850
  session;
851
851
  /**
852
+ * The identity associated with the session.
853
+ * Define getIdentity to return the identity from the request.
854
+ */
855
+ identity = {};
856
+ /**
857
+ * Returns the identity from the request.
858
+ * @returns The identity from the request.
859
+ * @param token - The token from the request.
860
+ */
861
+ async getIdentity(_token) {
862
+ return Promise.resolve({});
863
+ }
864
+ /**
852
865
  * Returns the user ID from the durable object name.
853
866
  */
854
867
  getUserId() {
@@ -883,6 +896,8 @@ var ChatAgent = class extends AIChatAgent {
883
896
  this.session = result.claims;
884
897
  }
885
898
  }
899
+ const token = extractTokenFromConnectRequest(ctx.request);
900
+ if (token) this.identity = await this.getIdentity(token);
886
901
  return super.onConnect(connection, ctx);
887
902
  }
888
903
  /**
@@ -1040,4 +1055,4 @@ var ChatAgentHarness = class extends ChatAgent {
1040
1055
  }
1041
1056
  };
1042
1057
  //#endregion
1043
- export { Agent, ChatAgent, ChatAgentHarness, buildLLMParams, extractTokenFromConnectRequest, routeAgentRequest };
1058
+ export { Agent, ChatAgent, ChatAgentHarness, buildLLMParams, routeAgentRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@economic/agents",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "description": "A starter for creating a TypeScript package.",
5
5
  "license": "MIT",
6
6
  "bin": {