agentfootprint 9.5.1 → 9.7.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.
Files changed (185) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/ai-instructions/claude-code/SKILL.md +1 -1
  4. package/dist/adapters/code/agentcore.js +294 -0
  5. package/dist/adapters/code/agentcore.js.map +1 -0
  6. package/dist/adapters/code/local.js +200 -0
  7. package/dist/adapters/code/local.js.map +1 -0
  8. package/dist/adapters/llm/AnthropicProvider.js +6 -0
  9. package/dist/adapters/llm/AnthropicProvider.js.map +1 -1
  10. package/dist/adapters/llm/BedrockProvider.js +7 -0
  11. package/dist/adapters/llm/BedrockProvider.js.map +1 -1
  12. package/dist/adapters/llm/BrowserAnthropicProvider.js +13 -0
  13. package/dist/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
  14. package/dist/adapters/llm/BrowserOpenAIProvider.js +14 -0
  15. package/dist/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
  16. package/dist/adapters/llm/OpenAIProvider.js +7 -0
  17. package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
  18. package/dist/adapters/llm/contextWindow.js +284 -0
  19. package/dist/adapters/llm/contextWindow.js.map +1 -0
  20. package/dist/core/Agent.js +145 -0
  21. package/dist/core/Agent.js.map +1 -1
  22. package/dist/core/RunnerBase.js +67 -0
  23. package/dist/core/RunnerBase.js.map +1 -1
  24. package/dist/core/agent/stages/seed.js +67 -11
  25. package/dist/core/agent/stages/seed.js.map +1 -1
  26. package/dist/core/agent/stages/toolCalls.js +90 -0
  27. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  28. package/dist/core/codeRunnerTool.js +252 -0
  29. package/dist/core/codeRunnerTool.js.map +1 -0
  30. package/dist/core/runCheckpoint.js +102 -2
  31. package/dist/core/runCheckpoint.js.map +1 -1
  32. package/dist/core/toolSessions.js +396 -0
  33. package/dist/core/toolSessions.js.map +1 -0
  34. package/dist/core/tools.js.map +1 -1
  35. package/dist/doors/providers.js +13 -0
  36. package/dist/doors/providers.js.map +1 -1
  37. package/dist/esm/adapters/code/agentcore.d.ts +133 -0
  38. package/dist/esm/adapters/code/agentcore.js +290 -0
  39. package/dist/esm/adapters/code/agentcore.js.map +1 -0
  40. package/dist/esm/adapters/code/local.d.ts +99 -0
  41. package/dist/esm/adapters/code/local.js +196 -0
  42. package/dist/esm/adapters/code/local.js.map +1 -0
  43. package/dist/esm/adapters/llm/AnthropicProvider.js +6 -0
  44. package/dist/esm/adapters/llm/AnthropicProvider.js.map +1 -1
  45. package/dist/esm/adapters/llm/BedrockProvider.js +7 -0
  46. package/dist/esm/adapters/llm/BedrockProvider.js.map +1 -1
  47. package/dist/esm/adapters/llm/BrowserAnthropicProvider.js +13 -0
  48. package/dist/esm/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
  49. package/dist/esm/adapters/llm/BrowserOpenAIProvider.js +14 -0
  50. package/dist/esm/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
  51. package/dist/esm/adapters/llm/OpenAIProvider.js +7 -0
  52. package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
  53. package/dist/esm/adapters/llm/contextWindow.d.ts +111 -0
  54. package/dist/esm/adapters/llm/contextWindow.js +277 -0
  55. package/dist/esm/adapters/llm/contextWindow.js.map +1 -0
  56. package/dist/esm/adapters/types.d.ts +87 -0
  57. package/dist/esm/core/Agent.d.ts +65 -0
  58. package/dist/esm/core/Agent.js +146 -1
  59. package/dist/esm/core/Agent.js.map +1 -1
  60. package/dist/esm/core/RunnerBase.d.ts +51 -0
  61. package/dist/esm/core/RunnerBase.js +67 -0
  62. package/dist/esm/core/RunnerBase.js.map +1 -1
  63. package/dist/esm/core/agent/stages/seed.d.ts +12 -0
  64. package/dist/esm/core/agent/stages/seed.js +67 -11
  65. package/dist/esm/core/agent/stages/seed.js.map +1 -1
  66. package/dist/esm/core/agent/stages/toolCalls.d.ts +31 -0
  67. package/dist/esm/core/agent/stages/toolCalls.js +90 -0
  68. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  69. package/dist/esm/core/agent/types.d.ts +23 -2
  70. package/dist/esm/core/codeRunnerTool.d.ts +120 -0
  71. package/dist/esm/core/codeRunnerTool.js +247 -0
  72. package/dist/esm/core/codeRunnerTool.js.map +1 -0
  73. package/dist/esm/core/runCheckpoint.d.ts +25 -0
  74. package/dist/esm/core/runCheckpoint.js +100 -1
  75. package/dist/esm/core/runCheckpoint.js.map +1 -1
  76. package/dist/esm/core/toolSessions.d.ts +318 -0
  77. package/dist/esm/core/toolSessions.js +389 -0
  78. package/dist/esm/core/toolSessions.js.map +1 -0
  79. package/dist/esm/core/tools.d.ts +60 -0
  80. package/dist/esm/core/tools.js.map +1 -1
  81. package/dist/esm/doors/providers.d.ts +7 -0
  82. package/dist/esm/doors/providers.js +10 -0
  83. package/dist/esm/doors/providers.js.map +1 -1
  84. package/dist/esm/events/payloads.d.ts +50 -0
  85. package/dist/esm/events/registry.d.ts +9 -1
  86. package/dist/esm/events/registry.js +8 -0
  87. package/dist/esm/events/registry.js.map +1 -1
  88. package/dist/esm/index.d.ts +4 -1
  89. package/dist/esm/index.js +11 -1
  90. package/dist/esm/index.js.map +1 -1
  91. package/dist/esm/lib/mcp/mcpServe.js +37 -1
  92. package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
  93. package/dist/esm/lib/trace-toolpack/traceToolpack.js +15 -1
  94. package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
  95. package/dist/esm/memory/causal/writeSnapshot.d.ts +17 -4
  96. package/dist/esm/memory/causal/writeSnapshot.js +31 -27
  97. package/dist/esm/memory/causal/writeSnapshot.js.map +1 -1
  98. package/dist/esm/memory/define.js +4 -0
  99. package/dist/esm/memory/define.js.map +1 -1
  100. package/dist/esm/memory/define.types.d.ts +17 -0
  101. package/dist/esm/memory/define.types.js.map +1 -1
  102. package/dist/esm/memory/index.d.ts +1 -0
  103. package/dist/esm/memory/index.js +1 -0
  104. package/dist/esm/memory/index.js.map +1 -1
  105. package/dist/esm/memory/stages/types.d.ts +13 -3
  106. package/dist/esm/memory/turn/index.d.ts +7 -0
  107. package/dist/esm/memory/turn/index.js +11 -0
  108. package/dist/esm/memory/turn/index.js.map +1 -0
  109. package/dist/esm/memory/turn/resolveTurnNumber.d.ts +94 -0
  110. package/dist/esm/memory/turn/resolveTurnNumber.js +75 -0
  111. package/dist/esm/memory/turn/resolveTurnNumber.js.map +1 -0
  112. package/dist/events/registry.js +8 -0
  113. package/dist/events/registry.js.map +1 -1
  114. package/dist/index.js +23 -1
  115. package/dist/index.js.map +1 -1
  116. package/dist/lib/mcp/mcpServe.js +37 -1
  117. package/dist/lib/mcp/mcpServe.js.map +1 -1
  118. package/dist/lib/trace-toolpack/traceToolpack.js +15 -1
  119. package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
  120. package/dist/memory/causal/writeSnapshot.js +31 -27
  121. package/dist/memory/causal/writeSnapshot.js.map +1 -1
  122. package/dist/memory/define.js +4 -0
  123. package/dist/memory/define.js.map +1 -1
  124. package/dist/memory/define.types.js.map +1 -1
  125. package/dist/memory/index.js +1 -0
  126. package/dist/memory/index.js.map +1 -1
  127. package/dist/memory/turn/index.js +16 -0
  128. package/dist/memory/turn/index.js.map +1 -0
  129. package/dist/memory/turn/resolveTurnNumber.js +81 -0
  130. package/dist/memory/turn/resolveTurnNumber.js.map +1 -0
  131. package/dist/types/adapters/code/agentcore.d.ts +134 -0
  132. package/dist/types/adapters/code/agentcore.d.ts.map +1 -0
  133. package/dist/types/adapters/code/local.d.ts +100 -0
  134. package/dist/types/adapters/code/local.d.ts.map +1 -0
  135. package/dist/types/adapters/llm/AnthropicProvider.d.ts.map +1 -1
  136. package/dist/types/adapters/llm/BedrockProvider.d.ts.map +1 -1
  137. package/dist/types/adapters/llm/BrowserAnthropicProvider.d.ts.map +1 -1
  138. package/dist/types/adapters/llm/BrowserOpenAIProvider.d.ts.map +1 -1
  139. package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
  140. package/dist/types/adapters/llm/contextWindow.d.ts +112 -0
  141. package/dist/types/adapters/llm/contextWindow.d.ts.map +1 -0
  142. package/dist/types/adapters/types.d.ts +87 -0
  143. package/dist/types/adapters/types.d.ts.map +1 -1
  144. package/dist/types/core/Agent.d.ts +65 -0
  145. package/dist/types/core/Agent.d.ts.map +1 -1
  146. package/dist/types/core/RunnerBase.d.ts +51 -0
  147. package/dist/types/core/RunnerBase.d.ts.map +1 -1
  148. package/dist/types/core/agent/stages/seed.d.ts +12 -0
  149. package/dist/types/core/agent/stages/seed.d.ts.map +1 -1
  150. package/dist/types/core/agent/stages/toolCalls.d.ts +31 -0
  151. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  152. package/dist/types/core/agent/types.d.ts +23 -2
  153. package/dist/types/core/agent/types.d.ts.map +1 -1
  154. package/dist/types/core/codeRunnerTool.d.ts +121 -0
  155. package/dist/types/core/codeRunnerTool.d.ts.map +1 -0
  156. package/dist/types/core/runCheckpoint.d.ts +25 -0
  157. package/dist/types/core/runCheckpoint.d.ts.map +1 -1
  158. package/dist/types/core/toolSessions.d.ts +319 -0
  159. package/dist/types/core/toolSessions.d.ts.map +1 -0
  160. package/dist/types/core/tools.d.ts +60 -0
  161. package/dist/types/core/tools.d.ts.map +1 -1
  162. package/dist/types/doors/providers.d.ts +7 -0
  163. package/dist/types/doors/providers.d.ts.map +1 -1
  164. package/dist/types/events/payloads.d.ts +50 -0
  165. package/dist/types/events/payloads.d.ts.map +1 -1
  166. package/dist/types/events/registry.d.ts +9 -1
  167. package/dist/types/events/registry.d.ts.map +1 -1
  168. package/dist/types/index.d.ts +4 -1
  169. package/dist/types/index.d.ts.map +1 -1
  170. package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
  171. package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
  172. package/dist/types/memory/causal/writeSnapshot.d.ts +17 -4
  173. package/dist/types/memory/causal/writeSnapshot.d.ts.map +1 -1
  174. package/dist/types/memory/define.d.ts.map +1 -1
  175. package/dist/types/memory/define.types.d.ts +17 -0
  176. package/dist/types/memory/define.types.d.ts.map +1 -1
  177. package/dist/types/memory/index.d.ts +1 -0
  178. package/dist/types/memory/index.d.ts.map +1 -1
  179. package/dist/types/memory/stages/types.d.ts +13 -3
  180. package/dist/types/memory/stages/types.d.ts.map +1 -1
  181. package/dist/types/memory/turn/index.d.ts +8 -0
  182. package/dist/types/memory/turn/index.d.ts.map +1 -0
  183. package/dist/types/memory/turn/resolveTurnNumber.d.ts +95 -0
  184. package/dist/types/memory/turn/resolveTurnNumber.d.ts.map +1 -0
  185. package/package.json +1 -1
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ /**
3
+ * ContextWindowExceededError — "the request did not fit" as a typed error
4
+ * that names the fixes (9.6.0).
5
+ *
6
+ * Every vendor refuses an over-long request in its own words, and until now
7
+ * every one of them reached the caller as an opaque provider error:
8
+ *
9
+ * [openai] 400 Input tokens exceed the configured limit of 272000 tokens.
10
+ * Your messages resulted in 879073 tokens.
11
+ *
12
+ * That is the message a production field deployment spent a day on. It is a
13
+ * true sentence and a useless one: it does not say which of the framework's
14
+ * dials moves that number, and it looks exactly like a transient 400 — so the
15
+ * natural next move is to retry, which re-sends the same oversized history and
16
+ * fails identically, forever.
17
+ *
18
+ * So the adapters translate it, ONCE, into an error whose message contains the
19
+ * three fixes in the order they are worth trying, and which carries the two
20
+ * numbers (limit, actual) when the vendor stated them.
21
+ *
22
+ * **Detection is deliberately conservative.** Only unmistakable phrases and
23
+ * vendor codes translate; everything else passes through untouched as the
24
+ * provider error it always was. In particular a RATE limit ("rate limit
25
+ * reached … tokens per min") is a different failure with a different fix and
26
+ * must never land here — which is why no pattern matches on "too many tokens".
27
+ *
28
+ * @see ../../core/runCheckpoint.ts where this class makes `resumeOnError`
29
+ * stop advertising a resume that cannot work
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.asContextWindowExceeded = exports.looksLikeContextWindowExceeded = exports.isContextWindowExceeded = exports.ContextWindowExceededError = exports.ERR_CONTEXT_WINDOW_EXCEEDED = void 0;
33
+ /** Discriminator carried on the error — stable across releases. */
34
+ exports.ERR_CONTEXT_WINDOW_EXCEEDED = 'ERR_CONTEXT_WINDOW_EXCEEDED';
35
+ /**
36
+ * Thrown by an LLM adapter when the provider refused the request because the
37
+ * prompt did not fit the model's context window.
38
+ *
39
+ * A refusal, not a failure of the model: nothing was generated and nothing was
40
+ * charged for output. Retrying the identical request is deterministic — it
41
+ * fails the same way — so this is one of the classes
42
+ * {@link canResume} reports as not resumable.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { ContextWindowExceededError } from 'agentfootprint';
47
+ *
48
+ * try {
49
+ * await agent.run({ message: 'summarise the fabric inventory' });
50
+ * } catch (err) {
51
+ * if (err instanceof ContextWindowExceededError) {
52
+ * console.error(`sent ${err.actualTokens} against ${err.limitTokens}`);
53
+ * // …cap the tool result, or add .window(slidingWindow({ keepRecentTurns: 2 }))
54
+ * }
55
+ * }
56
+ * ```
57
+ */
58
+ class ContextWindowExceededError extends Error {
59
+ code = exports.ERR_CONTEXT_WINDOW_EXCEEDED;
60
+ /** Which adapter refused — `'openai'`, `'anthropic'`, `'bedrock'`, … */
61
+ provider;
62
+ /** The model's (or gateway's) ceiling in tokens, when the vendor said it. */
63
+ limitTokens;
64
+ /** What the request actually came to in tokens, when the vendor said it. */
65
+ actualTokens;
66
+ /** HTTP status, when there was one. Kept so retry policies still see a 4xx. */
67
+ status;
68
+ /** The provider's own error, unchanged. */
69
+ cause;
70
+ constructor(args) {
71
+ super(buildMessage(args));
72
+ this.name = 'ContextWindowExceededError';
73
+ this.provider = args.provider;
74
+ if (args.limitTokens !== undefined)
75
+ this.limitTokens = args.limitTokens;
76
+ if (args.actualTokens !== undefined)
77
+ this.actualTokens = args.actualTokens;
78
+ if (args.status !== undefined)
79
+ this.status = args.status;
80
+ if (args.cause !== undefined)
81
+ this.cause = args.cause;
82
+ }
83
+ }
84
+ exports.ContextWindowExceededError = ContextWindowExceededError;
85
+ /** `true` for the typed error, including across a `structuredClone`-free
86
+ * boundary where `instanceof` still holds. Kept as a function so callers do
87
+ * not have to import the class to ask the question. */
88
+ function isContextWindowExceeded(err) {
89
+ return (err instanceof ContextWindowExceededError ||
90
+ (err instanceof Error && err.code === exports.ERR_CONTEXT_WINDOW_EXCEEDED));
91
+ }
92
+ exports.isContextWindowExceeded = isContextWindowExceeded;
93
+ // ─── Detection ───────────────────────────────────────────────────────
94
+ /**
95
+ * The phrases that mean "your request was too big for the context window",
96
+ * as the four shipped wire vendors actually word them. Every one of these is
97
+ * unambiguous on its own — which is the bar for being on this list, because a
98
+ * pattern that also matches a rate limit or a `max_tokens` validation error
99
+ * would send callers to the wrong fix.
100
+ *
101
+ * openai This model's maximum context length is 8192 tokens. However,
102
+ * your messages resulted in 9000 tokens.
103
+ * openai (code) context_length_exceeded
104
+ * gateways Input tokens exceed the configured limit of 272000 tokens.
105
+ * Your messages resulted in 879073 tokens.
106
+ * anthropic prompt is too long: 250000 tokens > 200000 maximum
107
+ * anthropic input length and `max_tokens` exceed context limit:
108
+ * 195000 + 8192 > 200000
109
+ * bedrock Input is too long for requested model.
110
+ * bedrock (ValidationException carrying either anthropic phrase)
111
+ */
112
+ const CONTEXT_PHRASES = [
113
+ /context_length_exceeded/i,
114
+ /maximum context length/i,
115
+ /prompt is too long/i,
116
+ /exceed(?:s)? context limit/i,
117
+ /input (?:is )?too long for (?:the )?requested model/i,
118
+ /input tokens exceed the configured limit/i,
119
+ // "input tokens" spelled out on purpose. A gateway saying "exceeds the
120
+ // maximum allowed number of tokens" with no side named could equally be an
121
+ // OUTPUT `max_tokens` cap, which has a different fix — and a pattern that
122
+ // cannot tell those apart sends callers to the wrong one.
123
+ /exceeds? the maximum (?:allowed )?(?:number of )?input tokens/i,
124
+ ];
125
+ /** `"272,000"` → `272000`; anything unparseable → undefined. */
126
+ function num(raw) {
127
+ if (raw === undefined)
128
+ return undefined;
129
+ const value = Number(raw.replace(/[,_\s]/g, ''));
130
+ return Number.isFinite(value) && value > 0 ? value : undefined;
131
+ }
132
+ /** Pull `{ limit, actual }` out of the vendor's sentence when it stated them. */
133
+ function readNumbers(text) {
134
+ // anthropic: "prompt is too long: 250000 tokens > 200000 maximum"
135
+ const tooLong = /prompt is too long:\s*([\d,_]+)\s*tokens?\s*>\s*([\d,_]+)/i.exec(text);
136
+ if (tooLong) {
137
+ return { actualTokens: num(tooLong[1]), limitTokens: num(tooLong[2]) };
138
+ }
139
+ // anthropic / bedrock: "input length and `max_tokens` exceed context limit:
140
+ // 195000 + 8192 > 200000"
141
+ const sum = /exceed(?:s)? context limit:\s*([\d,_]+)\s*\+\s*([\d,_]+)\s*>\s*([\d,_]+)/i.exec(text);
142
+ if (sum) {
143
+ const input = num(sum[1]);
144
+ const output = num(sum[2]);
145
+ return {
146
+ ...(input !== undefined && output !== undefined && { actualTokens: input + output }),
147
+ ...(num(sum[3]) !== undefined && { limitTokens: num(sum[3]) }),
148
+ };
149
+ }
150
+ const limit = num(/maximum context length is\s*([\d,_]+)/i.exec(text)?.[1]) ??
151
+ num(/configured limit of\s*([\d,_]+)/i.exec(text)?.[1]) ??
152
+ num(/limit of\s*([\d,_]+)\s*tokens/i.exec(text)?.[1]);
153
+ const actual = num(/resulted in\s*([\d,_]+)\s*tokens/i.exec(text)?.[1]) ??
154
+ num(/requested\s*([\d,_]+)\s*tokens/i.exec(text)?.[1]) ??
155
+ num(/you (?:sent|submitted|provided)\s*([\d,_]+)\s*tokens/i.exec(text)?.[1]);
156
+ return {
157
+ ...(limit !== undefined && { limitTokens: limit }),
158
+ ...(actual !== undefined && { actualTokens: actual }),
159
+ };
160
+ }
161
+ /** Every place a vendor hides its sentence, flattened into one string. */
162
+ function textOf(err, extraText) {
163
+ const parts = [];
164
+ if (typeof extraText === 'string')
165
+ parts.push(extraText);
166
+ const seen = new Set();
167
+ let node = err;
168
+ for (let depth = 0; depth < 4 && node !== undefined && node !== null; depth++) {
169
+ if (seen.has(node))
170
+ break;
171
+ seen.add(node);
172
+ const record = node;
173
+ for (const value of [record.message, record.code, record.type, record.name]) {
174
+ if (typeof value === 'string')
175
+ parts.push(value);
176
+ }
177
+ node = record.error ?? record.cause;
178
+ }
179
+ return parts.join(' • ');
180
+ }
181
+ /** HTTP status from wherever the SDK put it. */
182
+ function statusOf(err) {
183
+ const record = err;
184
+ for (const value of [
185
+ record?.status,
186
+ record?.statusCode,
187
+ record?.$metadata?.httpStatusCode,
188
+ record?.response?.status,
189
+ ]) {
190
+ if (typeof value === 'number' && Number.isFinite(value))
191
+ return value;
192
+ }
193
+ return undefined;
194
+ }
195
+ /**
196
+ * Does this error SAY it is a context overflow, whoever produced it?
197
+ *
198
+ * The same conservative phrase test the adapters translate on, asked without
199
+ * building anything — for code that has to classify an error it did not
200
+ * catch at an adapter boundary. A custom `LLMProvider`, a gateway wrapper or
201
+ * a proxy in front of a vendor produces the vendor's sentence without ever
202
+ * passing through `wrapError`, and a caller reading that error deserves the
203
+ * same answer an adapter would have given.
204
+ *
205
+ * @see ../../core/runCheckpoint.ts — the caller this exists for
206
+ */
207
+ function looksLikeContextWindowExceeded(err, bodyText) {
208
+ if (isContextWindowExceeded(err))
209
+ return true;
210
+ const text = textOf(err, bodyText);
211
+ return text.length > 0 && CONTEXT_PHRASES.some((pattern) => pattern.test(text));
212
+ }
213
+ exports.looksLikeContextWindowExceeded = looksLikeContextWindowExceeded;
214
+ /**
215
+ * Translate a provider error into {@link ContextWindowExceededError} — or
216
+ * return `undefined`, which means "not this failure, leave it alone".
217
+ *
218
+ * Already-translated errors are returned as they are, so an adapter that
219
+ * wraps another adapter cannot double-wrap.
220
+ */
221
+ function asContextWindowExceeded(err, options) {
222
+ if (isContextWindowExceeded(err))
223
+ return err;
224
+ if (!looksLikeContextWindowExceeded(err, options.bodyText))
225
+ return undefined;
226
+ const text = textOf(err, options.bodyText);
227
+ const numbers = readNumbers(text);
228
+ // The status the SDK attached, else the one the adapter read off the
229
+ // response, else a leading `400` the vendor put in the message itself
230
+ // (several gateways do). Kept because retry policies classify on it, and a
231
+ // context overflow must never look retryable.
232
+ const status = statusOf(err) ?? options.status ?? num(/^\s*(4\d\d)\b/.exec(messageOf(err))?.[1]);
233
+ return new ContextWindowExceededError({
234
+ provider: options.provider,
235
+ providerMessage: messageOf(err) || options.bodyText || text,
236
+ ...numbers,
237
+ ...(status !== undefined && { status }),
238
+ ...(err instanceof Error && { cause: err }),
239
+ });
240
+ }
241
+ exports.asContextWindowExceeded = asContextWindowExceeded;
242
+ function messageOf(err) {
243
+ if (err instanceof Error)
244
+ return err.message;
245
+ if (typeof err === 'string')
246
+ return err;
247
+ return '';
248
+ }
249
+ // ─── The message ─────────────────────────────────────────────────────
250
+ function tokens(value) {
251
+ return value === undefined ? undefined : `${value.toLocaleString('en-US')} tokens`;
252
+ }
253
+ /**
254
+ * The teaching half. Three fixes, cheapest first, and the one thing about
255
+ * `.compaction()` that is not obvious until it fails: folding a span means
256
+ * SENDING that span to the summarizer, so compaction cannot rescue a single
257
+ * round that is already bigger than the window.
258
+ */
259
+ function buildMessage(args) {
260
+ const sent = tokens(args.actualTokens);
261
+ const limit = tokens(args.limitTokens);
262
+ const size = sent && limit
263
+ ? ` — ${sent} sent against a limit of ${limit}`
264
+ : limit
265
+ ? ` — the limit is ${limit}`
266
+ : sent
267
+ ? ` — the request came to ${sent}`
268
+ : '';
269
+ return (`[${args.provider}] the request did not fit the context window${size}. ` +
270
+ `The provider refused it before the model saw it, so nothing was generated ` +
271
+ `and re-sending the same conversation fails the same way.\n` +
272
+ ` Fix 1 — cap oversized TOOL RESULTS where they are produced. One raw ` +
273
+ `database dump returned to the model is the usual whole overrun: return a ` +
274
+ `summary plus an id the model can ask about, not every row.\n` +
275
+ ` Fix 2 — .window(slidingWindow({ keepRecentTurns: 2 })) drops older ` +
276
+ `rounds before the request is assembled, so the conversation stops growing ` +
277
+ `without bound.\n` +
278
+ ` Fix 3 — .compaction() keeps a LONG conversation small, but it cannot ` +
279
+ `fold a span that is already bigger than the window: the summarizer call ` +
280
+ `sends that span, so it fails exactly as this call did. Fix the oversized ` +
281
+ `round first, then compact.\n` +
282
+ ` Provider said: ${args.providerMessage}`);
283
+ }
284
+ //# sourceMappingURL=contextWindow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contextWindow.js","sourceRoot":"","sources":["../../../src/adapters/llm/contextWindow.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,19 @@ const ResilienceRecorder_js_1 = require("../recorders/core/ResilienceRecorder.js
44
44
  const CheckInRecorder_js_1 = require("../recorders/core/CheckInRecorder.js");
