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.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/code/agentcore.js +294 -0
- package/dist/adapters/code/agentcore.js.map +1 -0
- package/dist/adapters/code/local.js +200 -0
- package/dist/adapters/code/local.js.map +1 -0
- package/dist/adapters/llm/AnthropicProvider.js +6 -0
- package/dist/adapters/llm/AnthropicProvider.js.map +1 -1
- package/dist/adapters/llm/BedrockProvider.js +7 -0
- package/dist/adapters/llm/BedrockProvider.js.map +1 -1
- package/dist/adapters/llm/BrowserAnthropicProvider.js +13 -0
- package/dist/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
- package/dist/adapters/llm/BrowserOpenAIProvider.js +14 -0
- package/dist/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/adapters/llm/OpenAIProvider.js +7 -0
- package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/adapters/llm/contextWindow.js +284 -0
- package/dist/adapters/llm/contextWindow.js.map +1 -0
- package/dist/core/Agent.js +145 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/RunnerBase.js +67 -0
- package/dist/core/RunnerBase.js.map +1 -1
- package/dist/core/agent/stages/seed.js +67 -11
- package/dist/core/agent/stages/seed.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +90 -0
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/codeRunnerTool.js +252 -0
- package/dist/core/codeRunnerTool.js.map +1 -0
- package/dist/core/runCheckpoint.js +102 -2
- package/dist/core/runCheckpoint.js.map +1 -1
- package/dist/core/toolSessions.js +396 -0
- package/dist/core/toolSessions.js.map +1 -0
- package/dist/core/tools.js.map +1 -1
- package/dist/doors/providers.js +13 -0
- package/dist/doors/providers.js.map +1 -1
- package/dist/esm/adapters/code/agentcore.d.ts +133 -0
- package/dist/esm/adapters/code/agentcore.js +290 -0
- package/dist/esm/adapters/code/agentcore.js.map +1 -0
- package/dist/esm/adapters/code/local.d.ts +99 -0
- package/dist/esm/adapters/code/local.js +196 -0
- package/dist/esm/adapters/code/local.js.map +1 -0
- package/dist/esm/adapters/llm/AnthropicProvider.js +6 -0
- package/dist/esm/adapters/llm/AnthropicProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BedrockProvider.js +7 -0
- package/dist/esm/adapters/llm/BedrockProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BrowserAnthropicProvider.js +13 -0
- package/dist/esm/adapters/llm/BrowserAnthropicProvider.js.map +1 -1
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js +14 -0
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/llm/OpenAIProvider.js +7 -0
- package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/llm/contextWindow.d.ts +111 -0
- package/dist/esm/adapters/llm/contextWindow.js +277 -0
- package/dist/esm/adapters/llm/contextWindow.js.map +1 -0
- package/dist/esm/adapters/types.d.ts +87 -0
- package/dist/esm/core/Agent.d.ts +65 -0
- package/dist/esm/core/Agent.js +146 -1
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/RunnerBase.d.ts +51 -0
- package/dist/esm/core/RunnerBase.js +67 -0
- package/dist/esm/core/RunnerBase.js.map +1 -1
- package/dist/esm/core/agent/stages/seed.d.ts +12 -0
- package/dist/esm/core/agent/stages/seed.js +67 -11
- package/dist/esm/core/agent/stages/seed.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.d.ts +31 -0
- package/dist/esm/core/agent/stages/toolCalls.js +90 -0
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +23 -2
- package/dist/esm/core/codeRunnerTool.d.ts +120 -0
- package/dist/esm/core/codeRunnerTool.js +247 -0
- package/dist/esm/core/codeRunnerTool.js.map +1 -0
- package/dist/esm/core/runCheckpoint.d.ts +25 -0
- package/dist/esm/core/runCheckpoint.js +100 -1
- package/dist/esm/core/runCheckpoint.js.map +1 -1
- package/dist/esm/core/toolSessions.d.ts +318 -0
- package/dist/esm/core/toolSessions.js +389 -0
- package/dist/esm/core/toolSessions.js.map +1 -0
- package/dist/esm/core/tools.d.ts +60 -0
- package/dist/esm/core/tools.js.map +1 -1
- package/dist/esm/doors/providers.d.ts +7 -0
- package/dist/esm/doors/providers.js +10 -0
- package/dist/esm/doors/providers.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +50 -0
- package/dist/esm/events/registry.d.ts +9 -1
- package/dist/esm/events/registry.js +8 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.js +11 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/mcp/mcpServe.js +37 -1
- package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
- package/dist/esm/lib/trace-toolpack/traceToolpack.js +15 -1
- package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/esm/memory/causal/writeSnapshot.d.ts +17 -4
- package/dist/esm/memory/causal/writeSnapshot.js +31 -27
- package/dist/esm/memory/causal/writeSnapshot.js.map +1 -1
- package/dist/esm/memory/define.js +4 -0
- package/dist/esm/memory/define.js.map +1 -1
- package/dist/esm/memory/define.types.d.ts +17 -0
- package/dist/esm/memory/define.types.js.map +1 -1
- package/dist/esm/memory/index.d.ts +1 -0
- package/dist/esm/memory/index.js +1 -0
- package/dist/esm/memory/index.js.map +1 -1
- package/dist/esm/memory/stages/types.d.ts +13 -3
- package/dist/esm/memory/turn/index.d.ts +7 -0
- package/dist/esm/memory/turn/index.js +11 -0
- package/dist/esm/memory/turn/index.js.map +1 -0
- package/dist/esm/memory/turn/resolveTurnNumber.d.ts +94 -0
- package/dist/esm/memory/turn/resolveTurnNumber.js +75 -0
- package/dist/esm/memory/turn/resolveTurnNumber.js.map +1 -0
- package/dist/events/registry.js +8 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp/mcpServe.js +37 -1
- package/dist/lib/mcp/mcpServe.js.map +1 -1
- package/dist/lib/trace-toolpack/traceToolpack.js +15 -1
- package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
- package/dist/memory/causal/writeSnapshot.js +31 -27
- package/dist/memory/causal/writeSnapshot.js.map +1 -1
- package/dist/memory/define.js +4 -0
- package/dist/memory/define.js.map +1 -1
- package/dist/memory/define.types.js.map +1 -1
- package/dist/memory/index.js +1 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/turn/index.js +16 -0
- package/dist/memory/turn/index.js.map +1 -0
- package/dist/memory/turn/resolveTurnNumber.js +81 -0
- package/dist/memory/turn/resolveTurnNumber.js.map +1 -0
- package/dist/types/adapters/code/agentcore.d.ts +134 -0
- package/dist/types/adapters/code/agentcore.d.ts.map +1 -0
- package/dist/types/adapters/code/local.d.ts +100 -0
- package/dist/types/adapters/code/local.d.ts.map +1 -0
- package/dist/types/adapters/llm/AnthropicProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BedrockProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BrowserAnthropicProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/BrowserOpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/contextWindow.d.ts +112 -0
- package/dist/types/adapters/llm/contextWindow.d.ts.map +1 -0
- package/dist/types/adapters/types.d.ts +87 -0
- package/dist/types/adapters/types.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +65 -0
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/RunnerBase.d.ts +51 -0
- package/dist/types/core/RunnerBase.d.ts.map +1 -1
- package/dist/types/core/agent/stages/seed.d.ts +12 -0
- package/dist/types/core/agent/stages/seed.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts +31 -0
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +23 -2
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/codeRunnerTool.d.ts +121 -0
- package/dist/types/core/codeRunnerTool.d.ts.map +1 -0
- package/dist/types/core/runCheckpoint.d.ts +25 -0
- package/dist/types/core/runCheckpoint.d.ts.map +1 -1
- package/dist/types/core/toolSessions.d.ts +319 -0
- package/dist/types/core/toolSessions.d.ts.map +1 -0
- package/dist/types/core/tools.d.ts +60 -0
- package/dist/types/core/tools.d.ts.map +1 -1
- package/dist/types/doors/providers.d.ts +7 -0
- package/dist/types/doors/providers.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +50 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +9 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
- package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
- package/dist/types/memory/causal/writeSnapshot.d.ts +17 -4
- package/dist/types/memory/causal/writeSnapshot.d.ts.map +1 -1
- package/dist/types/memory/define.d.ts.map +1 -1
- package/dist/types/memory/define.types.d.ts +17 -0
- package/dist/types/memory/define.types.d.ts.map +1 -1
- package/dist/types/memory/index.d.ts +1 -0
- package/dist/types/memory/index.d.ts.map +1 -1
- package/dist/types/memory/stages/types.d.ts +13 -3
- package/dist/types/memory/stages/types.d.ts.map +1 -1
- package/dist/types/memory/turn/index.d.ts +8 -0
- package/dist/types/memory/turn/index.d.ts.map +1 -0
- package/dist/types/memory/turn/resolveTurnNumber.d.ts +95 -0
- package/dist/types/memory/turn/resolveTurnNumber.d.ts.map +1 -0
- 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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"}
|
package/dist/core/Agent.js
CHANGED
|
@@ -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
|