@economic/agents 2.3.25 → 2.3.27

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
@@ -83,6 +83,31 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
83
83
  */
84
84
  protected getRemoteSkills(): string[];
85
85
  private _getAuthorizedTools;
86
+ /**
87
+ * Wrap each tool's `execute` so it falls back to the current turn's tool
88
+ * context ({@link _toolContextForCurrentTurn}: request body + `_userContext`)
89
+ * when the caller supplies none. A caller-supplied `experimental_context`
90
+ * always wins, so normal steps — where {@link beforeStep} provides the
91
+ * context — are untouched.
92
+ *
93
+ * The fallback exists for the approval continuation: when a `needsApproval`
94
+ * tool is approved, the AI SDK executes it BEFORE the step loop starts, so no
95
+ * `beforeStep` runs for it and `execute` receives `experimental_context:
96
+ * undefined` — which stripped action tools of their auth token / user context
97
+ * after approval. The continuation is a turn of its own: {@link beforeTurn}
98
+ * re-sets {@link _toolContextForCurrentTurn} from the approval request's body
99
+ * before the SDK executes the tool, so the fallback context is the approval
100
+ * request's — clients must resend anything tools need (e.g. tokens) on it.
101
+ *
102
+ * TODO: remove once @cloudflare/think supports a turn-level
103
+ * `experimental_context` (its TurnConfig has no such field and it passes none
104
+ * to `streamText`, so only `beforeStep` can supply one — and the approval
105
+ * execution happens before any step).
106
+ *
107
+ * See {@link withFallbackToolContext} for the wrap itself, which preserves an
108
+ * `async function*` `execute`'s streaming shape.
109
+ */
110
+ private _withTurnContextFallback;
86
111
  private _getLastActivatedSkillName;
87
112
  /**
88
113
  * Override to enable JWT authentication on WebSocket connections.
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.
@@ -211,7 +248,7 @@ var Agent = class extends Think {
211
248
  tools: ["activate_skill"]
212
249
  }]
213
250
  }),
214
- tools,
251
+ tools: this._withTurnContextFallback(tools),
215
252
  activeTools,
216
253
  experimental_transform: buildSourcesTransform(),
217
254
  experimental_telemetry: {
@@ -291,6 +328,33 @@ var Agent = class extends Think {
291
328
  activeTools
292
329
  };
293
330
  }
331
+ /**
332
+ * Wrap each tool's `execute` so it falls back to the current turn's tool
333
+ * context ({@link _toolContextForCurrentTurn}: request body + `_userContext`)
334
+ * when the caller supplies none. A caller-supplied `experimental_context`
335
+ * always wins, so normal steps — where {@link beforeStep} provides the
336
+ * context — are untouched.
337
+ *
338
+ * The fallback exists for the approval continuation: when a `needsApproval`
339
+ * tool is approved, the AI SDK executes it BEFORE the step loop starts, so no
340
+ * `beforeStep` runs for it and `execute` receives `experimental_context:
341
+ * undefined` — which stripped action tools of their auth token / user context
342
+ * after approval. The continuation is a turn of its own: {@link beforeTurn}
343
+ * re-sets {@link _toolContextForCurrentTurn} from the approval request's body
344
+ * before the SDK executes the tool, so the fallback context is the approval
345
+ * request's — clients must resend anything tools need (e.g. tokens) on it.
346
+ *
347
+ * TODO: remove once @cloudflare/think supports a turn-level
348
+ * `experimental_context` (its TurnConfig has no such field and it passes none
349
+ * to `streamText`, so only `beforeStep` can supply one — and the approval
350
+ * execution happens before any step).
351
+ *
352
+ * See {@link withFallbackToolContext} for the wrap itself, which preserves an
353
+ * `async function*` `execute`'s streaming shape.
354
+ */
355
+ _withTurnContextFallback(tools) {
356
+ return withFallbackToolContext(tools, () => this._toolContextForCurrentTurn);
357
+ }
294
358
  _getLastActivatedSkillName(items = []) {
295
359
  for (let index = items.length - 1; index >= 0; index--) {
296
360
  const item = items[index];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@economic/agents",
3
- "version": "2.3.25",
3
+ "version": "2.3.27",
4
4
  "description": "A starter for creating a TypeScript package.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -36,7 +36,7 @@
36
36
  "devDependencies": {
37
37
  "@babel/core": "^7.29.7",
38
38
  "@babel/plugin-proposal-decorators": "^7.29.7",
39
- "@cloudflare/workers-types": "^4.20260701.1",
39
+ "@cloudflare/workers-types": "^4.20260702.1",
40
40
  "@rolldown/plugin-babel": "^0.2.3",
41
41
  "@types/node": "^25.6.0",
42
42
  "@typescript/native-preview": "7.0.0-dev.20260412.1",
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@cloudflare/think": "^0.12.1",
49
- "@cloudflare/vite-plugin": "^1.42.4",
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"