45
45
  const CompactionMeter_js_1 = require("../recorders/core/CompactionMeter.js");
46
46
  const durabilityBarrier_js_1 = require("./durabilityBarrier.js");
47
+ const toolSessions_js_1 = require("./toolSessions.js");
48
+ const eventMeta_js_1 = require("../bridge/eventMeta.js");
49
+ /**
50
+ * The pseudo-stage a tool-teardown event is stamped with.
51
+ *
52
+ * `session_closed` and `session_close_failed` fire after the run's last stage
53
+ * has committed — there is no runtimeStageId to inherit, and inventing one that
54
+ * looked like a real stage would put a fictitious node in every consumer's step
55
+ * strip. This says plainly where it came from, the way `'<stageId>#paused'`
56
+ * does at the pause boundary. Their two siblings, `session_started` and
57
+ * `session_reused`, happen inside a real stage and carry its real id.
58
+ */
59
+ const TOOL_TEARDOWN_STAGE_ID = 'tool-teardown#0';
47
60
  const EmitBridge_js_1 = require("../recorders/core/EmitBridge.js");
48
61
  const window_js_1 = require("./agent/stages/window.js");
49
62
  const deliver_js_1 = require("./agent/stages/deliver.js");
@@ -295,6 +308,9 @@ class Agent extends RunnerBase_js_1.RunnerBase {
295
308
  * default is derived from a runId, and storing that would pin a whole
296
309
  * conversation to the id of the one run that started it. */
297
310
  lastRunIdentity;
311
+ /** How long ONE tool teardown may take before the runner stops waiting.
312
+ * See `AgentOptions.toolTeardownTimeoutMs`. */
313
+ toolTeardownTimeoutMs;
298
314
  /** The run in flight, by id — the whole of the one-turn-at-a-time guard.
299
315
  * Set before the executor is built and cleared in `finally`, so a run that
300
316
  * throws does not leave the agent permanently refusing. */
@@ -476,6 +492,8 @@ class Agent extends RunnerBase_js_1.RunnerBase {
476
492
  // 8.6.0 — default `'pause'`: consent is work waiting on a person, and the
477
493
  // model is the one party that cannot click a link.
478
494
  this.onAuthorizationRequired = opts.onAuthorizationRequired ?? 'pause';
495
+ // 9.7.0 — teardown is on the SIGTERM path, so it is bounded by default.
496
+ this.toolTeardownTimeoutMs = opts.toolTeardownTimeoutMs ?? toolSessions_js_1.TOOL_TEARDOWN_TIMEOUT_MS;
479
497
  if (reliabilityConfig !== undefined)
480
498
  this.reliabilityConfig = reliabilityConfig;
481
499
  // v2.14 — Resolve thinking handler. Three states:
@@ -793,9 +811,12 @@ class Agent extends RunnerBase_js_1.RunnerBase {
793
811
  if (typeof finalized === 'string')
794
812
  this.lastRunAnswer = finalized;
795
813
  this.recordPendingQuestion(finalized);
814
+ await this.endRunToolSessions(finalized);
796
815
  return finalized;
797
816
  }
798
817
  catch (cause) {
818
+ // A THROWN pause is still a pause — see `endRunToolSessions`.
819
+ await this.endRunToolSessions(cause);
799
820
  // Wrap recoverable errors with the last-known-good checkpoint.
800
821
  // Don't wrap intentional terminal signals — let them propagate as
801
822
  // their typed shapes so callers can `instanceof` them:
@@ -1108,12 +1129,48 @@ class Agent extends RunnerBase_js_1.RunnerBase {
1108
1129
  // The question this resume answered is settled; a resume that paused
1109
1130
  // AGAIN has asked a new one, and that one is outstanding from here.
1110
1131
  this.recordPendingQuestion(finalized);
1132
+ await this.endRunToolSessions(finalized);
1111
1133
  return finalized;
1112
1134
  }
1135
+ catch (cause) {
1136
+ await this.endRunToolSessions(cause);
1137
+ throw cause;
1138
+ }
1113
1139
  finally {
1114
1140
  this.inFlightRunId = undefined;
1115
1141
  }
1116
1142
  }
1143
+ /**
1144
+ * Fire `'run'`-scoped tool teardown — IF this run really ended.
1145
+ *
1146
+ * **Not on `finally`, and that is the whole point.** `finally` runs on every
1147
+ * exit including a pause, and a pause exits TWO ways: a returned
1148
+ * `RunnerPauseOutcome` and a thrown `PauseSignal`. A check-in on a
1149
+ * code-interpreter call pauses the run so a person can approve the code —
1150
+ * tearing the sandbox down there destroys the exact state the resume needs,
1151
+ * and it fails QUIETLY, as a resumed run that "just re-ran everything".
1152
+ * Both shapes are discriminated here and both are skipped.
1153
+ *
1154
+ * An error IS a terminal: the run is over, nobody is coming back, and a
1155
+ * sandbox held by a run that crashed is the clearest kind of leak. Only a
1156
+ * pause survives.
1157
+ *
1158
+ * Fired for the TURN, not for `currentRunContext.runId` — `resume()` mints a
1159
+ * fresh run id, so a pause and its resume are one turn across two runs, and
1160
+ * filtering on the id would leave everything a paused turn opened alive
1161
+ * forever. See `ToolSessionTier.fireRun`.
1162
+ *
1163
+ * @param outcome what `run()`/`resume()` is about to return, or about to throw.
1164
+ */
1165
+ async endRunToolSessions(outcome) {
1166
+ if (!this.toolSessionTier)
1167
+ return;
1168
+ if ((0, pause_js_1.isPaused)(outcome))
1169
+ return;
1170
+ if (outcome instanceof Error && outcome.name === 'PauseSignal')
1171
+ return;
1172
+ await this.toolSessionTier.fireRun();
1173
+ }
1117
1174
  /**
1118
1175
  * The conversation this agent's LAST completed run leaves behind, packed as
1119
1176
  * the same `AgentRunCheckpoint` that `resumeOnError(...)` accepts. Store it,
@@ -1333,6 +1390,74 @@ class Agent extends RunnerBase_js_1.RunnerBase {
1333
1390
  * An open pick ACTIVATES but never moves the cursor — see the tool-calls gate.
1334
1391
  * Computed once per chart build; the injection list is fixed at construction.
1335
1392
  */
1393
+ /**
1394
+ * The identity facts this run hands `tool.execute` (9.7.0).
1395
+ *
1396
+ * Read through an ACCESSOR from the chart (see `ToolCallsHandlerDeps.currentRun`)
1397
+ * because the chart is built once and this changes every run.
1398
+ *
1399
+ * `identity` is `lastRunIdentity` — what the CALLER passed — and deliberately
1400
+ * NOT `scope.runIdentity`, which is always populated and defaults to
1401
+ * `{ conversationId: '<runId>' }`. Handing a tool a synthesized conversation
1402
+ * as "the identity" would let it key an isolated session on a fiction, and
1403
+ * would make "absent" unrepresentable at exactly the layer that most needs to
1404
+ * see it.
1405
+ */
1406
+ toolRunFacts() {
1407
+ return {
1408
+ runId: this.currentRunContext.runId,
1409
+ ...(this.currentRunContext.sessionId !== undefined && {
1410
+ sessionId: this.currentRunContext.sessionId,
1411
+ }),
1412
+ ...(this.lastRunIdentity !== undefined && { identity: this.lastRunIdentity }),
1413
+ };
1414
+ }
1415
+ /**
1416
+ * The teardown tier, built on FIRST registration.
1417
+ *
1418
+ * An agent whose tools never hold a session never allocates one, and its
1419
+ * terminals stay a single `undefined` check.
1420
+ */
1421
+ toolSessions() {
1422
+ if (!this.toolSessionTier) {
1423
+ this.toolSessionTier = new toolSessions_js_1.ToolSessionTier({
1424
+ timeoutMs: this.toolTeardownTimeoutMs,
1425
+ report: (report) => this.emitToolSessionReport(report),
1426
+ });
1427
+ }
1428
+ return this.toolSessionTier;
1429
+ }
1430
+ /**
1431
+ * Turn one TEARDOWN report into a typed `agentfootprint.tools.session_*` event.
1432
+ *
1433
+ * Only the two closing events come through here. A start and a reuse happen
1434
+ * inside `tool.execute`, where the dispatch loop still holds the scope, so
1435
+ * those ride the ordinary emit channel and carry the stage they really
1436
+ * happened in. These two fire after the run's last stage committed, and this
1437
+ * is the one place that has to answer "from where?" without a stage to point
1438
+ * at.
1439
+ *
1440
+ * **Built with `buildEventMeta`, never `minimalMeta()`.** `minimalMeta()`
1441
+ * hardcodes `runId: 'consumer-scope'`, and a teardown event stamped that way
1442
+ * cannot be joined to the run that OPENED the session — the exact
1443
+ * unjoinability 9.4.0 spent a release fixing for credential events. So the
1444
+ * meta comes from `currentRunContext`, with a STATED pseudo-stage, the same
1445
+ * move as the `'<stageId>#paused'` stamp at the pause boundary.
1446
+ */
1447
+ emitToolSessionReport(report) {
1448
+ const type = report.kind === 'closed'
1449
+ ? 'agentfootprint.tools.session_closed'
1450
+ : 'agentfootprint.tools.session_close_failed';
1451
+ const dispatcher = this.getDispatcher();
1452
+ if (!dispatcher.hasListenersFor(type))
1453
+ return;
1454
+ const { kind: _kind, ...payload } = report;
1455
+ dispatcher.dispatch({
1456
+ type,
1457
+ payload,
1458
+ meta: (0, eventMeta_js_1.buildEventMeta)({ runtimeStageId: TOOL_TEARDOWN_STAGE_ID }, this.currentRunContext),
1459
+ });
1460
+ }
1336
1461
  openSkillIds() {
1337
1462
  return this.injections
1338
1463
  .filter((i) => i.flavor === 'skill' &&
@@ -1856,6 +1981,13 @@ class Agent extends RunnerBase_js_1.RunnerBase {
1856
1981
  // toolSchemas is finalized further down; pass a getter that reads
1857
1982
  // the eventual const at stage-execution time.
1858
1983
  let toolSchemasResolved = [];
1984
+ // The stores the conversation itself is kept in — the durable anchor seed
1985
+ // resolves the turn number against. Deduplicated (several memories over
1986
+ // one store is the common shape) and reference-stable, so the scan runs
1987
+ // once per store per run.
1988
+ const conversationStores = Array.from(new Set(this.memories
1989
+ .filter((m) => m.write !== undefined && m.corpus === undefined && m.store !== undefined)
1990
+ .map((m) => m.store)));
1859
1991
  const seed = (0, seed_js_1.buildSeedStage)({
1860
1992
  maxIterations,
1861
1993
  cachingDisabled,
@@ -1874,6 +2006,12 @@ class Agent extends RunnerBase_js_1.RunnerBase {
1874
2006
  return f;
1875
2007
  },
1876
2008
  getCurrentRunId: () => this.currentRunContext?.runId,
2009
+ // WHICH TURN THIS IS (9.6.0). Only memories that WRITE the conversation
2010
+ // are consulted: they are the ones whose entry ids are turn-stamped, and
2011
+ // a corpus (`.rag(...)`, which reads under its own namespace) has no
2012
+ // turns at all. Empty list → seed stays synchronous and makes no store
2013
+ // call, so an agent without memory is unchanged.
2014
+ ...(conversationStores.length > 0 && { conversationStores }),
1877
2015
  // The `'input'` half of the message chain, run BEFORE `userMessage` and
1878
2016
  // `history` are committed — see SeedStageDeps.messageMiddleware.
1879
2017
  ...(this.messageMiddleware.length > 0 && { messageMiddleware: this.messageMiddleware }),
@@ -2038,6 +2176,13 @@ class Agent extends RunnerBase_js_1.RunnerBase {
2038
2176
  // later, so a direct field read here would be stale forever. Answers
2039
2177
  // `undefined` — no await, no microtask — until one is installed.
2040
2178
  awaitDurable: () => (0, durabilityBarrier_js_1.pendingDurableWrite)(this),
2179
+ // 9.7.0 — run/session identity and the teardown registrar. BOTH are
2180
+ // accessors for the reason `awaitDurable` is one: the chart is built once
2181
+ // at construction, and a captured value would be run #1's forever. The
2182
+ // tier one is lazy on top of that — an agent whose tools hold no sessions
2183
+ // never allocates it.
2184
+ currentRun: () => this.toolRunFacts(),
2185
+ toolSessions: () => this.toolSessions(),
2041
2186
  // 8.6.0 — what a run does when a declared credential needs 3LO consent.
2042
2187
  onAuthorizationRequired: this.onAuthorizationRequired,
2043
2188
  // The `'tell-model'` consent record travels OFF tracked state (a tracked