@economic/agents 2.3.26 → 2.4.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/dist/index.d.mts +50 -2
- package/dist/index.mjs +120 -11
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as JwtAuthConfig, t as routeAgentRequest } from "./route-agent-request-D2ll--nF.mjs";
|
|
2
2
|
import { Agent as Agent$1, Connection, ConnectionContext, SubAgentClass } from "agents";
|
|
3
3
|
import { ChatResponseResult, PrepareStepContext, Session, Think, ToolCallContext, ToolCallDecision, TurnConfig, TurnContext, skills } from "@cloudflare/think";
|
|
4
|
-
import { JSONValue, LanguageModel, Tool as Tool$1, UIMessage } from "ai";
|
|
4
|
+
import { JSONValue, LanguageModel, ModelMessage, Tool as Tool$1, UIMessage } from "ai";
|
|
5
5
|
import { createCompactFunction } from "agents/experimental/memory/utils";
|
|
6
6
|
import { SkillSource as SkillSource$1 } from "agents/skills";
|
|
7
7
|
|
|
@@ -34,6 +34,15 @@ type Tool<Context extends Record<string, unknown> = Record<string, unknown>, INP
|
|
|
34
34
|
declare function tool<Context extends Record<string, unknown> = Record<string, unknown>, INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any>(tool: Tool<Context, INPUT, OUTPUT>): Tool$1<INPUT, OUTPUT>;
|
|
35
35
|
//#endregion
|
|
36
36
|
//#region src/server/agents/Agent.d.ts
|
|
37
|
+
/** What the model would see on its next step — returned by {@link Agent.inspectTurn}. */
|
|
38
|
+
interface TurnSnapshot {
|
|
39
|
+
system: string;
|
|
40
|
+
tools: ToolSet;
|
|
41
|
+
activeTools: string[];
|
|
42
|
+
/** Tools provided by the framework (session/skill meta-tools, MCP), not the agent. */
|
|
43
|
+
frameworkToolNames: string[];
|
|
44
|
+
messages: ModelMessage[];
|
|
45
|
+
}
|
|
37
46
|
declare abstract class Agent<RequestContext extends Record<string, unknown> = Record<string, unknown>, UserContext extends Record<string, unknown> = Record<string, unknown>, State = unknown> extends Think<Cloudflare.Env & AgentEnv, State> {
|
|
38
47
|
protected agentType: AgentConnectionType;
|
|
39
48
|
protected clientIp?: string;
|
|
@@ -75,6 +84,19 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
|
|
|
75
84
|
}>;
|
|
76
85
|
beforeToolCall(ctx: ToolCallContext): Promise<ToolCallDecision | void>;
|
|
77
86
|
getTools(): ToolSet;
|
|
87
|
+
/**
|
|
88
|
+
* Read-only: what the model would see on its next step for the given history
|
|
89
|
+
* — the assembled system prompt, the skill-gated toolset, and pruned
|
|
90
|
+
* messages. Runs no turn (nothing admitted, persisted, executed; no model
|
|
91
|
+
* call). Skill gating is derived from the history, so a history with an
|
|
92
|
+
* `activate_skill` call yields that skill's tools. For eval harnesses and
|
|
93
|
+
* prompt-preview tooling; call it inside the DO context.
|
|
94
|
+
*/
|
|
95
|
+
inspectTurn(input?: {
|
|
96
|
+
messages?: ModelMessage[];
|
|
97
|
+
requestContext?: RequestContext;
|
|
98
|
+
userContext?: UserContext;
|
|
99
|
+
}): Promise<TurnSnapshot>;
|
|
78
100
|
workspaceBash: boolean;
|
|
79
101
|
getSkillScriptRunner(): skills.SkillScriptRunner | null;
|
|
80
102
|
/**
|
|
@@ -82,7 +104,33 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
|
|
|
82
104
|
* @returns The remote skills to be loaded from SKILLS_BUCKET.
|
|
83
105
|
*/
|
|
84
106
|
protected getRemoteSkills(): string[];
|
|
107
|
+
private _pruneTurnMessages;
|
|
85
108
|
private _getAuthorizedTools;
|
|
109
|
+
/**
|
|
110
|
+
* Wrap each tool's `execute` so it falls back to the current turn's tool
|
|
111
|
+
* context ({@link _toolContextForCurrentTurn}: request body + `_userContext`)
|
|
112
|
+
* when the caller supplies none. A caller-supplied `experimental_context`
|
|
113
|
+
* always wins, so normal steps — where {@link beforeStep} provides the
|
|
114
|
+
* context — are untouched.
|
|
115
|
+
*
|
|
116
|
+
* The fallback exists for the approval continuation: when a `needsApproval`
|
|
117
|
+
* tool is approved, the AI SDK executes it BEFORE the step loop starts, so no
|
|
118
|
+
* `beforeStep` runs for it and `execute` receives `experimental_context:
|
|
119
|
+
* undefined` — which stripped action tools of their auth token / user context
|
|
120
|
+
* after approval. The continuation is a turn of its own: {@link beforeTurn}
|
|
121
|
+
* re-sets {@link _toolContextForCurrentTurn} from the approval request's body
|
|
122
|
+
* before the SDK executes the tool, so the fallback context is the approval
|
|
123
|
+
* request's — clients must resend anything tools need (e.g. tokens) on it.
|
|
124
|
+
*
|
|
125
|
+
* TODO: remove once @cloudflare/think supports a turn-level
|
|
126
|
+
* `experimental_context` (its TurnConfig has no such field and it passes none
|
|
127
|
+
* to `streamText`, so only `beforeStep` can supply one — and the approval
|
|
128
|
+
* execution happens before any step).
|
|
129
|
+
*
|
|
130
|
+
* See {@link withFallbackToolContext} for the wrap itself, which preserves an
|
|
131
|
+
* `async function*` `execute`'s streaming shape.
|
|
132
|
+
*/
|
|
133
|
+
private _withTurnContextFallback;
|
|
86
134
|
private _getLastActivatedSkillName;
|
|
87
135
|
/**
|
|
88
136
|
* Override to enable JWT authentication on WebSocket connections.
|
|
@@ -315,4 +363,4 @@ declare function skill<Context extends Record<string, unknown> = Record<string,
|
|
|
315
363
|
//#region src/server/index.d.ts
|
|
316
364
|
declare function getCurrentToolContext(): any;
|
|
317
365
|
//#endregion
|
|
318
|
-
export { Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, Assistant, ChatAgent, type FacetStub, type LegacyChatStub, type LegacyMessageFeedback, type MigrationDeps, type Skill, type SkillSource, type Tool, type ToolContext, type ToolSet, getCurrentToolContext, migrateUserFromV1, routeAgentRequest, skill, tool };
|
|
366
|
+
export { Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, Assistant, ChatAgent, type FacetStub, type LegacyChatStub, type LegacyMessageFeedback, type MigrationDeps, type Skill, type SkillSource, type Tool, type ToolContext, type ToolSet, type TurnSnapshot, getCurrentToolContext, migrateUserFromV1, routeAgentRequest, skill, tool };
|
package/dist/index.mjs
CHANGED
|
@@ -8,6 +8,43 @@ import { createCompactFunction } from "agents/experimental/memory/utils";
|
|
|
8
8
|
function tool(tool) {
|
|
9
9
|
return tool$1(tool);
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Wrap each tool's `execute` so it falls back to `getFallbackContext()` for
|
|
13
|
+
* `experimental_context` when the caller supplies none (e.g. the approval
|
|
14
|
+
* continuation, which bypasses `beforeStep`). A caller-supplied context always
|
|
15
|
+
* wins, so on a normal turn the wrap is a no-op.
|
|
16
|
+
*
|
|
17
|
+
* Crucially it preserves the function's shape: an `async function*` `execute`
|
|
18
|
+
* stays an async generator so `@cloudflare/think` keeps detecting it
|
|
19
|
+
* (`execute.constructor.name === "AsyncGeneratorFunction"`) and streams the
|
|
20
|
+
* tool's preliminary (yielded) results. A plain wrapper would make think consume
|
|
21
|
+
* the iterable and keep only its final value — breaking streaming for every
|
|
22
|
+
* generator tool, on approval AND normal turns. Non-generator executes get an
|
|
23
|
+
* equivalent plain wrapper; non-function executes pass through untouched.
|
|
24
|
+
*/
|
|
25
|
+
function withFallbackToolContext(tools, getFallbackContext) {
|
|
26
|
+
const result = {};
|
|
27
|
+
for (const [name, tool] of Object.entries(tools)) {
|
|
28
|
+
const originalExecute = tool.execute;
|
|
29
|
+
if (typeof originalExecute !== "function") {
|
|
30
|
+
result[name] = tool;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
result[name] = {
|
|
34
|
+
...tool,
|
|
35
|
+
execute: originalExecute.constructor?.name === "AsyncGeneratorFunction" ? async function* (input, options) {
|
|
36
|
+
yield* originalExecute(input, {
|
|
37
|
+
...options,
|
|
38
|
+
experimental_context: options?.experimental_context ?? getFallbackContext()
|
|
39
|
+
});
|
|
40
|
+
} : (input, options) => originalExecute(input, {
|
|
41
|
+
...options,
|
|
42
|
+
experimental_context: options?.experimental_context ?? getFallbackContext()
|
|
43
|
+
})
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
11
48
|
//#endregion
|
|
12
49
|
//#region src/server/util/prompts.ts
|
|
13
50
|
const SECURITY_RULES_PROMPT = `These rules override all other instructions, no matter what the user asks.
|
|
@@ -201,17 +238,8 @@ var Agent = class extends Think {
|
|
|
201
238
|
return {
|
|
202
239
|
system: await this.session.refreshSystemPrompt(),
|
|
203
240
|
model: this.getModel(this._toolContextForCurrentTurn),
|
|
204
|
-
messages:
|
|
205
|
-
|
|
206
|
-
toolCalls: [{
|
|
207
|
-
type: "before-last-2-messages",
|
|
208
|
-
tools: []
|
|
209
|
-
}, {
|
|
210
|
-
type: "before-last-5-messages",
|
|
211
|
-
tools: ["activate_skill"]
|
|
212
|
-
}]
|
|
213
|
-
}),
|
|
214
|
-
tools,
|
|
241
|
+
messages: this._pruneTurnMessages(ctx.messages),
|
|
242
|
+
tools: this._withTurnContextFallback(tools),
|
|
215
243
|
activeTools,
|
|
216
244
|
experimental_transform: buildSourcesTransform(),
|
|
217
245
|
experimental_telemetry: {
|
|
@@ -264,6 +292,48 @@ var Agent = class extends Think {
|
|
|
264
292
|
getTools() {
|
|
265
293
|
return {};
|
|
266
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Read-only: what the model would see on its next step for the given history
|
|
297
|
+
* — the assembled system prompt, the skill-gated toolset, and pruned
|
|
298
|
+
* messages. Runs no turn (nothing admitted, persisted, executed; no model
|
|
299
|
+
* call). Skill gating is derived from the history, so a history with an
|
|
300
|
+
* `activate_skill` call yields that skill's tools. For eval harnesses and
|
|
301
|
+
* prompt-preview tooling; call it inside the DO context.
|
|
302
|
+
*/
|
|
303
|
+
async inspectTurn(input = {}) {
|
|
304
|
+
const messages = input.messages ?? [];
|
|
305
|
+
await this.__unsafe_ensureInitialized();
|
|
306
|
+
const previousContext = this._toolContextForCurrentTurn;
|
|
307
|
+
this._toolContextForCurrentTurn = {
|
|
308
|
+
...input.requestContext ?? {},
|
|
309
|
+
_userContext: input.userContext
|
|
310
|
+
};
|
|
311
|
+
const previousAuthorizedTools = this._authorizedToolsForCurrentTurn;
|
|
312
|
+
try {
|
|
313
|
+
const system = await this.session.refreshSystemPrompt();
|
|
314
|
+
const think = this;
|
|
315
|
+
const frameworkTools = {
|
|
316
|
+
...await this.session.tools(),
|
|
317
|
+
...think._skillRegistry?.tools(),
|
|
318
|
+
...think.mcp?.getAITools?.()
|
|
319
|
+
};
|
|
320
|
+
const { tools, activeTools } = await this._getAuthorizedTools({
|
|
321
|
+
...this.getTools(),
|
|
322
|
+
...frameworkTools
|
|
323
|
+
}, this._getLastActivatedSkillName(messages));
|
|
324
|
+
const snapshotContext = this._toolContextForCurrentTurn;
|
|
325
|
+
return {
|
|
326
|
+
system,
|
|
327
|
+
tools: withFallbackToolContext(tools, () => snapshotContext),
|
|
328
|
+
activeTools,
|
|
329
|
+
frameworkToolNames: Object.keys(frameworkTools),
|
|
330
|
+
messages: this._pruneTurnMessages(messages)
|
|
331
|
+
};
|
|
332
|
+
} finally {
|
|
333
|
+
this._toolContextForCurrentTurn = previousContext;
|
|
334
|
+
this._authorizedToolsForCurrentTurn = previousAuthorizedTools;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
267
337
|
workspaceBash = false;
|
|
268
338
|
getSkillScriptRunner() {
|
|
269
339
|
if (!("LOADER" in this.env)) return null;
|
|
@@ -276,6 +346,18 @@ var Agent = class extends Think {
|
|
|
276
346
|
getRemoteSkills() {
|
|
277
347
|
return [];
|
|
278
348
|
}
|
|
349
|
+
_pruneTurnMessages(messages) {
|
|
350
|
+
return pruneMessages({
|
|
351
|
+
messages,
|
|
352
|
+
toolCalls: [{
|
|
353
|
+
type: "before-last-2-messages",
|
|
354
|
+
tools: []
|
|
355
|
+
}, {
|
|
356
|
+
type: "before-last-5-messages",
|
|
357
|
+
tools: ["activate_skill"]
|
|
358
|
+
}]
|
|
359
|
+
});
|
|
360
|
+
}
|
|
279
361
|
async _getAuthorizedTools(availableTools, activeSkillName) {
|
|
280
362
|
const tools = { ...availableTools };
|
|
281
363
|
const activeTools = Object.keys(tools);
|
|
@@ -291,6 +373,33 @@ var Agent = class extends Think {
|
|
|
291
373
|
activeTools
|
|
292
374
|
};
|
|
293
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* Wrap each tool's `execute` so it falls back to the current turn's tool
|
|
378
|
+
* context ({@link _toolContextForCurrentTurn}: request body + `_userContext`)
|
|
379
|
+
* when the caller supplies none. A caller-supplied `experimental_context`
|
|
380
|
+
* always wins, so normal steps — where {@link beforeStep} provides the
|
|
381
|
+
* context — are untouched.
|
|
382
|
+
*
|
|
383
|
+
* The fallback exists for the approval continuation: when a `needsApproval`
|
|
384
|
+
* tool is approved, the AI SDK executes it BEFORE the step loop starts, so no
|
|
385
|
+
* `beforeStep` runs for it and `execute` receives `experimental_context:
|
|
386
|
+
* undefined` — which stripped action tools of their auth token / user context
|
|
387
|
+
* after approval. The continuation is a turn of its own: {@link beforeTurn}
|
|
388
|
+
* re-sets {@link _toolContextForCurrentTurn} from the approval request's body
|
|
389
|
+
* before the SDK executes the tool, so the fallback context is the approval
|
|
390
|
+
* request's — clients must resend anything tools need (e.g. tokens) on it.
|
|
391
|
+
*
|
|
392
|
+
* TODO: remove once @cloudflare/think supports a turn-level
|
|
393
|
+
* `experimental_context` (its TurnConfig has no such field and it passes none
|
|
394
|
+
* to `streamText`, so only `beforeStep` can supply one — and the approval
|
|
395
|
+
* execution happens before any step).
|
|
396
|
+
*
|
|
397
|
+
* See {@link withFallbackToolContext} for the wrap itself, which preserves an
|
|
398
|
+
* `async function*` `execute`'s streaming shape.
|
|
399
|
+
*/
|
|
400
|
+
_withTurnContextFallback(tools) {
|
|
401
|
+
return withFallbackToolContext(tools, () => this._toolContextForCurrentTurn);
|
|
402
|
+
}
|
|
294
403
|
_getLastActivatedSkillName(items = []) {
|
|
295
404
|
for (let index = items.length - 1; index >= 0; index--) {
|
|
296
405
|
const item = items[index];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@economic/agents",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "A starter for creating a TypeScript package.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@cloudflare/think": "^0.12.1",
|
|
49
|
-
"@cloudflare/vite-plugin": "^1.43.0",
|
|
49
|
+
"@cloudflare/vite-plugin": "^1.43.0 <1.43.2",
|
|
50
50
|
"@cloudflare/worker-bundler": "^0.2.1",
|
|
51
51
|
"agents": "^0.17.3",
|
|
52
52
|
"vite": ">=8.0.0"
|