maestro-agent-sdk 0.1.37 → 0.1.39
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 +55 -62
- package/dist/core/loop.d.ts.map +1 -1
- package/dist/core/loop.js +5 -43
- package/dist/core/loop.js.map +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -6
- package/dist/index.js.map +1 -1
- package/dist/memory/aux-model-map.d.ts +2 -43
- package/dist/memory/aux-model-map.d.ts.map +1 -1
- package/dist/memory/aux-model-map.js +3 -85
- package/dist/memory/aux-model-map.js.map +1 -1
- package/dist/platform/config.d.ts +0 -7
- package/dist/platform/config.d.ts.map +1 -1
- package/dist/platform/config.js +0 -14
- package/dist/platform/config.js.map +1 -1
- package/dist/platform/version.d.ts +1 -1
- package/dist/platform/version.js +1 -1
- package/dist/provider.d.ts +12 -55
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +99 -156
- package/dist/provider.js.map +1 -1
- package/dist/registry.d.ts +6 -39
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +9 -76
- package/dist/registry.js.map +1 -1
- package/dist/sub-agent/runner.d.ts.map +1 -1
- package/dist/sub-agent/runner.js +0 -3
- package/dist/sub-agent/runner.js.map +1 -1
- package/dist/tools/builtin/bash.js +2 -2
- package/dist/tools/builtin/bash.js.map +1 -1
- package/dist/tools/builtin/bash_background.js +1 -1
- package/dist/tools/builtin/bash_background.js.map +1 -1
- package/dist/tools/builtin/gemini_image_qa.d.ts +12 -0
- package/dist/tools/builtin/gemini_image_qa.d.ts.map +1 -0
- package/dist/tools/builtin/gemini_image_qa.js +195 -0
- package/dist/tools/builtin/gemini_image_qa.js.map +1 -0
- package/dist/tools/builtin/read.d.ts.map +1 -1
- package/dist/tools/builtin/read.js +6 -6
- package/dist/tools/builtin/read.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/package.json +2 -24
- package/dist/providers/anthropic.d.ts +0 -328
- package/dist/providers/anthropic.d.ts.map +0 -1
- package/dist/providers/anthropic.js +0 -857
- package/dist/providers/anthropic.js.map +0 -1
- package/dist/providers/codex-auth.d.ts +0 -149
- package/dist/providers/codex-auth.d.ts.map +0 -1
- package/dist/providers/codex-auth.js +0 -332
- package/dist/providers/codex-auth.js.map +0 -1
- package/dist/providers/codex-stream.d.ts +0 -42
- package/dist/providers/codex-stream.d.ts.map +0 -1
- package/dist/providers/codex-stream.js +0 -345
- package/dist/providers/codex-stream.js.map +0 -1
- package/dist/providers/codex-translators.d.ts +0 -105
- package/dist/providers/codex-translators.d.ts.map +0 -1
- package/dist/providers/codex-translators.js +0 -244
- package/dist/providers/codex-translators.js.map +0 -1
- package/dist/providers/codex.d.ts +0 -234
- package/dist/providers/codex.d.ts.map +0 -1
- package/dist/providers/codex.js +0 -461
- package/dist/providers/codex.js.map +0 -1
- package/dist/providers/fallback.d.ts +0 -71
- package/dist/providers/fallback.d.ts.map +0 -1
- package/dist/providers/fallback.js +0 -223
- package/dist/providers/fallback.js.map +0 -1
package/dist/providers/codex.js
DELETED
|
@@ -1,461 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CodexResponsesProvider — call OpenAI's Responses API through the ChatGPT
|
|
3
|
-
* Codex backend using a `codex login` OAuth token.
|
|
4
|
-
*
|
|
5
|
-
* High-level shape:
|
|
6
|
-
*
|
|
7
|
-
* ┌────────────────────────┐ ┌──────────────────────────────────────┐
|
|
8
|
-
* │ AIAgent loop │ │ CodexResponsesProvider │
|
|
9
|
-
* │ ProviderMessage[] ─┼───▶│ - resolveAccessToken (refresh-aware)│
|
|
10
|
-
* │ │ │ - translateMessagesToResponses │
|
|
11
|
-
* │ │ │ - translateToolsToResponses │
|
|
12
|
-
* │ │ │ - POST /responses (stream:true) │
|
|
13
|
-
* │ ProviderStreamChunk ◀┼────│ - parseCodexStream │
|
|
14
|
-
* └────────────────────────┘ └──────────────────────────────────────┘
|
|
15
|
-
*
|
|
16
|
-
* Pinned constraints (verified empirically against
|
|
17
|
-
* `https://chatgpt.com/backend-api/codex/responses` on 2026-05-23):
|
|
18
|
-
*
|
|
19
|
-
* - **Stream is required**: non-streaming requests return
|
|
20
|
-
* `400 {"detail":"Stream must be set to true"}`.
|
|
21
|
-
* - **Model whitelist**: ChatGPT-account requests are limited to a small
|
|
22
|
-
* set of codex-issued model slugs (`gpt-5.5`, `gpt-5.4`, `gpt-5.4-mini`,
|
|
23
|
-
* `gpt-5.3-codex`, `gpt-5.2`, ...). Passing `gpt-5` returns 400 with
|
|
24
|
-
* `not supported when using Codex with a ChatGPT account`.
|
|
25
|
-
* - **Cloudflare headers required**: `originator: codex_cli_rs` plus a
|
|
26
|
-
* codex-shaped `User-Agent` are mandatory on non-residential IPs.
|
|
27
|
-
* - **`store: false`**: required when the rollout lives on the client side.
|
|
28
|
-
* Without it, the server expects subsequent requests to look items up
|
|
29
|
-
* by `id` and 404s when they can't.
|
|
30
|
-
*
|
|
31
|
-
* What this provider does NOT cover (deliberate scope cuts):
|
|
32
|
-
*
|
|
33
|
-
* - Reasoning chain replay across turns (would need `encrypted_content`
|
|
34
|
-
* plumbed into the message history). Reasoning summaries flow through
|
|
35
|
-
* as `thinking` blocks for the current turn only.
|
|
36
|
-
* - Built-in hosted tools (`web_search`, `file_search`). Only
|
|
37
|
-
* user-supplied function tools are wired.
|
|
38
|
-
* - Token-bucket rate-limit handling. The backend rate-limits aggressively
|
|
39
|
-
* for free accounts; surfacing a structured retry hint can be a follow-up.
|
|
40
|
-
*
|
|
41
|
-
* Hermes reference: `agent/transports/codex.py` + `_run_codex_stream`. We
|
|
42
|
-
* implement the same wire contract using only `fetch` and the SSE parser in
|
|
43
|
-
* `codex-stream.ts`, with no httpx / OpenAI SDK dependency.
|
|
44
|
-
*/
|
|
45
|
-
import { logger } from "../platform/logger.js";
|
|
46
|
-
import { cloudflareHeaders, resolveAccessToken } from "../providers/codex-auth.js";
|
|
47
|
-
import { parseCodexStream } from "../providers/codex-stream.js";
|
|
48
|
-
import { translateMessagesToResponses, translateToolsToResponses, } from "../providers/codex-translators.js";
|
|
49
|
-
import { nodeFetch } from "../providers/node-fetch.js";
|
|
50
|
-
/** Default base URL — the ChatGPT-hosted Codex endpoint. Hosts that point at
|
|
51
|
-
* an alternate proxy (corporate gateway, mock server for tests) can override
|
|
52
|
-
* via the constructor opts.baseUrl. */
|
|
53
|
-
const DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex";
|
|
54
|
-
/**
|
|
55
|
-
* Map maestro's `EffortLevel` to the Responses API `reasoning.effort` string.
|
|
56
|
-
*
|
|
57
|
-
* Codex backend accepts `low | medium | high | xhigh`. The 5-tier maestro
|
|
58
|
-
* scale collapses as follows:
|
|
59
|
-
* - `low` / `medium` / `high` → direct passthrough.
|
|
60
|
-
* - `xhigh` → passthrough (Codex actually supports this tier on gpt-5.x).
|
|
61
|
-
* - `max` → `xhigh`. Codex has no `max`; we pick the deepest tier the
|
|
62
|
-
* backend exposes rather than silently dropping the user's intent.
|
|
63
|
-
*/
|
|
64
|
-
export function effortForCodex(e) {
|
|
65
|
-
switch (e) {
|
|
66
|
-
case "low":
|
|
67
|
-
return "low";
|
|
68
|
-
case "medium":
|
|
69
|
-
return "medium";
|
|
70
|
-
case "high":
|
|
71
|
-
return "high";
|
|
72
|
-
case "xhigh":
|
|
73
|
-
return "xhigh";
|
|
74
|
-
case "max":
|
|
75
|
-
return "xhigh";
|
|
76
|
-
default:
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Provider implementation. Construct once per process; safe to share across
|
|
82
|
-
* concurrent agent turns (token refresh is best-effort idempotent under the
|
|
83
|
-
* skew check + on-disk persistence).
|
|
84
|
-
*/
|
|
85
|
-
export class CodexResponsesProvider {
|
|
86
|
-
baseUrl;
|
|
87
|
-
refreshTimeoutMs;
|
|
88
|
-
refreshSkewSeconds;
|
|
89
|
-
idleTimeoutMs;
|
|
90
|
-
totalTimeoutMs;
|
|
91
|
-
toolOutputWireCapChars;
|
|
92
|
-
keepRecentToolOutputsFull;
|
|
93
|
-
/** Surfaced to the agent loop (see `Provider.compactionTriggerRatio`). Codex
|
|
94
|
-
* compacts earlier than cache-friendly providers because it re-uploads the
|
|
95
|
-
* whole conversation every iteration. */
|
|
96
|
-
compactionTriggerRatio;
|
|
97
|
-
/** Surfaced via `Provider.compactionTailProtect`. Shorter tail than the
|
|
98
|
-
* compressor default so codex compactions fold more of the middle. */
|
|
99
|
-
compactionTailProtect;
|
|
100
|
-
/** Surfaced via `Provider.guidedCompaction`. Codex opts into focus-steered
|
|
101
|
-
* compaction (active task preserved in full); other providers don't. */
|
|
102
|
-
guidedCompaction = true;
|
|
103
|
-
constructor(opts = {}) {
|
|
104
|
-
this.baseUrl = (opts.baseUrl ?? DEFAULT_CODEX_BASE_URL).replace(/\/+$/, "");
|
|
105
|
-
this.refreshTimeoutMs = opts.refreshTimeoutMs ?? 20_000;
|
|
106
|
-
this.refreshSkewSeconds = opts.refreshSkewSeconds;
|
|
107
|
-
this.idleTimeoutMs = opts.idleTimeoutMs ?? 1_800_000;
|
|
108
|
-
this.totalTimeoutMs = opts.totalTimeoutMs ?? opts.fetchTimeoutMs ?? 5_400_000;
|
|
109
|
-
this.toolOutputWireCapChars = opts.toolOutputWireCapChars ?? 4_000;
|
|
110
|
-
this.keepRecentToolOutputsFull = opts.keepRecentToolOutputsFull ?? 2;
|
|
111
|
-
this.compactionTriggerRatio = opts.compactionTriggerRatio ?? 0.35;
|
|
112
|
-
this.compactionTailProtect = opts.compactionTailProtect ?? 4;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Build the `nodeFetch` init shared by the initial POST and the 401-refresh
|
|
116
|
-
* retry. We route through `node:http` (not Bun's global `fetch`) because Bun
|
|
117
|
-
* caps `fetch` at a hard, unconfigurable ~300 s; `AbortSignal` can only
|
|
118
|
-
* shorten that, never raise it (see `node-fetch.ts` for the empirical proof).
|
|
119
|
-
* The two-layer timeout (idle + total) is honored by node:http, and the
|
|
120
|
-
* caller's `abortSignal` still wins immediately for user cancels.
|
|
121
|
-
*/
|
|
122
|
-
buildFetchInit(headers, body, userSignal) {
|
|
123
|
-
return {
|
|
124
|
-
method: "POST",
|
|
125
|
-
headers,
|
|
126
|
-
body,
|
|
127
|
-
idleTimeoutMs: this.idleTimeoutMs,
|
|
128
|
-
totalTimeoutMs: this.totalTimeoutMs,
|
|
129
|
-
...(userSignal ? { signal: userSignal } : {}),
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Factory parity with `DeepseekProvider.fromEnv()` — for Codex the "env"
|
|
134
|
-
* inputs are really the on-disk `~/.codex/auth.json` (no API key env var
|
|
135
|
-
* makes sense for OAuth). The factory still throws early if the auth file
|
|
136
|
-
* is missing or stale, so a host can fail fast at startup instead of on
|
|
137
|
-
* the first user message.
|
|
138
|
-
*/
|
|
139
|
-
static fromEnv(opts = {}) {
|
|
140
|
-
return new CodexResponsesProvider(opts);
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Streaming entry point. The Codex backend rejects non-streaming requests
|
|
144
|
-
* outright, so this is the load-bearing method — `complete()` is just a
|
|
145
|
-
* convenience wrapper around it.
|
|
146
|
-
*/
|
|
147
|
-
async *stream(opts) {
|
|
148
|
-
// v0.1.28 diagnostic instrumentation. The gpt-5.5 swap reproducer
|
|
149
|
-
// surfaced "The operation timed out" as the bare error message bubbled
|
|
150
|
-
// through `maestroProvider`'s catch. We don't yet know which hop —
|
|
151
|
-
// OAuth refresh (`codex-auth.ts`), `/responses` POST below, or SSE
|
|
152
|
-
// stream parse — actually raises it. Each `logger.*` line below stamps
|
|
153
|
-
// a phase + elapsed time so the next reproduction pinpoints the source.
|
|
154
|
-
const streamStart = Date.now();
|
|
155
|
-
const tokenStart = Date.now();
|
|
156
|
-
let token;
|
|
157
|
-
try {
|
|
158
|
-
token = await resolveAccessToken({
|
|
159
|
-
timeoutMs: this.refreshTimeoutMs,
|
|
160
|
-
...(this.refreshSkewSeconds !== undefined ? { skewSeconds: this.refreshSkewSeconds } : {}),
|
|
161
|
-
});
|
|
162
|
-
logger.info({ model: opts.model, elapsedMs: Date.now() - tokenStart }, "codex: resolveAccessToken OK");
|
|
163
|
-
}
|
|
164
|
-
catch (e) {
|
|
165
|
-
logger.error({
|
|
166
|
-
phase: "resolveAccessToken",
|
|
167
|
-
elapsedMs: Date.now() - tokenStart,
|
|
168
|
-
model: opts.model,
|
|
169
|
-
errName: e instanceof Error ? e.name : typeof e,
|
|
170
|
-
errCode: e?.code,
|
|
171
|
-
errMessage: e instanceof Error ? e.message : String(e),
|
|
172
|
-
errCause: e?.cause,
|
|
173
|
-
stack: e instanceof Error ? e.stack : undefined,
|
|
174
|
-
}, "codex: resolveAccessToken FAILED");
|
|
175
|
-
throw e;
|
|
176
|
-
}
|
|
177
|
-
const body = buildRequestBody(opts, {
|
|
178
|
-
capChars: this.toolOutputWireCapChars,
|
|
179
|
-
keepRecent: this.keepRecentToolOutputsFull,
|
|
180
|
-
});
|
|
181
|
-
const url = `${this.baseUrl}/responses`;
|
|
182
|
-
const headers = {
|
|
183
|
-
...cloudflareHeaders(token),
|
|
184
|
-
"Content-Type": "application/json",
|
|
185
|
-
Accept: "text/event-stream",
|
|
186
|
-
};
|
|
187
|
-
const init = this.buildFetchInit(headers, JSON.stringify(body), opts.abortSignal);
|
|
188
|
-
const responseStart = Date.now();
|
|
189
|
-
logger.info({
|
|
190
|
-
url,
|
|
191
|
-
model: opts.model,
|
|
192
|
-
bodyBytes: init.body.length,
|
|
193
|
-
idleTimeoutMs: this.idleTimeoutMs,
|
|
194
|
-
totalTimeoutMs: this.totalTimeoutMs,
|
|
195
|
-
}, "codex: /responses fetch start");
|
|
196
|
-
let response;
|
|
197
|
-
try {
|
|
198
|
-
response = await nodeFetch(url, init);
|
|
199
|
-
logger.info({
|
|
200
|
-
status: response.status,
|
|
201
|
-
elapsedMs: Date.now() - responseStart,
|
|
202
|
-
model: opts.model,
|
|
203
|
-
}, "codex: /responses fetch returned headers");
|
|
204
|
-
}
|
|
205
|
-
catch (e) {
|
|
206
|
-
logger.error({
|
|
207
|
-
phase: "/responses fetch",
|
|
208
|
-
elapsedMs: Date.now() - responseStart,
|
|
209
|
-
totalElapsedMs: Date.now() - streamStart,
|
|
210
|
-
url,
|
|
211
|
-
model: opts.model,
|
|
212
|
-
errName: e instanceof Error ? e.name : typeof e,
|
|
213
|
-
errCode: e?.code,
|
|
214
|
-
errMessage: e instanceof Error ? e.message : String(e),
|
|
215
|
-
errCause: e?.cause,
|
|
216
|
-
stack: e instanceof Error ? e.stack : undefined,
|
|
217
|
-
}, "codex: /responses fetch THREW (likely the source of 'The operation timed out')");
|
|
218
|
-
throw e;
|
|
219
|
-
}
|
|
220
|
-
if (response.status === 401) {
|
|
221
|
-
// Refresh-then-retry once. The on-disk token may have rotated since
|
|
222
|
-
// resolveAccessToken's skew check (e.g. another process refreshed and
|
|
223
|
-
// wrote a token we still saw as valid). A second attempt under
|
|
224
|
-
// forceRefresh covers that race.
|
|
225
|
-
const fresh = await resolveAccessToken({
|
|
226
|
-
forceRefresh: true,
|
|
227
|
-
timeoutMs: this.refreshTimeoutMs,
|
|
228
|
-
...(this.refreshSkewSeconds !== undefined ? { skewSeconds: this.refreshSkewSeconds } : {}),
|
|
229
|
-
});
|
|
230
|
-
const retryInit = this.buildFetchInit({
|
|
231
|
-
...cloudflareHeaders(fresh),
|
|
232
|
-
"Content-Type": "application/json",
|
|
233
|
-
Accept: "text/event-stream",
|
|
234
|
-
}, JSON.stringify(body), opts.abortSignal);
|
|
235
|
-
const retry = await nodeFetch(url, retryInit);
|
|
236
|
-
if (!retry.ok) {
|
|
237
|
-
await throwCodexHttpError(retry);
|
|
238
|
-
}
|
|
239
|
-
if (!retry.body)
|
|
240
|
-
throw new Error("Codex Responses API: missing response body on 401 retry");
|
|
241
|
-
yield* parseCodexStream(retry.body, opts.abortSignal);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (!response.ok) {
|
|
245
|
-
await throwCodexHttpError(response);
|
|
246
|
-
}
|
|
247
|
-
if (!response.body) {
|
|
248
|
-
throw new Error("Codex Responses API: missing response body");
|
|
249
|
-
}
|
|
250
|
-
yield* parseCodexStream(response.body, opts.abortSignal);
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Non-streaming entry point. The Codex backend doesn't support
|
|
254
|
-
* `stream: false`, so we drain `stream()` into a single `ProviderResponse`.
|
|
255
|
-
* Callers that want progressive UI updates should use `stream()` directly.
|
|
256
|
-
*
|
|
257
|
-
* The reconstruction follows DeepseekProvider's convention:
|
|
258
|
-
* - text deltas collapse into one `text` content block per stream;
|
|
259
|
-
* - tool_use_start + tool_use_input_delta + tool_use_complete bundle
|
|
260
|
-
* into one `tool_use` block with parsed JSON args;
|
|
261
|
-
* - thinking_complete blocks are forwarded verbatim.
|
|
262
|
-
*
|
|
263
|
-
* Block order in the returned `content`: thinking → text → tool_use,
|
|
264
|
-
* matching the assistant-history convention the loop expects on replay.
|
|
265
|
-
*/
|
|
266
|
-
async complete(opts) {
|
|
267
|
-
let text = "";
|
|
268
|
-
const thinkingBlocks = [];
|
|
269
|
-
const tools = new Map();
|
|
270
|
-
let stopReason = "end_turn";
|
|
271
|
-
let usage = { inputTokens: 0, outputTokens: 0 };
|
|
272
|
-
for await (const chunk of this.stream(opts)) {
|
|
273
|
-
switch (chunk.type) {
|
|
274
|
-
case "text_delta":
|
|
275
|
-
text += chunk.text;
|
|
276
|
-
break;
|
|
277
|
-
case "tool_use_start":
|
|
278
|
-
tools.set(chunk.id, { name: chunk.name, args: "" });
|
|
279
|
-
break;
|
|
280
|
-
case "tool_use_input_delta": {
|
|
281
|
-
const entry = tools.get(chunk.id);
|
|
282
|
-
if (entry)
|
|
283
|
-
entry.args += chunk.partial_json;
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
case "tool_use_complete": {
|
|
287
|
-
const entry = tools.get(chunk.id);
|
|
288
|
-
if (entry && !entry.name)
|
|
289
|
-
entry.name = chunk.name;
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
case "thinking_complete":
|
|
293
|
-
thinkingBlocks.push(chunk.block);
|
|
294
|
-
break;
|
|
295
|
-
case "message_complete":
|
|
296
|
-
stopReason = chunk.stopReason;
|
|
297
|
-
usage = chunk.usage;
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
const content = [];
|
|
302
|
-
for (const block of thinkingBlocks)
|
|
303
|
-
content.push(block);
|
|
304
|
-
if (text.length > 0)
|
|
305
|
-
content.push({ type: "text", text });
|
|
306
|
-
for (const [id, entry] of tools.entries()) {
|
|
307
|
-
let input = {};
|
|
308
|
-
const trimmed = entry.args.trim();
|
|
309
|
-
if (trimmed.length > 0) {
|
|
310
|
-
try {
|
|
311
|
-
input = JSON.parse(trimmed);
|
|
312
|
-
}
|
|
313
|
-
catch {
|
|
314
|
-
// Defensive — malformed JSON args fall through as `{}`. Matches
|
|
315
|
-
// DeepseekProvider's behavior on the same failure mode.
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
content.push({ type: "tool_use", id, name: entry.name, input });
|
|
319
|
-
}
|
|
320
|
-
return { content, stopReason, usage };
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Build the JSON body the Responses API expects.
|
|
325
|
-
*
|
|
326
|
-
* Notable fields:
|
|
327
|
-
* - `instructions`: maestro's `system` string. The Responses API has no
|
|
328
|
-
* `system` role; this slot is the canonical place for persona / global
|
|
329
|
-
* constraints.
|
|
330
|
-
* - `input`: the message history as Responses input items
|
|
331
|
-
* (translateMessagesToResponses).
|
|
332
|
-
* - `tools` / `tool_choice` / `parallel_tool_calls`: standard.
|
|
333
|
-
* - `store: false`: keep the conversation client-side. With `store: true`
|
|
334
|
-
* the server expects subsequent requests to reference earlier items
|
|
335
|
-
* by ID and 404s when they don't — incompatible with maestro's
|
|
336
|
-
* stateless turn model.
|
|
337
|
-
* - `stream: true`: required; non-streaming returns 400.
|
|
338
|
-
* - `reasoning`: only emitted when the caller picked an effort tier.
|
|
339
|
-
* We always include `summary: "auto"` so the model surfaces a
|
|
340
|
-
* human-readable reasoning trace alongside the encrypted content.
|
|
341
|
-
* - `include: ["reasoning.encrypted_content"]`: makes the encrypted
|
|
342
|
-
* reasoning blob available in `output_item.done` payloads. We don't
|
|
343
|
-
* replay it yet, but capturing it now keeps the future replay path
|
|
344
|
-
* a translator change rather than another wire change.
|
|
345
|
-
*/
|
|
346
|
-
/**
|
|
347
|
-
* Codex wire-diet. Trims `function_call_output.output` for tool results OLDER
|
|
348
|
-
* than the `keepRecent` most recent ones, preserving head+tail with an elision
|
|
349
|
-
* marker. Pure function over the input-item array; the caller's stored message
|
|
350
|
-
* history is untouched (this only shrinks the bytes on the wire).
|
|
351
|
-
*
|
|
352
|
-
* Why only `function_call_output`: it's a free-form string, safe to truncate.
|
|
353
|
-
* We deliberately do NOT touch `function_call.arguments` — that's a JSON string
|
|
354
|
-
* the backend may parse, and mid-string truncation would corrupt it.
|
|
355
|
-
*/
|
|
356
|
-
export function dietToolOutputs(input, capChars, keepRecent) {
|
|
357
|
-
if (!Number.isFinite(capChars) || capChars <= 0)
|
|
358
|
-
return input; // disabled
|
|
359
|
-
const fcoIndices = [];
|
|
360
|
-
for (let i = 0; i < input.length; i++) {
|
|
361
|
-
if (input[i]?.type === "function_call_output")
|
|
362
|
-
fcoIndices.push(i);
|
|
363
|
-
}
|
|
364
|
-
if (fcoIndices.length <= keepRecent)
|
|
365
|
-
return input; // nothing old enough to trim
|
|
366
|
-
const keepFull = new Set(fcoIndices.slice(keepRecent > 0 ? -keepRecent : fcoIndices.length));
|
|
367
|
-
const headLen = Math.floor(capChars * 0.7);
|
|
368
|
-
const tailLen = capChars - headLen;
|
|
369
|
-
let trimmedItems = 0;
|
|
370
|
-
let savedChars = 0;
|
|
371
|
-
const out = input.map((item, i) => {
|
|
372
|
-
if (item.type !== "function_call_output" || keepFull.has(i))
|
|
373
|
-
return item;
|
|
374
|
-
if (typeof item.output !== "string" || item.output.length <= capChars)
|
|
375
|
-
return item;
|
|
376
|
-
const removed = item.output.length - headLen - tailLen;
|
|
377
|
-
trimmedItems++;
|
|
378
|
-
savedChars += removed;
|
|
379
|
-
return {
|
|
380
|
-
...item,
|
|
381
|
-
output: `${item.output.slice(0, headLen)}\n\n…[codex wire-diet: ${removed} chars elided from an earlier tool output]…\n\n${item.output.slice(item.output.length - tailLen)}`,
|
|
382
|
-
};
|
|
383
|
-
});
|
|
384
|
-
if (trimmedItems > 0) {
|
|
385
|
-
logger.info({ trimmedItems, savedChars, oldToolOutputs: fcoIndices.length - keepFull.size, capChars }, "codex: wire-diet trimmed old tool outputs");
|
|
386
|
-
}
|
|
387
|
-
return out;
|
|
388
|
-
}
|
|
389
|
-
function buildRequestBody(opts, diet) {
|
|
390
|
-
let input = translateMessagesToResponses(opts.messages);
|
|
391
|
-
input = dietToolOutputs(input, diet.capChars, diet.keepRecent);
|
|
392
|
-
const tools = translateToolsToResponses(opts.tools);
|
|
393
|
-
const body = {
|
|
394
|
-
model: opts.model,
|
|
395
|
-
instructions: opts.system ?? "",
|
|
396
|
-
input,
|
|
397
|
-
store: false,
|
|
398
|
-
stream: true,
|
|
399
|
-
parallel_tool_calls: true,
|
|
400
|
-
};
|
|
401
|
-
if (tools && tools.length > 0) {
|
|
402
|
-
body.tools = tools;
|
|
403
|
-
body.tool_choice = "auto";
|
|
404
|
-
}
|
|
405
|
-
// NOTE: the codex chatgpt backend rejects `max_output_tokens` outright
|
|
406
|
-
// (verified 2026-05-23: returns 400 "Unsupported parameter: max_output_tokens").
|
|
407
|
-
// This matches hermes's `agent/transports/codex.py` which only sets
|
|
408
|
-
// max_output_tokens when `not is_codex_backend`. Hosts that need to clamp
|
|
409
|
-
// output length on Codex should rely on iteration caps + `effort` instead.
|
|
410
|
-
// We deliberately drop `opts.maxTokens` here even though the field exists.
|
|
411
|
-
const effort = effortForCodex(opts.effort);
|
|
412
|
-
if (effort) {
|
|
413
|
-
body.reasoning = { effort, summary: "auto" };
|
|
414
|
-
body.include = ["reasoning.encrypted_content"];
|
|
415
|
-
}
|
|
416
|
-
return body;
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Construct a thrown `Error` carrying as much diagnostic context as the
|
|
420
|
-
* Codex backend gives us. The backend returns several shapes:
|
|
421
|
-
*
|
|
422
|
-
* - `{"detail":"..."}` (most common, e.g. model-not-allowed, stream-required)
|
|
423
|
-
* - `{"error":{"message":"..."}}` (OpenAI legacy)
|
|
424
|
-
* - Plain text (Cloudflare 403)
|
|
425
|
-
*
|
|
426
|
-
* We surface whichever is present, prefixed with the HTTP status so the
|
|
427
|
-
* caller can grep by status code in logs.
|
|
428
|
-
*/
|
|
429
|
-
async function throwCodexHttpError(response) {
|
|
430
|
-
let bodyText = "";
|
|
431
|
-
try {
|
|
432
|
-
bodyText = await response.text();
|
|
433
|
-
}
|
|
434
|
-
catch {
|
|
435
|
-
bodyText = "";
|
|
436
|
-
}
|
|
437
|
-
let detail = bodyText.slice(0, 500);
|
|
438
|
-
try {
|
|
439
|
-
const j = JSON.parse(bodyText);
|
|
440
|
-
if (typeof j.detail === "string")
|
|
441
|
-
detail = j.detail;
|
|
442
|
-
else if (j.error && typeof j.error === "object") {
|
|
443
|
-
const inner = j.error;
|
|
444
|
-
if (typeof inner.message === "string")
|
|
445
|
-
detail = inner.message;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
catch {
|
|
449
|
-
// bodyText wasn't JSON; keep the snippet.
|
|
450
|
-
}
|
|
451
|
-
const cf = response.headers.get("cf-mitigated");
|
|
452
|
-
const suffix = cf ? ` (cf-mitigated: ${cf})` : "";
|
|
453
|
-
const err = new Error(`Codex Responses API ${response.status} ${response.statusText}: ${detail}${suffix}`);
|
|
454
|
-
// Attach the raw status for callers that want to switch on it.
|
|
455
|
-
err.httpStatus = response.status;
|
|
456
|
-
throw err;
|
|
457
|
-
}
|
|
458
|
-
// Re-export for hosts that want to surface the typed error from
|
|
459
|
-
// `codex-auth.ts` without importing both modules.
|
|
460
|
-
export { CodexAuthError } from "../providers/codex-auth.js";
|
|
461
|
-
//# sourceMappingURL=codex.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/providers/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type { Provider, ProviderCompleteOptions, ProviderResponse, ProviderStreamChunk } from "../providers/base.js";
|
|
2
|
-
/**
|
|
3
|
-
* Provider wrapper that falls back from a `primary` to a `fallback` provider
|
|
4
|
-
* when the primary fails *before producing any output*.
|
|
5
|
-
*
|
|
6
|
-
* Motivating case: the Codex `/responses` backend (ChatGPT-OAuth) is the
|
|
7
|
-
* primary for `gpt-5.*` models, but its OAuth refresh, HTTP round-trip, and
|
|
8
|
-
* time-to-first-byte all happen INSIDE `stream()` before the first chunk is
|
|
9
|
-
* yielded (see `codex.ts` — `fromEnv()` only constructs; auth resolves at
|
|
10
|
-
* stream time). When any of those legs throws — OAuth dead, HTTP 401/429/5xx,
|
|
11
|
-
* connect/TTFB timeout, network reset — this wrapper retries the turn against
|
|
12
|
-
* DeepSeek instead of surfacing a hard `error` event.
|
|
13
|
-
*
|
|
14
|
-
* ## Why pre-first-chunk only
|
|
15
|
-
*
|
|
16
|
-
* Once the primary has yielded ANY chunk, the host has already displayed text
|
|
17
|
-
* (or a tool_use has started) and the assistant turn's history is half-built.
|
|
18
|
-
* Restarting against a different provider there would double-emit content and
|
|
19
|
-
* desync the loop's message accumulation. So the switch is only safe before
|
|
20
|
-
* the first chunk — after that, errors propagate unchanged. This covers the
|
|
21
|
-
* overwhelming majority of "codex isn't working" failures, which are all
|
|
22
|
-
* pre-stream by construction.
|
|
23
|
-
*
|
|
24
|
-
* ## Model id + maxTokens rewrite
|
|
25
|
-
*
|
|
26
|
-
* The agent loop passes the primary's resolved model id (e.g. `gpt-5.5`) in
|
|
27
|
-
* `ProviderCompleteOptions.model`. DeepSeek would 400 on that slug, so the
|
|
28
|
-
* fallback delegation rewrites `opts.model` to `fallbackModel` and clamps
|
|
29
|
-
* `opts.maxTokens` to the fallback model's native output ceiling (a gpt-5.5
|
|
30
|
-
* `maxTokens` could exceed a flash-tier fallback's cap). `thinkingBudget` is
|
|
31
|
-
* harmlessly ignored by DeepSeek; `effort` is honored natively. Tools and
|
|
32
|
-
* messages pass through untouched — each provider runs its own translation
|
|
33
|
-
* from the shared `ProviderMessage` shape.
|
|
34
|
-
*
|
|
35
|
-
* ## Compaction props
|
|
36
|
-
*
|
|
37
|
-
* `compactionTriggerRatio` / `compactionTailProtect` / `guidedCompaction` are
|
|
38
|
-
* read once by the loop *before* the turn, so they reflect the PRIMARY's
|
|
39
|
-
* preference (Codex compacts early + guided). If the fallback fires, DeepSeek
|
|
40
|
-
* runs against a slightly-more-aggressively-compacted history — harmless, and
|
|
41
|
-
* not worth the complexity of swapping mid-turn.
|
|
42
|
-
*/
|
|
43
|
-
export declare class FallbackProvider implements Provider {
|
|
44
|
-
private readonly primary;
|
|
45
|
-
private readonly fallbackFactory;
|
|
46
|
-
private readonly fallbackModel;
|
|
47
|
-
private fallbackInstance;
|
|
48
|
-
/**
|
|
49
|
-
* @param primary The preferred provider (e.g. Codex).
|
|
50
|
-
* @param fallbackFactory Lazily constructs the fallback provider. Deferred so
|
|
51
|
-
* a process that never trips the fallback never pays its construction cost
|
|
52
|
-
* (and never requires its env to be present until actually needed).
|
|
53
|
-
* @param fallbackModel Wire model id handed to the fallback provider, e.g.
|
|
54
|
-
* `deepseek-v4-pro`. Replaces the primary's model id on delegation.
|
|
55
|
-
*/
|
|
56
|
-
constructor(primary: Provider, fallbackFactory: () => Provider, fallbackModel: string);
|
|
57
|
-
get compactionTriggerRatio(): number | undefined;
|
|
58
|
-
get compactionTailProtect(): number | undefined;
|
|
59
|
-
get guidedCompaction(): boolean | undefined;
|
|
60
|
-
private getFallback;
|
|
61
|
-
/** Rewrite the request for the fallback provider: swap model id, clamp
|
|
62
|
-
* maxTokens to the fallback's native output ceiling. */
|
|
63
|
-
private rewriteOpts;
|
|
64
|
-
private shouldRethrow;
|
|
65
|
-
stream(opts: ProviderCompleteOptions): AsyncGenerator<ProviderStreamChunk>;
|
|
66
|
-
complete(opts: ProviderCompleteOptions): Promise<ProviderResponse>;
|
|
67
|
-
/** Adapt a `complete()`-only primary into the streaming shape. Defensive
|
|
68
|
-
* helper for the stream-less-primary branch; unused for Codex/DeepSeek. */
|
|
69
|
-
private streamViaComplete;
|
|
70
|
-
}
|
|
71
|
-
//# sourceMappingURL=fallback.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fallback.d.ts","sourceRoot":"","sources":["../../src/providers/fallback.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,QAAQ,EACR,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAG1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,qBAAa,gBAAiB,YAAW,QAAQ;IAY7C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAbhC,OAAO,CAAC,gBAAgB,CAAyB;IAEjD;;;;;;;OAOG;gBAEgB,OAAO,EAAE,QAAQ,EACjB,eAAe,EAAE,MAAM,QAAQ,EAC/B,aAAa,EAAE,MAAM;IAIxC,IAAI,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAE/C;IACD,IAAI,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAE9C;IACD,IAAI,gBAAgB,IAAI,OAAO,GAAG,SAAS,CAE1C;IAED,OAAO,CAAC,WAAW;IAOnB;6DACyD;IACzD,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,aAAa;IAId,MAAM,CAAC,IAAI,EAAE,uBAAuB,GAAG,cAAc,CAAC,mBAAmB,CAAC;IA0D3E,QAAQ,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuBxE;gFAC4E;YAC7D,iBAAiB;CAsBjC"}
|