@economic/agents 1.6.0 → 1.6.2
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 +3 -2
- package/dist/index.mjs +97 -97
- package/package.json +1 -1
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 { AIChatAgent, ChatResponseResult, OnChatMessageOptions } from "@cloudflare/ai-chat";
|
|
4
3
|
import { JWTPayload } from "jose";
|
|
4
|
+
import { AIChatAgent, ChatResponseResult, OnChatMessageOptions } from "@cloudflare/ai-chat";
|
|
5
5
|
|
|
6
6
|
//#region src/server/shared/features/skills/index.d.ts
|
|
7
7
|
/**
|
|
@@ -83,6 +83,7 @@ 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;
|
|
86
87
|
//#endregion
|
|
87
88
|
//#region src/server/agent/Agent.d.ts
|
|
88
89
|
/**
|
|
@@ -277,4 +278,4 @@ declare abstract class ChatAgentHarness<Env extends Cloudflare.Env, RequestBody
|
|
|
277
278
|
onChatMessage(onFinish: StreamTextOnFinishCallback<ToolSet>, options?: OnChatMessageOptions): Promise<Response>;
|
|
278
279
|
}
|
|
279
280
|
//#endregion
|
|
280
|
-
export { Agent, type AgentToolContext, type BuildLLMParamsConfig, ChatAgent, ChatAgentHarness, type Skill, buildLLMParams, routeAgentRequest };
|
|
281
|
+
export { Agent, type AgentToolContext, type BuildLLMParamsConfig, ChatAgent, ChatAgentHarness, type Skill, buildLLMParams, extractTokenFromConnectRequest, 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 { AIChatAgent } from "@cloudflare/ai-chat";
|
|
4
3
|
import { createRemoteJWKSet, decodeJwt, errors, jwtVerify } from "jose";
|
|
4
|
+
import { AIChatAgent } from "@cloudflare/ai-chat";
|
|
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,98 +269,6 @@ 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
|
|
364
272
|
//#region src/server/shared/features/auth/index.ts
|
|
365
273
|
const jwksByIssuer = /* @__PURE__ */ new Map();
|
|
366
274
|
function getJwksForIssuer(issuer) {
|
|
@@ -375,7 +283,7 @@ function getJwksForIssuer(issuer) {
|
|
|
375
283
|
function isIssuerAllowed(iss, allowed) {
|
|
376
284
|
return allowed.some((rule) => typeof rule === "string" ? rule === iss : rule.test(iss));
|
|
377
285
|
}
|
|
378
|
-
function
|
|
286
|
+
function extractTokenFromConnectRequest(request) {
|
|
379
287
|
const authorization = request.headers.get("Authorization");
|
|
380
288
|
if (authorization) {
|
|
381
289
|
const match = authorization.match(/^Bearer\s+(.+)$/i);
|
|
@@ -412,7 +320,7 @@ function hasRequiredScopes(tokenScope, required) {
|
|
|
412
320
|
* @throws Error for unexpected failures that should be logged
|
|
413
321
|
*/
|
|
414
322
|
async function verifyJwt(request, config) {
|
|
415
|
-
const token =
|
|
323
|
+
const token = extractTokenFromConnectRequest(request);
|
|
416
324
|
if (!token) return {
|
|
417
325
|
success: false,
|
|
418
326
|
status: 401,
|
|
@@ -461,6 +369,98 @@ async function verifyJwt(request, config) {
|
|
|
461
369
|
};
|
|
462
370
|
}
|
|
463
371
|
//#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,
|
|
@@ -1036,8 +1036,8 @@ var ChatAgentHarness = class extends ChatAgent {
|
|
|
1036
1036
|
system: this.getSystemPrompt(ctx),
|
|
1037
1037
|
skills: this.getSkills(ctx),
|
|
1038
1038
|
tools: this.getTools(ctx)
|
|
1039
|
-
})).toUIMessageStreamResponse();
|
|
1039
|
+
})).toUIMessageStreamResponse({ sendSources: true });
|
|
1040
1040
|
}
|
|
1041
1041
|
};
|
|
1042
1042
|
//#endregion
|
|
1043
|
-
export { Agent, ChatAgent, ChatAgentHarness, buildLLMParams, routeAgentRequest };
|
|
1043
|
+
export { Agent, ChatAgent, ChatAgentHarness, buildLLMParams, extractTokenFromConnectRequest, routeAgentRequest };
|