@e2edev/e2e 0.10.0 → 0.11.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/README.md +11 -5
- package/dist/agent/act-validation.d.ts +2 -0
- package/dist/agent/act-validation.d.ts.map +1 -1
- package/dist/agent/act-validation.js +1 -1
- package/dist/agent/act-validation.js.map +1 -1
- package/dist/agent/act.d.ts.map +1 -1
- package/dist/agent/act.js +14 -0
- package/dist/agent/act.js.map +1 -1
- package/dist/agent/ai-sdk.d.ts +2 -2
- package/dist/agent/ai-sdk.d.ts.map +1 -1
- package/dist/agent/ai-sdk.js +3 -4
- package/dist/agent/ai-sdk.js.map +1 -1
- package/dist/agent/default-agent.d.ts +17 -2
- package/dist/agent/default-agent.d.ts.map +1 -1
- package/dist/agent/default-agent.js +17 -3
- package/dist/agent/default-agent.js.map +1 -1
- package/dist/agent/error.d.ts.map +1 -1
- package/dist/agent/error.js +1 -0
- package/dist/agent/error.js.map +1 -1
- package/dist/agent/executor.d.ts +13 -0
- package/dist/agent/executor.d.ts.map +1 -1
- package/dist/agent/executor.js.map +1 -1
- package/dist/agent/model/adapter.d.ts +3 -0
- package/dist/agent/model/adapter.d.ts.map +1 -1
- package/dist/agent/model/adapter.js.map +1 -1
- package/dist/agent/model/overflow.d.ts +20 -0
- package/dist/agent/model/overflow.d.ts.map +1 -0
- package/dist/agent/model/overflow.js +82 -0
- package/dist/agent/model/overflow.js.map +1 -0
- package/dist/agent/model/prompt-cache.d.ts +47 -0
- package/dist/agent/model/prompt-cache.d.ts.map +1 -0
- package/dist/agent/model/prompt-cache.js +78 -0
- package/dist/agent/model/prompt-cache.js.map +1 -0
- package/dist/agent/model/sdk.d.ts +41 -24
- package/dist/agent/model/sdk.d.ts.map +1 -1
- package/dist/agent/model/sdk.js +64 -91
- package/dist/agent/model/sdk.js.map +1 -1
- package/dist/agent/primitives.d.ts.map +1 -1
- package/dist/agent/primitives.js +2 -1
- package/dist/agent/primitives.js.map +1 -1
- package/dist/agent/public.d.ts +1 -1
- package/dist/agent/public.d.ts.map +1 -1
- package/dist/agent/public.js.map +1 -1
- package/dist/agent/screen-update.d.ts +8 -3
- package/dist/agent/screen-update.d.ts.map +1 -1
- package/dist/agent/screen-update.js +18 -5
- package/dist/agent/screen-update.js.map +1 -1
- package/dist/agent/tool-loop.d.ts.map +1 -1
- package/dist/agent/tool-loop.js +149 -33
- package/dist/agent/tool-loop.js.map +1 -1
- package/dist/agent/tool-output.d.ts +31 -0
- package/dist/agent/tool-output.d.ts.map +1 -0
- package/dist/agent/tool-output.js +60 -0
- package/dist/agent/tool-output.js.map +1 -0
- package/dist/agent/tool.d.ts +9 -3
- package/dist/agent/tool.d.ts.map +1 -1
- package/dist/agent/tool.js +2 -2
- package/dist/agent/tool.js.map +1 -1
- package/dist/agent/usage.d.ts +7 -0
- package/dist/agent/usage.d.ts.map +1 -1
- package/dist/agent/usage.js +11 -0
- package/dist/agent/usage.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +119 -34
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/engines.d.ts +2 -2
- package/dist/cli/init/engines.js +3 -3
- package/dist/cli/init/gateways.d.ts +22 -0
- package/dist/cli/init/gateways.d.ts.map +1 -0
- package/dist/cli/init/gateways.js +50 -0
- package/dist/cli/init/gateways.js.map +1 -0
- package/dist/cli/init/scaffold.d.ts +7 -1
- package/dist/cli/init/scaffold.d.ts.map +1 -1
- package/dist/cli/init/scaffold.js +21 -10
- package/dist/cli/init/scaffold.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +51 -7
- package/dist/cli/init.js.map +1 -1
- package/dist/collect/collect.d.ts +7 -0
- package/dist/collect/collect.d.ts.map +1 -1
- package/dist/collect/collect.js +16 -0
- package/dist/collect/collect.js.map +1 -1
- package/dist/collect/registry.d.ts.map +1 -1
- package/dist/collect/registry.js +10 -4
- package/dist/collect/registry.js.map +1 -1
- package/dist/config/agent.d.ts +13 -32
- package/dist/config/agent.d.ts.map +1 -1
- package/dist/config/agent.js +32 -123
- package/dist/config/agent.js.map +1 -1
- package/dist/config/resolve.js +1 -1
- package/dist/explore/body.d.ts +36 -0
- package/dist/explore/body.d.ts.map +1 -0
- package/dist/explore/body.js +168 -0
- package/dist/explore/body.js.map +1 -0
- package/dist/explore/executor.d.ts +25 -0
- package/dist/explore/executor.d.ts.map +1 -0
- package/dist/explore/executor.js +86 -0
- package/dist/explore/executor.js.map +1 -0
- package/dist/explore/index.d.ts +64 -0
- package/dist/explore/index.d.ts.map +1 -0
- package/dist/explore/index.js +183 -0
- package/dist/explore/index.js.map +1 -0
- package/dist/explore/plan.d.ts +74 -0
- package/dist/explore/plan.d.ts.map +1 -0
- package/dist/explore/plan.js +149 -0
- package/dist/explore/plan.js.map +1 -0
- package/dist/explore/reporter.d.ts +11 -0
- package/dist/explore/reporter.d.ts.map +1 -0
- package/dist/explore/reporter.js +54 -0
- package/dist/explore/reporter.js.map +1 -0
- package/dist/explore/state.d.ts +58 -0
- package/dist/explore/state.d.ts.map +1 -0
- package/dist/explore/state.js +147 -0
- package/dist/explore/state.js.map +1 -0
- package/dist/report/build.d.ts +53 -0
- package/dist/report/build.d.ts.map +1 -1
- package/dist/report/build.js +10 -1
- package/dist/report/build.js.map +1 -1
- package/dist/report/debug-steps.d.ts.map +1 -1
- package/dist/report/debug-steps.js +15 -0
- package/dist/report/debug-steps.js.map +1 -1
- package/dist/report/format.d.ts +11 -1
- package/dist/report/format.d.ts.map +1 -1
- package/dist/report/format.js +15 -3
- package/dist/report/format.js.map +1 -1
- package/dist/run/events.d.ts +2 -2
- package/dist/run/events.d.ts.map +1 -1
- package/dist/run/in-process.d.ts +8 -0
- package/dist/run/in-process.d.ts.map +1 -1
- package/dist/run/in-process.js +3 -3
- package/dist/run/in-process.js.map +1 -1
- package/dist/run/runner.d.ts +20 -1
- package/dist/run/runner.d.ts.map +1 -1
- package/dist/run/runner.js +19 -14
- package/dist/run/runner.js.map +1 -1
- package/dist/run/steps.d.ts +7 -0
- package/dist/run/steps.d.ts.map +1 -1
- package/dist/run/steps.js.map +1 -1
- package/dist/run/worker-models.d.ts +4 -4
- package/dist/run/worker-models.js +6 -13
- package/dist/run/worker-models.js.map +1 -1
- package/dist/telemetry/events.d.ts.map +1 -1
- package/dist/telemetry/events.js +17 -2
- package/dist/telemetry/events.js.map +1 -1
- package/dist/types.d.ts +12 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -2
- package/skills/e2e/SKILL.md +11 -4
- package/skills/e2e/references/agent.md +19 -14
- package/skills/e2e/references/debugging.md +2 -1
- package/skills/e2e/references/explore.md +83 -0
- package/skills/e2e/references/running.md +4 -3
- package/skills/e2e/references/setup.md +10 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/agent/model/adapter.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAI9B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/agent/model/adapter.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAI9B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAyEzC;;;;GAIG;AACH,MAAM,OAAO,uBAAwB,SAAQ,UAAU;IAC5C,OAAO,CAAqB;IAErC,YAAY,KAAa,EAAE,OAAO,GAA0C,EAAE;QAC5E,KAAK,CAAC,sBAAsB,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAClG,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACjC,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC;AACnD,CAAC;AAED,+EAA+E;AAC/E,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAwC;IAC3E,OAAO,CACL,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC;QACnD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,CACrD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recognizes a context-window overflow in a provider failure. Providers say
|
|
3
|
+
* it in as many ways as there are providers, and a gateway forwards their
|
|
4
|
+
* words; the patterns below are the ones seen in the wild (ported from the
|
|
5
|
+
* pi agent harness, which collected them across twenty providers), plus the
|
|
6
|
+
* HTTP 413 some of them answer with instead of a message.
|
|
7
|
+
*
|
|
8
|
+
* The runner reacts to an overflow differently from any other provider
|
|
9
|
+
* failure: the request was too big, so a smaller request can still succeed,
|
|
10
|
+
* where a 5xx or a rate limit needs only time.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Whether a provider failure says the request exceeded the model's context
|
|
14
|
+
* window. Reads the message, the HTTP status, and the raw response body of
|
|
15
|
+
* the error and of everything it wraps (`cause`, or the last attempt of a
|
|
16
|
+
* spent retry chain), so a gateway or retry wrapper does not hide the
|
|
17
|
+
* provider's words.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isContextOverflow(error: unknown): boolean;
|
|
20
|
+
//# sourceMappingURL=overflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../../src/agent/model/overflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAwCH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASzD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recognizes a context-window overflow in a provider failure. Providers say
|
|
3
|
+
* it in as many ways as there are providers, and a gateway forwards their
|
|
4
|
+
* words; the patterns below are the ones seen in the wild (ported from the
|
|
5
|
+
* pi agent harness, which collected them across twenty providers), plus the
|
|
6
|
+
* HTTP 413 some of them answer with instead of a message.
|
|
7
|
+
*
|
|
8
|
+
* The runner reacts to an overflow differently from any other provider
|
|
9
|
+
* failure: the request was too big, so a smaller request can still succeed,
|
|
10
|
+
* where a 5xx or a rate limit needs only time.
|
|
11
|
+
*/
|
|
12
|
+
const OVERFLOW_PATTERNS = [
|
|
13
|
+
/prompt is too long/i, // Anthropic
|
|
14
|
+
/request_too_large/i, // Anthropic (HTTP 413)
|
|
15
|
+
/input is too long for requested model/i, // Amazon Bedrock
|
|
16
|
+
/exceeds the context window/i, // OpenAI
|
|
17
|
+
/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\d,]+ tokens?|\s*\([\d,]+\))/i, // OpenAI-compatible proxies
|
|
18
|
+
/input token count.*exceeds the maximum/i, // Google
|
|
19
|
+
/maximum prompt length is \d+/i, // xAI
|
|
20
|
+
/reduce the length of the messages/i, // Groq
|
|
21
|
+
/maximum context length is \d+ tokens/i, // OpenRouter
|
|
22
|
+
/exceeds (?:the )?maximum allowed input length of [\d,]+ tokens?/i, // OpenRouter/Poolside
|
|
23
|
+
/input \(\d+ tokens\) is longer than the model'?s context length \(\d+ tokens\)/i, // Together AI
|
|
24
|
+
/exceeds the limit of \d+/i, // GitHub Copilot
|
|
25
|
+
/exceeds the available context size/i, // llama.cpp
|
|
26
|
+
/greater than the context length/i, // LM Studio
|
|
27
|
+
/context window exceeds limit/i, // MiniMax
|
|
28
|
+
/exceeded model token limit/i, // Kimi
|
|
29
|
+
/too large for model with \d+ maximum context length/i, // Mistral
|
|
30
|
+
/prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i, // DS4
|
|
31
|
+
/model_context_window_exceeded/i, // z.ai
|
|
32
|
+
/prompt too long; exceeded (?:max )?context length/i, // Ollama
|
|
33
|
+
/range of input length should be/i, // DashScope / Qwen
|
|
34
|
+
/context[_ ]length[_ ]exceeded/i, // generic
|
|
35
|
+
/too many tokens/i, // generic
|
|
36
|
+
/token limit exceeded/i, // generic
|
|
37
|
+
];
|
|
38
|
+
/** Failures that mention tokens without being an overflow: throttling and its cousins. */
|
|
39
|
+
const NON_OVERFLOW_PATTERNS = [
|
|
40
|
+
/throttl/i, // Amazon Bedrock: "ThrottlingException: Too many tokens, please wait…"
|
|
41
|
+
/service unavailable/i,
|
|
42
|
+
/rate limit/i,
|
|
43
|
+
/too many requests/i,
|
|
44
|
+
];
|
|
45
|
+
/** Longest cause chain walked; a wrapped error rarely nests deeper. */
|
|
46
|
+
const MAX_CAUSE_DEPTH = 8;
|
|
47
|
+
/**
|
|
48
|
+
* Whether a provider failure says the request exceeded the model's context
|
|
49
|
+
* window. Reads the message, the HTTP status, and the raw response body of
|
|
50
|
+
* the error and of everything it wraps (`cause`, or the last attempt of a
|
|
51
|
+
* spent retry chain), so a gateway or retry wrapper does not hide the
|
|
52
|
+
* provider's words.
|
|
53
|
+
*/
|
|
54
|
+
export function isContextOverflow(error) {
|
|
55
|
+
let current = error;
|
|
56
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null; depth += 1) {
|
|
57
|
+
if (describesOverflow(current))
|
|
58
|
+
return true;
|
|
59
|
+
if (typeof current !== 'object')
|
|
60
|
+
return false;
|
|
61
|
+
const wrapper = current;
|
|
62
|
+
current = wrapper.cause ?? wrapper.lastError;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* One error object, read on its own. HTTP 413 is an overflow whatever the
|
|
68
|
+
* text says. A text field counts when it matches an overflow pattern and no
|
|
69
|
+
* throttling pattern; the veto is per field, so a wrapper's "rate limit"
|
|
70
|
+
* message cannot hide the provider's "prompt is too long" in the body.
|
|
71
|
+
*/
|
|
72
|
+
function describesOverflow(error) {
|
|
73
|
+
if (typeof error !== 'object' || error === null)
|
|
74
|
+
return false;
|
|
75
|
+
const record = error;
|
|
76
|
+
if ((record.statusCode ?? record.status) === 413)
|
|
77
|
+
return true;
|
|
78
|
+
return [record.message, record.responseBody].some((text) => typeof text === 'string' &&
|
|
79
|
+
OVERFLOW_PATTERNS.some((pattern) => pattern.test(text)) &&
|
|
80
|
+
!NON_OVERFLOW_PATTERNS.some((pattern) => pattern.test(text)));
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=overflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overflow.js","sourceRoot":"","sources":["../../../src/agent/model/overflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,iBAAiB,GAAsB;IAC3C,qBAAqB,EAAE,YAAY;IACnC,oBAAoB,EAAE,uBAAuB;IAC7C,wCAAwC,EAAE,iBAAiB;IAC3D,6BAA6B,EAAE,SAAS;IACxC,4FAA4F,EAAE,4BAA4B;IAC1H,yCAAyC,EAAE,SAAS;IACpD,+BAA+B,EAAE,MAAM;IACvC,oCAAoC,EAAE,OAAO;IAC7C,uCAAuC,EAAE,aAAa;IACtD,kEAAkE,EAAE,sBAAsB;IAC1F,iFAAiF,EAAE,cAAc;IACjG,2BAA2B,EAAE,iBAAiB;IAC9C,qCAAqC,EAAE,YAAY;IACnD,kCAAkC,EAAE,YAAY;IAChD,+BAA+B,EAAE,UAAU;IAC3C,6BAA6B,EAAE,OAAO;IACtC,sDAAsD,EAAE,UAAU;IAClE,+EAA+E,EAAE,MAAM;IACvF,gCAAgC,EAAE,OAAO;IACzC,oDAAoD,EAAE,SAAS;IAC/D,kCAAkC,EAAE,mBAAmB;IACvD,gCAAgC,EAAE,UAAU;IAC5C,kBAAkB,EAAE,UAAU;IAC9B,uBAAuB,EAAE,UAAU;CACpC,CAAC;AAEF,0FAA0F;AAC1F,MAAM,qBAAqB,GAAsB;IAC/C,UAAU,EAAE,uEAAuE;IACnF,sBAAsB;IACtB,aAAa;IACb,oBAAoB;CACrB,CAAC;AAEF,uEAAuE;AACvE,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,eAAe,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrG,IAAI,iBAAiB,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5C,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC9C,MAAM,OAAO,GAAG,OAAmD,CAAC;QACpE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,SAAS,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,MAAM,GAAG,KAA8F,CAAC;IAC9G,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAC/C,CAAC,IAAI,EAAE,EAAE,CACP,OAAO,IAAI,KAAK,QAAQ;QACxB,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAC/D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt-cache hints: what a request carries so the provider can serve the
|
|
3
|
+
* repeated prefix (system prompt, tool definitions, the conversation so far)
|
|
4
|
+
* from its cache instead of reading it again at full price.
|
|
5
|
+
*
|
|
6
|
+
* Anthropic caches only up to an explicit breakpoint, so the system prompt
|
|
7
|
+
* carries one (it covers the tool definitions ahead of it) and the newest
|
|
8
|
+
* message carries the other: the next turn's request then matches everything
|
|
9
|
+
* up to it. OpenAI caches prefixes on its own and takes a routing key; one
|
|
10
|
+
* key per system prompt sends every call of a run to the same cache. Other
|
|
11
|
+
* providers get nothing extra, and the request is exactly what it was.
|
|
12
|
+
*/
|
|
13
|
+
import type { ModelMessage, SystemModelMessage } from 'ai';
|
|
14
|
+
import type { ProviderOptions } from '../../types.ts';
|
|
15
|
+
export type CacheFamily = 'anthropic' | 'openai';
|
|
16
|
+
/** What the hints need to know about the model: the provider and model id the SDK reports. */
|
|
17
|
+
export interface CacheModelRef {
|
|
18
|
+
readonly provider?: string | undefined;
|
|
19
|
+
readonly modelId?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The provider family a model routes to. A gateway model names its upstream
|
|
23
|
+
* in the model id (`anthropic/claude-…`); a direct provider names it in the
|
|
24
|
+
* provider (`anthropic.messages`, `openai.responses`).
|
|
25
|
+
*/
|
|
26
|
+
export declare function cacheFamily(model: CacheModelRef | undefined): CacheFamily | undefined;
|
|
27
|
+
export interface PromptCacheHints {
|
|
28
|
+
readonly family: CacheFamily | undefined;
|
|
29
|
+
/** The system prompt as the request's instructions, carrying a breakpoint where the provider needs one. */
|
|
30
|
+
instructions(system: string): string | SystemModelMessage;
|
|
31
|
+
/**
|
|
32
|
+
* Request-level provider options: the caller's own, plus a prompt-cache
|
|
33
|
+
* routing key where the provider takes one. The caller's values win.
|
|
34
|
+
*/
|
|
35
|
+
providerOptions(base: ProviderOptions | undefined, system: string): ProviderOptions | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Moves the conversation breakpoint to the newest message. Every other
|
|
38
|
+
* message loses its breakpoint, so a history that carries forward across
|
|
39
|
+
* turns never accumulates more than the provider allows.
|
|
40
|
+
*/
|
|
41
|
+
markLatest(messages: ModelMessage[]): ModelMessage[];
|
|
42
|
+
}
|
|
43
|
+
/** The hints for one model; a no-op for providers without a cache the request can address. */
|
|
44
|
+
export declare function promptCacheHints(model: CacheModelRef | undefined): PromptCacheHints;
|
|
45
|
+
/** A stable key for one system prompt, so every call sharing the prefix routes alike. */
|
|
46
|
+
export declare function promptCacheKey(system: string): string;
|
|
47
|
+
//# sourceMappingURL=prompt-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-cache.d.ts","sourceRoot":"","sources":["../../../src/agent/model/prompt-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,IAAI,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEjD,8FAA8F;AAC9F,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAMrF;AAID,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,2GAA2G;IAC3G,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,CAAC;IAC1D;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAChG;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAAC;CACtD;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,gBAAgB,CAiBnF;AAED,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt-cache hints: what a request carries so the provider can serve the
|
|
3
|
+
* repeated prefix (system prompt, tool definitions, the conversation so far)
|
|
4
|
+
* from its cache instead of reading it again at full price.
|
|
5
|
+
*
|
|
6
|
+
* Anthropic caches only up to an explicit breakpoint, so the system prompt
|
|
7
|
+
* carries one (it covers the tool definitions ahead of it) and the newest
|
|
8
|
+
* message carries the other: the next turn's request then matches everything
|
|
9
|
+
* up to it. OpenAI caches prefixes on its own and takes a routing key; one
|
|
10
|
+
* key per system prompt sends every call of a run to the same cache. Other
|
|
11
|
+
* providers get nothing extra, and the request is exactly what it was.
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
/**
|
|
15
|
+
* The provider family a model routes to. A gateway model names its upstream
|
|
16
|
+
* in the model id (`anthropic/claude-…`); a direct provider names it in the
|
|
17
|
+
* provider (`anthropic.messages`, `openai.responses`).
|
|
18
|
+
*/
|
|
19
|
+
export function cacheFamily(model) {
|
|
20
|
+
const provider = (model?.provider ?? '').toLowerCase();
|
|
21
|
+
const modelId = (model?.modelId ?? '').toLowerCase();
|
|
22
|
+
if (modelId.startsWith('anthropic/') || provider.startsWith('anthropic'))
|
|
23
|
+
return 'anthropic';
|
|
24
|
+
if (modelId.startsWith('openai/') || provider.startsWith('openai'))
|
|
25
|
+
return 'openai';
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const ANTHROPIC_BREAKPOINT = { cacheControl: { type: 'ephemeral' } };
|
|
29
|
+
/** The hints for one model; a no-op for providers without a cache the request can address. */
|
|
30
|
+
export function promptCacheHints(model) {
|
|
31
|
+
const family = cacheFamily(model);
|
|
32
|
+
return {
|
|
33
|
+
family,
|
|
34
|
+
instructions: (system) => family === 'anthropic'
|
|
35
|
+
? { role: 'system', content: system, providerOptions: { anthropic: ANTHROPIC_BREAKPOINT } }
|
|
36
|
+
: system,
|
|
37
|
+
providerOptions: (base, system) => {
|
|
38
|
+
if (family !== 'openai')
|
|
39
|
+
return base;
|
|
40
|
+
return {
|
|
41
|
+
...base,
|
|
42
|
+
openai: { promptCacheKey: promptCacheKey(system), ...base?.['openai'] },
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
markLatest: (messages) => (family === 'anthropic' ? moveBreakpoint(messages) : messages),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** A stable key for one system prompt, so every call sharing the prefix routes alike. */
|
|
49
|
+
export function promptCacheKey(system) {
|
|
50
|
+
return `e2e-${createHash('sha256').update(system).digest('hex').slice(0, 16)}`;
|
|
51
|
+
}
|
|
52
|
+
function moveBreakpoint(messages) {
|
|
53
|
+
if (messages.length === 0)
|
|
54
|
+
return messages;
|
|
55
|
+
const last = messages.length - 1;
|
|
56
|
+
return messages.map((message, index) => (index === last ? withBreakpoint(message) : withoutBreakpoint(message)));
|
|
57
|
+
}
|
|
58
|
+
function withBreakpoint(message) {
|
|
59
|
+
const anthropic = message.providerOptions?.['anthropic'];
|
|
60
|
+
return {
|
|
61
|
+
...message,
|
|
62
|
+
providerOptions: { ...message.providerOptions, anthropic: { ...anthropic, ...ANTHROPIC_BREAKPOINT } },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function withoutBreakpoint(message) {
|
|
66
|
+
const anthropic = message.providerOptions?.['anthropic'];
|
|
67
|
+
if (anthropic === undefined || !('cacheControl' in anthropic))
|
|
68
|
+
return message;
|
|
69
|
+
const { cacheControl: _dropped, ...rest } = anthropic;
|
|
70
|
+
const { anthropic: _anthropic, ...others } = message.providerOptions ?? {};
|
|
71
|
+
const providerOptions = Object.keys(rest).length === 0 ? others : { ...others, anthropic: rest };
|
|
72
|
+
if (Object.keys(providerOptions).length === 0) {
|
|
73
|
+
const { providerOptions: _none, ...bare } = message;
|
|
74
|
+
return bare;
|
|
75
|
+
}
|
|
76
|
+
return { ...message, providerOptions };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=prompt-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-cache.js","sourceRoot":"","sources":["../../../src/agent/model/prompt-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AI SDK adapter. One implementation serves every
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* AI SDK adapter. One implementation serves every provider: the
|
|
3
|
+
* caller-supplied AI SDK model instance (`gateway('openai/gpt-5.4-mini')`,
|
|
4
|
+
* `openrouter(...)`, `openai('gpt-4o')`, a local provider, a scripted test
|
|
5
|
+
* model) is used as is. Everything after the model — bounded requests,
|
|
6
|
+
* closed-grammar validation, usage and error translation — is
|
|
7
|
+
* provider-independent.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import type { ResolvedModel, SdkLanguageModel } from '../../config/agent.ts';
|
|
10
10
|
import { type ModelAdapter } from './adapter.ts';
|
|
11
11
|
/**
|
|
12
12
|
* Provider transport retries; distinct from runner-owned model-call budget.
|
|
@@ -23,30 +23,47 @@ export declare const TRANSPORT_RETRIES = 5;
|
|
|
23
23
|
/** Creates the adapter for one resolved model, or fails with MODEL_UNAVAILABLE. */
|
|
24
24
|
export declare function createModelAdapter(model: ResolvedModel | undefined): ModelAdapter;
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* Gateway references require the AI SDK to be loaded (loadAiSdk) first; model
|
|
30
|
-
* instances never touch it.
|
|
26
|
+
* The bare AI SDK language model of one resolved model, for callers that
|
|
27
|
+
* drive the SDK directly (the default step executor) rather than through the
|
|
28
|
+
* adapter.
|
|
31
29
|
*/
|
|
32
30
|
export declare function instantiateLanguageModel(model: ResolvedModel): SdkLanguageModel;
|
|
31
|
+
/** The AI SDK usage fields the runner reads, structurally. */
|
|
32
|
+
export interface SdkUsage {
|
|
33
|
+
readonly inputTokens?: number | undefined;
|
|
34
|
+
readonly outputTokens?: number | undefined;
|
|
35
|
+
readonly inputTokenDetails?: {
|
|
36
|
+
readonly cacheReadTokens?: number | undefined;
|
|
37
|
+
readonly cacheWriteTokens?: number | undefined;
|
|
38
|
+
} | undefined;
|
|
39
|
+
}
|
|
33
40
|
/**
|
|
34
|
-
* The
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
|
|
41
|
+
* The prompt-cache split of one call's input, when the provider reported it.
|
|
42
|
+
* Providers that cache nothing report zeros; providers that do not report the
|
|
43
|
+
* split leave the fields undefined, and so does the report.
|
|
44
|
+
*/
|
|
45
|
+
export declare function cacheTokenFields(usage: SdkUsage | undefined): {
|
|
46
|
+
cacheReadTokens?: number;
|
|
47
|
+
cacheWriteTokens?: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Per-request cost, where the provider reports one in its metadata. The
|
|
51
|
+
* Vercel AI Gateway's `cost` is what it bills; BYOK routes bill the provider
|
|
52
|
+
* key directly and report `cost: "0"`, so fall back to `marketCost`, the
|
|
53
|
+
* list-price estimate of the same request. OpenRouter reports `usage.cost`
|
|
54
|
+
* when its provider is asked to account usage. Other providers simply lack
|
|
55
|
+
* the key.
|
|
38
56
|
*/
|
|
39
57
|
export declare function readCost(metadata: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined): number | undefined;
|
|
40
58
|
/**
|
|
41
|
-
* A rejected credential
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* has done by the time a provider call has failed.
|
|
59
|
+
* A rejected credential is named for what it is. The model instance owns its
|
|
60
|
+
* credential, read from the provider package's own variable
|
|
61
|
+
* (`AI_GATEWAY_API_KEY`, `OPENROUTER_API_KEY`, ...) or passed at
|
|
62
|
+
* construction, so the runner can only say that the provider refused it.
|
|
63
|
+
* Requires the SDK to be loaded, which every caller has done by the time a
|
|
64
|
+
* provider call has failed.
|
|
48
65
|
*/
|
|
49
|
-
export declare function credentialHint(cause: unknown
|
|
66
|
+
export declare function credentialHint(cause: unknown): string;
|
|
50
67
|
/**
|
|
51
68
|
* True when a provider call ended by abort or timeout rather than by a
|
|
52
69
|
* provider answer, including a retry chain the deadline cut short. Requires
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../../src/agent/model/sdk.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../../src/agent/model/sdk.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAM7E,OAAO,EAIL,KAAK,YAAY,EAKlB,MAAM,cAAc,CAAC;AAEtB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,YAAY,CAuFjF;AAsBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,CAE/E;AAUD,8DAA8D;AAC9D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,iBAAiB,CAAC,EACvB;QACE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC9C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAChD,GACD,SAAS,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,GAAG,SAAS,GAC1B;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,CAMzD;AAqCD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,GAChF,MAAM,GAAG,SAAS,CAOpB;AA6DD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYrD;AAaD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAI/C"}
|
package/dist/agent/model/sdk.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AI SDK adapter. One implementation serves every
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* AI SDK adapter. One implementation serves every provider: the
|
|
3
|
+
* caller-supplied AI SDK model instance (`gateway('openai/gpt-5.4-mini')`,
|
|
4
|
+
* `openrouter(...)`, `openai('gpt-4o')`, a local provider, a scripted test
|
|
5
|
+
* model) is used as is. Everything after the model — bounded requests,
|
|
6
|
+
* closed-grammar validation, usage and error translation — is
|
|
7
|
+
* provider-independent.
|
|
8
8
|
*/
|
|
9
9
|
import { withHint } from '../../internal/errors.js';
|
|
10
|
-
import { GATEWAY_API_KEY_ENV } from '../../config/agent.js';
|
|
11
10
|
import { aiSdk, loadAiSdk } from '../ai-sdk.js';
|
|
12
11
|
import { packageVersion } from '../../internal/package-version.js';
|
|
13
12
|
import { AgentError } from '../error.js';
|
|
13
|
+
import { isContextOverflow } from './overflow.js';
|
|
14
|
+
import { promptCacheHints } from './prompt-cache.js';
|
|
14
15
|
import { imageTokenUpperBound, ModelOutputInvalidError, tokenUpperBound, } from './adapter.js';
|
|
15
|
-
/** Default AI Gateway base URL used when no endpoint override is configured. */
|
|
16
|
-
const DEFAULT_GATEWAY_ENDPOINT = 'https://ai-gateway.vercel.sh/v4/ai';
|
|
17
|
-
const PROVIDER_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
18
16
|
/**
|
|
19
17
|
* Provider transport retries; distinct from runner-owned model-call budget.
|
|
20
18
|
*
|
|
@@ -30,23 +28,22 @@ export const TRANSPORT_RETRIES = 5;
|
|
|
30
28
|
/** Creates the adapter for one resolved model, or fails with MODEL_UNAVAILABLE. */
|
|
31
29
|
export function createModelAdapter(model) {
|
|
32
30
|
if (model === undefined) {
|
|
33
|
-
throw new AgentError('MODEL_UNAVAILABLE', 'the agent fixture requires a model: pass
|
|
31
|
+
throw new AgentError('MODEL_UNAVAILABLE', 'the agent fixture requires a model: pass an AI SDK model instance to createAgent({ model }) or set agent.model');
|
|
34
32
|
}
|
|
35
|
-
const { endpoint, flavor } = validateModel(model);
|
|
36
33
|
const adapterVersion = packageVersion(import.meta.url, '../../../package.json', '0.0.0');
|
|
37
|
-
|
|
38
|
-
// first call, after the loader has resolved (or clearly refused) it.
|
|
39
|
-
let languageModel;
|
|
34
|
+
const languageModel = model.model;
|
|
40
35
|
return {
|
|
41
36
|
provenance: {
|
|
42
37
|
provider: model.provider,
|
|
43
38
|
model: model.id,
|
|
44
|
-
endpoint
|
|
45
|
-
|
|
39
|
+
// The instance owns its transport; the report records that the endpoint
|
|
40
|
+
// is whatever the provider package was configured with.
|
|
41
|
+
endpoint: 'provider-default',
|
|
42
|
+
adapterVersion: `ai-sdk/${adapterVersion}`,
|
|
46
43
|
},
|
|
47
44
|
async generate(call) {
|
|
48
45
|
const { generateText, jsonSchema, Output } = await loadAiSdk();
|
|
49
|
-
|
|
46
|
+
const cache = promptCacheHints(languageModel);
|
|
50
47
|
const images = call.images ?? [];
|
|
51
48
|
const inputBound = tokenUpperBound(call.system) +
|
|
52
49
|
tokenUpperBound(call.prompt) +
|
|
@@ -56,9 +53,12 @@ export function createModelAdapter(model) {
|
|
|
56
53
|
}
|
|
57
54
|
let issue;
|
|
58
55
|
const schema = call.schema;
|
|
56
|
+
// The policy prefix is what every judgment call of a run shares, so it
|
|
57
|
+
// is where the prompt cache is addressed; the prompt itself is one-off.
|
|
58
|
+
const providerOptions = cache.providerOptions(call.providerOptions, call.system);
|
|
59
59
|
const settings = {
|
|
60
60
|
model: languageModel,
|
|
61
|
-
|
|
61
|
+
instructions: cache.instructions(call.system),
|
|
62
62
|
// Text-only calls keep the plain prompt form; images require the
|
|
63
63
|
// multi-part message form, and both must carry the same instruction
|
|
64
64
|
// text in the same position relative to the system policy.
|
|
@@ -66,9 +66,7 @@ export function createModelAdapter(model) {
|
|
|
66
66
|
? { prompt: call.prompt }
|
|
67
67
|
: { messages: [userMessage(call.prompt, images)] }),
|
|
68
68
|
maxOutputTokens: call.maxOutputTokens,
|
|
69
|
-
...(
|
|
70
|
-
? {}
|
|
71
|
-
: { providerOptions: call.providerOptions }),
|
|
69
|
+
...(providerOptions === undefined ? {} : { providerOptions: providerOptions }),
|
|
72
70
|
maxRetries: TRANSPORT_RETRIES,
|
|
73
71
|
abortSignal: call.signal,
|
|
74
72
|
timeout: call.timeoutMs,
|
|
@@ -105,7 +103,7 @@ export function createModelAdapter(model) {
|
|
|
105
103
|
return { value: output, usage: readUsage(result, inputBound) };
|
|
106
104
|
}
|
|
107
105
|
catch (cause) {
|
|
108
|
-
throw translateModelError(cause, issue, call.signal
|
|
106
|
+
throw translateModelError(cause, issue, call.signal);
|
|
109
107
|
}
|
|
110
108
|
},
|
|
111
109
|
};
|
|
@@ -130,61 +128,37 @@ function userMessage(prompt, images) {
|
|
|
130
128
|
};
|
|
131
129
|
}
|
|
132
130
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* Gateway references require the AI SDK to be loaded (loadAiSdk) first; model
|
|
137
|
-
* instances never touch it.
|
|
131
|
+
* The bare AI SDK language model of one resolved model, for callers that
|
|
132
|
+
* drive the SDK directly (the default step executor) rather than through the
|
|
133
|
+
* adapter.
|
|
138
134
|
*/
|
|
139
135
|
export function instantiateLanguageModel(model) {
|
|
140
|
-
return
|
|
136
|
+
return model.model;
|
|
141
137
|
}
|
|
142
138
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
139
|
+
* The prompt-cache split of one call's input, when the provider reported it.
|
|
140
|
+
* Providers that cache nothing report zeros; providers that do not report the
|
|
141
|
+
* split leave the fields undefined, and so does the report.
|
|
146
142
|
*/
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
if (!PROVIDER_PATTERN.test(model.provider)) {
|
|
154
|
-
throw new AgentError('MODEL_UNAVAILABLE', `unknown model provider "${model.provider}"; expected a gateway provider ID or an AI SDK model instance`);
|
|
155
|
-
}
|
|
156
|
-
if (model.apiKey === undefined) {
|
|
157
|
-
throw new AgentError('MODEL_UNAVAILABLE', `no model credential: set ${model.apiKeyEnv} or ${GATEWAY_API_KEY_ENV}`);
|
|
158
|
-
}
|
|
159
|
-
return { endpoint: model.endpoint ?? DEFAULT_GATEWAY_ENDPOINT, flavor: 'ai-gateway' };
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* The variable each gateway language model's credential was read from, keyed
|
|
163
|
-
* by the model object the SDK is handed. The tool loop sees only that object,
|
|
164
|
-
* and this is how a rejected credential is still reported by its source. A
|
|
165
|
-
* name, never a value.
|
|
166
|
-
*/
|
|
167
|
-
const credentialSources = new WeakMap();
|
|
168
|
-
/** Builds the AI SDK language model for one validated resolved model. */
|
|
169
|
-
function instantiate(model) {
|
|
170
|
-
if (model.kind === 'instance')
|
|
171
|
-
return { languageModel: model.model };
|
|
172
|
-
const { endpoint } = validateModel(model);
|
|
173
|
-
const gateway = aiSdk().createGateway({ apiKey: model.apiKey, baseURL: endpoint });
|
|
174
|
-
const languageModel = gateway.languageModel(`${model.provider}/${model.id}`);
|
|
175
|
-
credentialSources.set(languageModel, model.apiKeySource ?? model.apiKeyEnv);
|
|
176
|
-
return { languageModel };
|
|
143
|
+
export function cacheTokenFields(usage) {
|
|
144
|
+
const details = usage?.inputTokenDetails;
|
|
145
|
+
return {
|
|
146
|
+
...(typeof details?.cacheReadTokens === 'number' ? { cacheReadTokens: details.cacheReadTokens } : {}),
|
|
147
|
+
...(typeof details?.cacheWriteTokens === 'number' ? { cacheWriteTokens: details.cacheWriteTokens } : {}),
|
|
148
|
+
};
|
|
177
149
|
}
|
|
178
150
|
function readUsage(result, inputBound) {
|
|
179
151
|
const inputTokens = result.usage?.inputTokens;
|
|
180
152
|
const outputTokens = result.usage?.outputTokens;
|
|
181
153
|
const estimatedCostUsd = readCost(result.providerMetadata);
|
|
154
|
+
const cache = cacheTokenFields(result.usage);
|
|
182
155
|
if (typeof inputTokens === 'number' && typeof outputTokens === 'number') {
|
|
183
|
-
return { inputTokens, outputTokens, accounting: 'provider', estimatedCostUsd };
|
|
156
|
+
return { inputTokens, outputTokens, ...cache, accounting: 'provider', estimatedCostUsd };
|
|
184
157
|
}
|
|
185
158
|
return {
|
|
186
159
|
inputTokens: inputBound,
|
|
187
160
|
outputTokens: tokenUpperBound(result.text ?? ''),
|
|
161
|
+
...cache,
|
|
188
162
|
accounting: 'adapter-upper-bound',
|
|
189
163
|
estimatedCostUsd,
|
|
190
164
|
};
|
|
@@ -208,16 +182,22 @@ function parseJsonObject(text) {
|
|
|
208
182
|
}
|
|
209
183
|
}
|
|
210
184
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
185
|
+
* Per-request cost, where the provider reports one in its metadata. The
|
|
186
|
+
* Vercel AI Gateway's `cost` is what it bills; BYOK routes bill the provider
|
|
187
|
+
* key directly and report `cost: "0"`, so fall back to `marketCost`, the
|
|
188
|
+
* list-price estimate of the same request. OpenRouter reports `usage.cost`
|
|
189
|
+
* when its provider is asked to account usage. Other providers simply lack
|
|
190
|
+
* the key.
|
|
215
191
|
*/
|
|
216
192
|
export function readCost(metadata) {
|
|
217
193
|
const billed = parseCost(metadata?.['gateway']?.['cost']);
|
|
218
194
|
if (billed !== undefined && billed > 0)
|
|
219
195
|
return billed;
|
|
220
|
-
|
|
196
|
+
const market = parseCost(metadata?.['gateway']?.['marketCost']) ?? billed;
|
|
197
|
+
if (market !== undefined)
|
|
198
|
+
return market;
|
|
199
|
+
const openrouter = metadata?.['openrouter']?.['usage'];
|
|
200
|
+
return typeof openrouter === 'object' && openrouter !== null ? parseCost(openrouter['cost']) : undefined;
|
|
221
201
|
}
|
|
222
202
|
function parseCost(raw) {
|
|
223
203
|
const cost = typeof raw === 'string' ? Number(raw) : raw;
|
|
@@ -228,7 +208,7 @@ function parseCost(raw) {
|
|
|
228
208
|
* only after `generate` loaded the SDK, so the cached module is available for
|
|
229
209
|
* the error-class checks.
|
|
230
210
|
*/
|
|
231
|
-
function translateModelError(rawCause, issue, signal
|
|
211
|
+
function translateModelError(rawCause, issue, signal) {
|
|
232
212
|
const { APICallError, NoObjectGeneratedError } = aiSdk();
|
|
233
213
|
const cause = unwrapRetry(rawCause);
|
|
234
214
|
if (cause instanceof AgentError)
|
|
@@ -244,25 +224,29 @@ function translateModelError(rawCause, issue, signal, model) {
|
|
|
244
224
|
if (NoObjectGeneratedError.isInstance(cause)) {
|
|
245
225
|
return new ModelOutputInvalidError(issue ?? 'provider response did not match the closed response grammar', { ...(cause.text !== undefined ? { rawText: cause.text } : {}), cause });
|
|
246
226
|
}
|
|
227
|
+
// Too big a request is not a provider outage: the observation budget or
|
|
228
|
+
// the step is what needs to shrink, and the code says so.
|
|
229
|
+
if (isContextOverflow(cause)) {
|
|
230
|
+
return new AgentError('CONTEXT_OVERFLOW', `the model request exceeded the context window: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
231
|
+
}
|
|
247
232
|
if (APICallError.isInstance(cause)) {
|
|
248
|
-
return new AgentError('MODEL_PROVIDER_FAILED', withHint(`model provider failed: ${cause.message}`, credentialHint(cause
|
|
233
|
+
return new AgentError('MODEL_PROVIDER_FAILED', withHint(`model provider failed: ${cause.message}`, credentialHint(cause)), { cause });
|
|
249
234
|
}
|
|
250
235
|
return new AgentError('MODEL_PROVIDER_FAILED', `model provider failed: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
251
236
|
}
|
|
252
237
|
/**
|
|
253
|
-
* A rejected credential
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* has done by the time a provider call has failed.
|
|
238
|
+
* A rejected credential is named for what it is. The model instance owns its
|
|
239
|
+
* credential, read from the provider package's own variable
|
|
240
|
+
* (`AI_GATEWAY_API_KEY`, `OPENROUTER_API_KEY`, ...) or passed at
|
|
241
|
+
* construction, so the runner can only say that the provider refused it.
|
|
242
|
+
* Requires the SDK to be loaded, which every caller has done by the time a
|
|
243
|
+
* provider call has failed.
|
|
260
244
|
*/
|
|
261
|
-
export function credentialHint(cause
|
|
245
|
+
export function credentialHint(cause) {
|
|
262
246
|
const failure = unwrapRetry(cause);
|
|
263
247
|
if (!(failure instanceof Error))
|
|
264
248
|
return '';
|
|
265
|
-
//
|
|
249
|
+
// Gateways raise their own authentication error classes and a raw provider
|
|
266
250
|
// an APICallError; both carry the HTTP status, so that is what is read.
|
|
267
251
|
const statusCode = failure.statusCode;
|
|
268
252
|
const rejected = statusCode === 401 ||
|
|
@@ -270,18 +254,7 @@ export function credentialHint(cause, model) {
|
|
|
270
254
|
/unauthenticated|unauthorized|authentication/i.test(`${failure.name} ${failure.message}`);
|
|
271
255
|
if (!rejected)
|
|
272
256
|
return '';
|
|
273
|
-
|
|
274
|
-
if (source === undefined)
|
|
275
|
-
return 'the provider rejected the credential the model instance was created with';
|
|
276
|
-
return `the gateway rejected the credential read from ${source}: check that the key is complete and belongs to the AI Gateway (https://vercel.com/docs/ai-gateway)`;
|
|
277
|
-
}
|
|
278
|
-
/** The variable a gateway model's credential came from; undefined for a model that owns its own. */
|
|
279
|
-
function credentialSource(model) {
|
|
280
|
-
if (model === undefined || typeof model !== 'object')
|
|
281
|
-
return undefined;
|
|
282
|
-
if ('kind' in model)
|
|
283
|
-
return model.kind === 'gateway' ? (model.apiKeySource ?? model.apiKeyEnv) : undefined;
|
|
284
|
-
return credentialSources.get(model);
|
|
257
|
+
return 'the provider rejected the credential the model instance was created with: check the variable the provider package reads, or the key passed at construction';
|
|
285
258
|
}
|
|
286
259
|
/**
|
|
287
260
|
* Unwraps a spent transport retry chain to the attempt that actually failed,
|