@cydm/pie 2.7.5 → 2.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +6 -4
- package/dist/builtin/extensions/subagent/index.js +4 -4
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/chrome-devtools-axi/SKILL.md +2 -2
- package/dist/builtin/skills/computer-use-axi/SKILL.md +1 -1
- package/dist/builtin/skills/tui-use/SKILL.md +1 -1
- package/dist/chunks/{chunk-SUPAWIKP.js → chunk-2FEDB5GR.js} +193 -54
- package/dist/chunks/{chunk-OOUL3DRE.js → chunk-IU5L5DED.js} +325 -56
- package/dist/chunks/{chunk-BFHCZVNO.js → chunk-UPGEXDEQ.js} +336 -59
- package/dist/chunks/{chunk-MLRF72MK.js → chunk-W5B3OXHQ.js} +1 -1
- package/dist/chunks/{src-DV4UYUNJ.js → src-C2CBPEUY.js} +2 -2
- package/dist/chunks/{test-stream-SWO34GSS.js → test-stream-LDVUVSUP.js} +10 -1
- package/dist/cli.js +157 -111
- package/package.json +6 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createAskUserCapability
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
5
|
-
import "../../../chunks/chunk-
|
|
6
|
-
import "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-UPGEXDEQ.js";
|
|
5
|
+
import "../../../chunks/chunk-W5B3OXHQ.js";
|
|
6
|
+
import "../../../chunks/chunk-2FEDB5GR.js";
|
|
7
7
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
8
8
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
9
9
|
|
|
@@ -4,12 +4,13 @@ import {
|
|
|
4
4
|
createExecutionStateFromPlan,
|
|
5
5
|
createPlanCapability,
|
|
6
6
|
extractPlanTodoItems,
|
|
7
|
+
getToolCapabilityMetadata,
|
|
7
8
|
isPlanModeSafeCommand,
|
|
8
9
|
markCompletedPlanSteps,
|
|
9
10
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
11
|
-
import "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
11
|
+
} from "../../../chunks/chunk-UPGEXDEQ.js";
|
|
12
|
+
import "../../../chunks/chunk-W5B3OXHQ.js";
|
|
13
|
+
import "../../../chunks/chunk-2FEDB5GR.js";
|
|
13
14
|
import {
|
|
14
15
|
Type
|
|
15
16
|
} from "../../../chunks/chunk-XXGYUYXI.js";
|
|
@@ -258,7 +259,8 @@ Update the plan accordingly and call plan_submit again with the revised steps. D
|
|
|
258
259
|
}
|
|
259
260
|
});
|
|
260
261
|
ctx.on("tool:call", async (event) => {
|
|
261
|
-
if (!planModeEnabled
|
|
262
|
+
if (!planModeEnabled) return;
|
|
263
|
+
if (getToolCapabilityMetadata({ name: event.toolName })?.executesShell !== true) return;
|
|
262
264
|
const command = typeof event.args === "object" && event.args !== null ? event.args.command : void 0;
|
|
263
265
|
if (typeof command === "string" && !isPlanModeSafeCommand(command)) {
|
|
264
266
|
ctx.ui.notify(
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
formatTransportLifecycle,
|
|
5
5
|
getConfigDir,
|
|
6
6
|
logTransportLifecycle
|
|
7
|
-
} from "../../../chunks/chunk-
|
|
7
|
+
} from "../../../chunks/chunk-IU5L5DED.js";
|
|
8
8
|
import {
|
|
9
9
|
SUBAGENT_SESSION_RECORD_VERSION,
|
|
10
10
|
createSharedFileSystemTools,
|
|
11
11
|
createSubagentCapability
|
|
12
|
-
} from "../../../chunks/chunk-
|
|
13
|
-
import "../../../chunks/chunk-
|
|
14
|
-
import "../../../chunks/chunk-
|
|
12
|
+
} from "../../../chunks/chunk-UPGEXDEQ.js";
|
|
13
|
+
import "../../../chunks/chunk-W5B3OXHQ.js";
|
|
14
|
+
import "../../../chunks/chunk-2FEDB5GR.js";
|
|
15
15
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
16
16
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
17
17
|
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
executeManageTodoList,
|
|
9
9
|
executionStateToTodos,
|
|
10
10
|
restoreExecutionState
|
|
11
|
-
} from "../../../chunks/chunk-
|
|
12
|
-
import "../../../chunks/chunk-
|
|
13
|
-
import "../../../chunks/chunk-
|
|
11
|
+
} from "../../../chunks/chunk-UPGEXDEQ.js";
|
|
12
|
+
import "../../../chunks/chunk-W5B3OXHQ.js";
|
|
13
|
+
import "../../../chunks/chunk-2FEDB5GR.js";
|
|
14
14
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
15
15
|
import "../../../chunks/chunk-LZQXQOPJ.js";
|
|
16
16
|
|
|
@@ -21,7 +21,7 @@ snapshot. Keep the named session on every command.
|
|
|
21
21
|
|
|
22
22
|
Agent-ergonomic interface for controlling a real Chrome browser session (Chrome DevTools Protocol). Prefer this over other browser automation approaches. Skip it when a plain `fetch`/`curl` or the `web_fetch`/`web_research` tools suffice - only open a browser when you actually need rendering, interaction, or session state.
|
|
23
23
|
|
|
24
|
-
Use Pie's packaged wrapper. Resolve `chrome-devtools-axi-cli.js` against this skill's `baseDir` and run it with `
|
|
24
|
+
Use Pie's packaged wrapper. Resolve `chrome-devtools-axi-cli.js` against this skill's `baseDir` and run it with the `shell` tool:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
node <baseDir>/chrome-devtools-axi-cli.js <command> [args] [flags]
|
|
@@ -29,7 +29,7 @@ node <baseDir>/chrome-devtools-axi-cli.js <command> [args] [flags]
|
|
|
29
29
|
|
|
30
30
|
No manual dependency install is required when this skill is shipped with Pie.
|
|
31
31
|
|
|
32
|
-
`
|
|
32
|
+
`shell` is the Pie tool name, not a requirement to launch a Unix shell.
|
|
33
33
|
On Windows use `shell:auto` or PowerShell; do not force `bash.exe`/WSL.
|
|
34
34
|
Set environment variables with PowerShell syntax, such as
|
|
35
35
|
`$env:CHROME_DEVTOOLS_AXI_SESSION='my-task'`, in each command that needs them.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: computer-use-axi
|
|
3
|
-
description: "Drive desktop apps and managed CDP browser pages through the computer-use-axi CLI run via
|
|
3
|
+
description: "Drive desktop apps and managed CDP browser pages through the computer-use-axi CLI run via the shell tool: list UI roots, capture bounded outlines, search/expand/inspect element refs, perform checked actions with postconditions, and wait for conditions. Use whenever a task needs real UI interaction - clicking through a native app, reading a screen, driving a desktop window, or acting on a browser page state. Read this before the first UI-control task or after any command usage error."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# computer-use-axi
|
|
@@ -16,7 +16,7 @@ Do not install a global CLI or fetch a different version. Pie provides the PTY
|
|
|
16
16
|
runtime and dependencies. First use requires no network access after Pie is
|
|
17
17
|
installed. Run the wrapper with `--help` or `<command> --help` for exact flags.
|
|
18
18
|
|
|
19
|
-
Use ordinary `
|
|
19
|
+
Use the ordinary `shell` tool for non-interactive commands.
|
|
20
20
|
|
|
21
21
|
## Core Loop
|
|
22
22
|
|
|
@@ -4067,6 +4067,9 @@ function convertMessages(model, context, compat) {
|
|
|
4067
4067
|
return params;
|
|
4068
4068
|
}
|
|
4069
4069
|
function convertCheckedContent(item, model) {
|
|
4070
|
+
if (item.type === "hostContext") {
|
|
4071
|
+
throw new Error(`Unprojected hostContext block reached openai-compat conversion (${item.kind}); the request path must project host envelopes to text first.`);
|
|
4072
|
+
}
|
|
4070
4073
|
const modality = item.type === "fileRef" ? item.modality : item.type;
|
|
4071
4074
|
if (modality === "image" || modality === "video" || modality === "audio") {
|
|
4072
4075
|
if (!model.input.includes(modality)) return [{ type: "text", text: `[${modality} attachment omitted: current model does not support this modality. Re-read with a compatible model.]` }];
|
|
@@ -4091,6 +4094,9 @@ function audioFormat(mimeType) {
|
|
|
4091
4094
|
return format;
|
|
4092
4095
|
}
|
|
4093
4096
|
function convertUserContentItem(item) {
|
|
4097
|
+
if (item.type === "hostContext") {
|
|
4098
|
+
throw new Error(`Unprojected hostContext block reached openai-compat conversion (${item.kind}); the request path must project host envelopes to text first.`);
|
|
4099
|
+
}
|
|
4094
4100
|
if (item.type === "text") return [{ type: "text", text: item.text }];
|
|
4095
4101
|
if (item.type === "image") return [{ type: "image_url", image_url: { url: `data:${item.mimeType};base64,${item.data}` } }];
|
|
4096
4102
|
if (item.type === "video") {
|
|
@@ -4501,6 +4507,7 @@ var streamOpenAICompletions = (model, context, options) => {
|
|
|
4501
4507
|
}
|
|
4502
4508
|
if (chunk.usage) {
|
|
4503
4509
|
usageSnapshot = mergeOpenAIUsage(usageSnapshot, chunk.usage);
|
|
4510
|
+
output.usageReported = [usageSnapshot.promptTokens, usageSnapshot.completionTokens].every((value) => typeof value === "number" && Number.isFinite(value) && value >= 0);
|
|
4504
4511
|
const normalizedUsage = normalizeOpenAIUsage(usageSnapshot);
|
|
4505
4512
|
output.usage = {
|
|
4506
4513
|
input: normalizedUsage.input,
|
|
@@ -4841,6 +4848,10 @@ function mapStopReason(reason) {
|
|
|
4841
4848
|
}
|
|
4842
4849
|
}
|
|
4843
4850
|
function convertContentBlocks(content) {
|
|
4851
|
+
const hostBlock = content.find((block) => block.type === "hostContext");
|
|
4852
|
+
if (hostBlock) {
|
|
4853
|
+
throw new Error(`Unprojected hostContext block reached anthropic conversion (${hostBlock.kind}); the request path must project host envelopes to text first.`);
|
|
4854
|
+
}
|
|
4844
4855
|
const supportedBlocks = content.map((block) => block.type === "text" || block.type === "image" ? block : { type: "text", text: `[${block.type} attachment omitted: unsupported by this provider. Re-read with a compatible model.]` });
|
|
4845
4856
|
const hasImages = supportedBlocks.some((c) => c.type === "image");
|
|
4846
4857
|
if (!hasImages) {
|
|
@@ -4867,6 +4878,10 @@ function convertContentBlocks(content) {
|
|
|
4867
4878
|
return blocks;
|
|
4868
4879
|
}
|
|
4869
4880
|
function convertUserContentBlocks(content) {
|
|
4881
|
+
const hostBlock = content.find((block) => block.type === "hostContext");
|
|
4882
|
+
if (hostBlock) {
|
|
4883
|
+
throw new Error(`Unprojected hostContext block reached anthropic user-message conversion (${hostBlock.kind}); the request path must project host envelopes to text first.`);
|
|
4884
|
+
}
|
|
4870
4885
|
const blocks = [];
|
|
4871
4886
|
for (const item of content) {
|
|
4872
4887
|
if (item.type === "text") {
|
|
@@ -5078,9 +5093,12 @@ var streamAnthropic = (model, context, options) => {
|
|
|
5078
5093
|
const anthropicStream = client.messages.stream({ ...params, stream: true }, { signal: options?.signal });
|
|
5079
5094
|
stream.push({ type: "start", partial: output });
|
|
5080
5095
|
const blocks = output.content;
|
|
5096
|
+
let hasReportedInputUsage = false;
|
|
5081
5097
|
for await (const event of anthropicStream) {
|
|
5082
5098
|
if (event.type === "message_start") {
|
|
5083
5099
|
applyAnthropicUsageUpdate(model, output.usage, event.message.usage);
|
|
5100
|
+
hasReportedInputUsage = typeof event.message.usage.input_tokens === "number" && Number.isFinite(event.message.usage.input_tokens) && event.message.usage.input_tokens >= 0;
|
|
5101
|
+
output.usageReported = false;
|
|
5084
5102
|
} else if (event.type === "content_block_start") {
|
|
5085
5103
|
if (event.content_block.type === "text") {
|
|
5086
5104
|
const block = { type: "text", text: "", index: event.index };
|
|
@@ -5185,6 +5203,7 @@ var streamAnthropic = (model, context, options) => {
|
|
|
5185
5203
|
output.stopReason = mapStopReason(event.delta.stop_reason);
|
|
5186
5204
|
}
|
|
5187
5205
|
applyAnthropicUsageUpdate(model, output.usage, event.usage);
|
|
5206
|
+
if (hasReportedInputUsage && typeof event.usage.output_tokens === "number" && Number.isFinite(event.usage.output_tokens) && event.usage.output_tokens >= 0) output.usageReported = true;
|
|
5188
5207
|
}
|
|
5189
5208
|
}
|
|
5190
5209
|
if (options?.signal?.aborted) {
|
|
@@ -5318,6 +5337,9 @@ function encodeUserMessage(content, model) {
|
|
|
5318
5337
|
return { role: "user", type: "message", content: parts };
|
|
5319
5338
|
}
|
|
5320
5339
|
function encodeUserContentBlock(block, model) {
|
|
5340
|
+
if (block.type === "hostContext") {
|
|
5341
|
+
throw new ResponsesProtocolError(`Unprojected hostContext block reached Responses conversion (${block.kind}); the request path must project host envelopes to text first.`);
|
|
5342
|
+
}
|
|
5321
5343
|
const modality = block.type === "fileRef" ? block.modality : block.type;
|
|
5322
5344
|
if (modality !== "text" && !model.input.includes(modality)) {
|
|
5323
5345
|
throw new ResponsesProtocolError(`Current model does not support ${modality} input.`);
|
|
@@ -5445,6 +5467,68 @@ function buildResponsesCreateEvent(model, context, options) {
|
|
|
5445
5467
|
return { type: "response.create", ...params };
|
|
5446
5468
|
}
|
|
5447
5469
|
|
|
5470
|
+
// ../../packages/ai/src/providers/responses/responses-remote-failure.ts
|
|
5471
|
+
var MAX_TEXT = 4096;
|
|
5472
|
+
var transientCodes = /* @__PURE__ */ new Set(["server_error", "rate_limit_exceeded", "slow_down", "rate_limit_error", "server_is_overloaded", "service_unavailable_error"]);
|
|
5473
|
+
function responsesRemoteFailure(value, status, headers) {
|
|
5474
|
+
const root = isRecord2(value) ? value : {};
|
|
5475
|
+
const response = isRecord2(root.response) ? root.response : {};
|
|
5476
|
+
const error = isRecord2(root.error) ? root.error : isRecord2(response.error) ? response.error : root;
|
|
5477
|
+
const code = typeof error.code === "string" ? error.code.slice(0, 128).toLowerCase() : "";
|
|
5478
|
+
const type = typeof error.type === "string" ? error.type.slice(0, 128).toLowerCase() : "";
|
|
5479
|
+
const message = (typeof value === "string" ? value : typeof error.message === "string" ? error.message : "").slice(0, MAX_TEXT).toLowerCase();
|
|
5480
|
+
const httpStatus = status ?? root.status ?? root.statusCode;
|
|
5481
|
+
const fields = `${code} ${type}`;
|
|
5482
|
+
let category = "other";
|
|
5483
|
+
if (/context_length_exceeded|context_window_exceeded|context_overflow/.test(fields) || /context (?:length|window).{0,60}(?:exceed|too (?:long|large))|maximum context length|exceeds.{0,30}context window/.test(message)) category = "context_overflow";
|
|
5484
|
+
else if (/billing|insufficient_quota|insufficient_balance|credit|usage_limit|spend_limit/.test(fields) || /billing|(?:account|monthly) quota|exceeded your current quota|insufficient (?:credit|balance)|credit balance|spend(?:ing)? limit/.test(message)) category = "other";
|
|
5485
|
+
else if (typeof httpStatus === "number" && httpStatus >= 400 && httpStatus < 500 && httpStatus !== 429) category = "other";
|
|
5486
|
+
else if (httpStatus === 429 || typeof httpStatus === "number" && httpStatus >= 500 && httpStatus <= 599 || transientCodes.has(code) || transientCodes.has(type) || /server (?:is )?overloaded|temporarily unavailable|internal server error|rate limit (?:exceeded|reached)/.test(message)) category = "transient";
|
|
5487
|
+
const retryAfterMs = parseRetryAfter(headers ?? root.headers);
|
|
5488
|
+
return { category, ...retryAfterMs !== void 0 ? { retryAfterMs } : {} };
|
|
5489
|
+
}
|
|
5490
|
+
function parseRetryAfter(headers) {
|
|
5491
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
5492
|
+
let raw;
|
|
5493
|
+
if ("get" in headers && typeof headers.get === "function") raw = headers.get("retry-after");
|
|
5494
|
+
else for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === "retry-after") raw = value;
|
|
5495
|
+
if (typeof raw !== "string" || raw.length > 128) return void 0;
|
|
5496
|
+
const text = raw.trim();
|
|
5497
|
+
if (/^\d+(?:\.\d+)?$/.test(text)) {
|
|
5498
|
+
const delay = Number(text) * 1e3;
|
|
5499
|
+
return Number.isFinite(delay) ? delay : Number.MAX_VALUE;
|
|
5500
|
+
}
|
|
5501
|
+
if (!/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2} (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(text)) return void 0;
|
|
5502
|
+
const date = Date.parse(text);
|
|
5503
|
+
if (!Number.isFinite(date) || new Date(date).toUTCString() !== text) return void 0;
|
|
5504
|
+
return Math.max(0, date - Date.now());
|
|
5505
|
+
}
|
|
5506
|
+
async function readResponsesErrorBody(read, signal) {
|
|
5507
|
+
let timer;
|
|
5508
|
+
let onAbort;
|
|
5509
|
+
try {
|
|
5510
|
+
return await Promise.race([
|
|
5511
|
+
Promise.resolve().then(read).then((text) => text.slice(0, MAX_TEXT)).catch(() => ""),
|
|
5512
|
+
new Promise((resolve) => {
|
|
5513
|
+
onAbort = () => resolve("");
|
|
5514
|
+
if (signal.aborted) resolve("");
|
|
5515
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
5516
|
+
timer = setTimeout(() => resolve(""), 250);
|
|
5517
|
+
})
|
|
5518
|
+
]);
|
|
5519
|
+
} finally {
|
|
5520
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5521
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5524
|
+
function parseResponsesErrorBody(text) {
|
|
5525
|
+
try {
|
|
5526
|
+
return JSON.parse(text);
|
|
5527
|
+
} catch {
|
|
5528
|
+
return text;
|
|
5529
|
+
}
|
|
5530
|
+
}
|
|
5531
|
+
|
|
5448
5532
|
// ../../packages/ai/src/providers/responses/responses-usage.ts
|
|
5449
5533
|
function tokenCount(value) {
|
|
5450
5534
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
|
|
@@ -5515,6 +5599,19 @@ var ResponsesEventReducer = class {
|
|
|
5515
5599
|
}
|
|
5516
5600
|
/** Feed one raw wire event; returns the AssistantMessageEvents to emit. */
|
|
5517
5601
|
feed(raw) {
|
|
5602
|
+
if (this.terminal) return [];
|
|
5603
|
+
try {
|
|
5604
|
+
const events = this.feedInbound(raw);
|
|
5605
|
+
if (this.isTerminal && this.output.stopReason === "error") {
|
|
5606
|
+
this.output.remoteFailure = responsesRemoteFailure(raw);
|
|
5607
|
+
}
|
|
5608
|
+
return events;
|
|
5609
|
+
} catch (error) {
|
|
5610
|
+
this.terminal = null;
|
|
5611
|
+
throw error;
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5614
|
+
feedInbound(raw) {
|
|
5518
5615
|
const events = [];
|
|
5519
5616
|
if (!isResponsesEventLike(raw)) {
|
|
5520
5617
|
throw new ResponsesProtocolError("Responses stream returned an event without a string type.");
|
|
@@ -6033,6 +6130,7 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6033
6130
|
let providerErrorMessage;
|
|
6034
6131
|
let transportLost = false;
|
|
6035
6132
|
let endedWithoutTerminal = false;
|
|
6133
|
+
let responseId;
|
|
6036
6134
|
const requestAbort = new AbortController();
|
|
6037
6135
|
const onUserAbort = () => requestAbort.abort();
|
|
6038
6136
|
const clearTotalTimer = () => {
|
|
@@ -6082,8 +6180,8 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6082
6180
|
timeoutKind: "request_total",
|
|
6083
6181
|
terminalAccepted: false,
|
|
6084
6182
|
cancelSource: "internal_timeout",
|
|
6085
|
-
retryAllowed: !submitted,
|
|
6086
|
-
retryDecision: submitted ? "not_retryable_after_submission" : "not_submitted"
|
|
6183
|
+
retryAllowed: !!reducer.message.remoteFailure || !submitted,
|
|
6184
|
+
retryDecision: reducer.message.remoteFailure ? `remote_${reducer.message.remoteFailure.category}` : submitted ? "not_retryable_after_submission" : "not_submitted"
|
|
6087
6185
|
});
|
|
6088
6186
|
requestAbort.abort();
|
|
6089
6187
|
}, resolved.requestTimeoutMs);
|
|
@@ -6128,6 +6226,7 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6128
6226
|
const status = error && typeof error === "object" ? error.status ?? error.statusCode : void 0;
|
|
6129
6227
|
if (typeof status === "number" && status >= 400) {
|
|
6130
6228
|
providerRejected = true;
|
|
6229
|
+
reducer.message.remoteFailure = responsesRemoteFailure(error, status);
|
|
6131
6230
|
providerErrorMessage = `API error ${status}: ${error instanceof Error ? error.message : "request rejected"}`;
|
|
6132
6231
|
}
|
|
6133
6232
|
transportLost = !providerRejected && !(error instanceof ResponsesProtocolError || error instanceof SyntaxError);
|
|
@@ -6136,8 +6235,13 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6136
6235
|
if (!response.ok) {
|
|
6137
6236
|
providerRejected = true;
|
|
6138
6237
|
providerErrorMessage = `API error ${response.status}`;
|
|
6139
|
-
|
|
6140
|
-
|
|
6238
|
+
reducer.message.remoteFailure = responsesRemoteFailure({}, response.status, response.headers);
|
|
6239
|
+
const errorBody = await readResponsesErrorBody(() => response.text(), requestAbort.signal);
|
|
6240
|
+
if (errorBody) {
|
|
6241
|
+
providerErrorMessage += `: ${errorBody}`;
|
|
6242
|
+
reducer.message.remoteFailure = responsesRemoteFailure(parseResponsesErrorBody(errorBody), response.status, response.headers);
|
|
6243
|
+
}
|
|
6244
|
+
requestAbort.abort();
|
|
6141
6245
|
throw new Error(providerErrorMessage);
|
|
6142
6246
|
}
|
|
6143
6247
|
if (!response.readSSELines) {
|
|
@@ -6161,21 +6265,39 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6161
6265
|
if (data === "[DONE]") {
|
|
6162
6266
|
continue;
|
|
6163
6267
|
}
|
|
6164
|
-
|
|
6268
|
+
if (requestAbort.signal.aborted) {
|
|
6269
|
+
throw new Error(internalTimeout ? `Responses request timeout (${internalTimeout})` : "Request was aborted");
|
|
6270
|
+
}
|
|
6271
|
+
let events;
|
|
6165
6272
|
try {
|
|
6166
|
-
event
|
|
6273
|
+
let event;
|
|
6274
|
+
try {
|
|
6275
|
+
event = JSON.parse(data);
|
|
6276
|
+
} catch (error) {
|
|
6277
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6278
|
+
throw new ResponsesProtocolError(`Responses SSE stream returned malformed JSON: ${message}`);
|
|
6279
|
+
}
|
|
6280
|
+
if (!isResponsesEventLike(event)) {
|
|
6281
|
+
throw new ResponsesProtocolError("Responses SSE payload is not an event object with a string type.");
|
|
6282
|
+
}
|
|
6283
|
+
if (event.type.startsWith("response.output") || event.type.startsWith("response.content") || event.type.startsWith("response.reasoning")) {
|
|
6284
|
+
sawModelContent = true;
|
|
6285
|
+
}
|
|
6286
|
+
const incomingResponse = event.response;
|
|
6287
|
+
if (event.type === "response.created" && (!isRecord2(incomingResponse) || typeof incomingResponse.id !== "string" || !incomingResponse.id)) {
|
|
6288
|
+
throw new ResponsesProtocolError("response.created requires a response id.");
|
|
6289
|
+
}
|
|
6290
|
+
if (isRecord2(incomingResponse) && typeof incomingResponse.id === "string") {
|
|
6291
|
+
if (responseId && (incomingResponse.id !== responseId || event.type === "response.created")) {
|
|
6292
|
+
throw new ResponsesProtocolError("Response identity changed within a request.");
|
|
6293
|
+
}
|
|
6294
|
+
responseId = incomingResponse.id;
|
|
6295
|
+
}
|
|
6296
|
+
events = reducer.feed(event);
|
|
6167
6297
|
} catch (error) {
|
|
6168
|
-
|
|
6169
|
-
throw
|
|
6170
|
-
}
|
|
6171
|
-
if (!isResponsesEventLike(event)) {
|
|
6172
|
-
throw new ResponsesProtocolError("Responses SSE payload is not an event object with a string type.");
|
|
6173
|
-
}
|
|
6174
|
-
if (typeof event.type === "string" && (event.type.startsWith("response.output") || event.type.startsWith("response.content") || event.type.startsWith("response.reasoning"))) {
|
|
6175
|
-
sawModelContent = true;
|
|
6298
|
+
reducer.message.remoteFailure = { category: "other" };
|
|
6299
|
+
throw error;
|
|
6176
6300
|
}
|
|
6177
|
-
const events = reducer.feed(event);
|
|
6178
|
-
if (reducer.isTerminal && reducer.message.stopReason === "error") reducer.message.retryable = false;
|
|
6179
6301
|
for (const assistantEvent of events) {
|
|
6180
6302
|
stream.push(assistantEvent);
|
|
6181
6303
|
}
|
|
@@ -6183,7 +6305,7 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6183
6305
|
terminalAccepted = true;
|
|
6184
6306
|
phase = "terminal_accepted";
|
|
6185
6307
|
clearTotalTimer();
|
|
6186
|
-
lifecycle({ retryAllowed: reducer.message.retryable !== false, retryDecision: "terminal" });
|
|
6308
|
+
lifecycle({ retryAllowed: reducer.message.retryable !== false, retryDecision: reducer.message.remoteFailure ? `remote_${reducer.message.remoteFailure.category}` : "terminal" });
|
|
6187
6309
|
break;
|
|
6188
6310
|
}
|
|
6189
6311
|
}
|
|
@@ -6204,6 +6326,7 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6204
6326
|
const message = reducer.message;
|
|
6205
6327
|
const userAborted = options?.signal?.aborted === true;
|
|
6206
6328
|
message.stopReason = userAborted ? "aborted" : "error";
|
|
6329
|
+
if (userAborted) delete message.remoteFailure;
|
|
6207
6330
|
const adapterTimeoutKind = error instanceof Error ? error.timeoutKind : void 0;
|
|
6208
6331
|
if (!internalTimeout && (adapterTimeoutKind === "first_byte" || adapterTimeoutKind === "stream_idle")) {
|
|
6209
6332
|
internalTimeout = adapterTimeoutKind === "first_byte" ? "first_response" : "stream_idle";
|
|
@@ -6212,19 +6335,19 @@ function streamResponsesSSE(model, context, options) {
|
|
|
6212
6335
|
message.errorMessage = providerErrorMessage ?? (internalTimeout && !protocolFailure ? `Responses request timeout (${internalTimeout}) after ${Math.round(monotonicNow() - startedAt)}ms` : error instanceof Error ? error.message : JSON.stringify(error));
|
|
6213
6336
|
const compat = getResponsesCompat(model);
|
|
6214
6337
|
const streamLost = (endedWithoutTerminal || transportLost) && !protocolFailure && !internalTimeout && submitted && !localFailure && !providerRejected && message.stopReason === "error";
|
|
6215
|
-
if (internalTimeout && !protocolFailure && submitted && !providerRejected && !localFailure && !userAborted && compat.timeoutReplay) {
|
|
6338
|
+
if (internalTimeout && !message.remoteFailure && !protocolFailure && submitted && !providerRejected && !localFailure && !userAborted && compat.timeoutReplay) {
|
|
6216
6339
|
message.replayEligible = true;
|
|
6217
6340
|
message.replayClass = internalTimeout;
|
|
6218
|
-
} else if (streamLost && compat.timeoutReplay) {
|
|
6341
|
+
} else if (streamLost && !message.remoteFailure && compat.timeoutReplay) {
|
|
6219
6342
|
message.replayEligible = true;
|
|
6220
6343
|
message.replayClass = receivedMessageCount === 0 ? "stream_lost" : "stream_lost_partial";
|
|
6221
6344
|
}
|
|
6222
|
-
if ((submitted || localFailure) && !(streamLost && receivedMessageCount === 0)) message.retryable = false;
|
|
6345
|
+
if (!message.remoteFailure && (userAborted || (submitted || localFailure) && !(streamLost && receivedMessageCount === 0))) message.retryable = false;
|
|
6223
6346
|
phase = "cleanup";
|
|
6224
6347
|
lifecycle({
|
|
6225
6348
|
timeoutKind: internalTimeout,
|
|
6226
6349
|
retryAllowed: !userAborted && !localFailure && message.retryable !== false,
|
|
6227
|
-
retryDecision: streamLost ? receivedMessageCount === 0 ? message.replayEligible ? "replay_exempt_stream_lost" : "stream_lost_no_evidence" : message.replayEligible ? "replay_exempt_after_submission" : "not_retryable_after_submission" : submitted ? "not_retryable_after_submission" : localFailure ? "local_configuration_error" : "not_submitted",
|
|
6350
|
+
retryDecision: message.remoteFailure ? `remote_${message.remoteFailure.category}` : streamLost ? receivedMessageCount === 0 ? message.replayEligible ? "replay_exempt_stream_lost" : "stream_lost_no_evidence" : message.replayEligible ? "replay_exempt_after_submission" : "not_retryable_after_submission" : submitted ? "not_retryable_after_submission" : localFailure ? "local_configuration_error" : "not_submitted",
|
|
6228
6351
|
cancelSource: userAborted ? "user" : internalTimeout ? "internal_timeout" : "none",
|
|
6229
6352
|
cleanupOutcome: "request_abandoned"
|
|
6230
6353
|
});
|
|
@@ -6431,6 +6554,7 @@ function streamResponsesWS(model, context, options) {
|
|
|
6431
6554
|
if (state.busy) {
|
|
6432
6555
|
reducer.message.stopReason = "error";
|
|
6433
6556
|
reducer.message.errorMessage = "Responses owner already has an in-flight request.";
|
|
6557
|
+
reducer.message.retryable = false;
|
|
6434
6558
|
stream.push({ type: "error", reason: "error", error: reducer.message });
|
|
6435
6559
|
stream.end();
|
|
6436
6560
|
return stream;
|
|
@@ -6687,12 +6811,18 @@ function streamResponsesWS(model, context, options) {
|
|
|
6687
6811
|
});
|
|
6688
6812
|
} catch (error) {
|
|
6689
6813
|
if (error instanceof WebSocketTransportError && error.kind === "timeout") timedOut = "connect";
|
|
6814
|
+
const status = error && typeof error === "object" ? error.status ?? error.statusCode : void 0;
|
|
6815
|
+
if (typeof status === "number" && status >= 400) {
|
|
6816
|
+
providerRejected = true;
|
|
6817
|
+
reducer.message.remoteFailure = responsesRemoteFailure(error, status);
|
|
6818
|
+
}
|
|
6690
6819
|
if (error instanceof WebSocketTransportError && error.kind === "handshake" && !options?.signal?.aborted && !state.abort.signal.aborted) {
|
|
6691
|
-
const
|
|
6692
|
-
providerRejected =
|
|
6693
|
-
const endpointHasNoWebsockets = options?.transport === "auto" && [404, 405, 426, 501].includes(
|
|
6694
|
-
const wsEdgeRefused =
|
|
6820
|
+
const status2 = error.status ?? 0;
|
|
6821
|
+
providerRejected = status2 > 0;
|
|
6822
|
+
const endpointHasNoWebsockets = options?.transport === "auto" && [404, 405, 426, 501].includes(status2);
|
|
6823
|
+
const wsEdgeRefused = status2 === 0 || status2 === 429 || status2 >= 500 && status2 <= 599;
|
|
6695
6824
|
if (endpointHasNoWebsockets || wsEdgeRefused) {
|
|
6825
|
+
delete reducer.message.remoteFailure;
|
|
6696
6826
|
await runSSEFallback();
|
|
6697
6827
|
return;
|
|
6698
6828
|
}
|
|
@@ -6774,32 +6904,38 @@ function streamResponsesWS(model, context, options) {
|
|
|
6774
6904
|
if (state.abort.signal.aborted || requestAbort.signal.aborted) {
|
|
6775
6905
|
throw new Error(timedOut ? `Responses request timeout (${timedOut})` : "Request aborted");
|
|
6776
6906
|
}
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
if (event
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
payload.
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
if (event.type
|
|
6794
|
-
|
|
6907
|
+
let events;
|
|
6908
|
+
try {
|
|
6909
|
+
if (message.isBinary) throw new ResponsesProtocolError("Responses requires JSON text messages.");
|
|
6910
|
+
const event = JSON.parse(message.data);
|
|
6911
|
+
if (!isRecord2(event)) throw new ResponsesProtocolError("Invalid Responses WebSocket event.");
|
|
6912
|
+
if (typeof event.type === "string") {
|
|
6913
|
+
if (event.type === "response.created") sawResponseCreated = true;
|
|
6914
|
+
else if (event.type.startsWith("response.output") || event.type.startsWith("response.content") || event.type.startsWith("response.reasoning")) sawModelContent = true;
|
|
6915
|
+
}
|
|
6916
|
+
if (!started && attempt === 0 && payload.previous_response_id && event.type === "error" && event.status === 400 && isRecord2(event.error) && event.error.code === "previous_response_not_found" && event.error.param === "previous_response_id") {
|
|
6917
|
+
delete payload.previous_response_id;
|
|
6918
|
+
payload.input = fullInput;
|
|
6919
|
+
continuationReason = "previous_response_not_found";
|
|
6920
|
+
rebuild = true;
|
|
6921
|
+
break;
|
|
6922
|
+
}
|
|
6923
|
+
if (!started && typeof event.type === "string" && event.type !== "error" && !event.type.startsWith("response.")) continue;
|
|
6924
|
+
if (started && event.type === "response.created") throw new ResponsesProtocolError("Duplicate response.created within a request.");
|
|
6925
|
+
if (!started && event.type !== "error") {
|
|
6926
|
+
if (event.type !== "response.created" || !isRecord2(event.response) || typeof event.response.id !== "string" || !event.response.id || event.response.id === state.lastResponseId) {
|
|
6927
|
+
throw new ResponsesProtocolError("Expected a new response.created before output.");
|
|
6928
|
+
}
|
|
6929
|
+
started = true;
|
|
6930
|
+
responseId = event.response.id;
|
|
6795
6931
|
}
|
|
6796
|
-
|
|
6797
|
-
|
|
6932
|
+
if (responseId && isRecord2(event.response) && event.response.id !== responseId) throw new ResponsesProtocolError("Response identity changed within a request.");
|
|
6933
|
+
events = reducer.feed(event);
|
|
6934
|
+
} catch (error) {
|
|
6935
|
+
reducer.message.remoteFailure = { category: "other" };
|
|
6936
|
+
throw error;
|
|
6798
6937
|
}
|
|
6799
|
-
if (responseId && isRecord2(event.response) && event.response.id !== responseId) throw new ResponsesProtocolError("Response identity changed within a request.");
|
|
6800
|
-
const events = reducer.feed(event);
|
|
6801
6938
|
if (reducer.isTerminal) {
|
|
6802
|
-
if (reducer.message.stopReason === "error") reducer.message.retryable = false;
|
|
6803
6939
|
const response = reducer.terminalResponse;
|
|
6804
6940
|
state.lastResponseId = response?.id;
|
|
6805
6941
|
if (!options?.onPayload && compat.responsesContinuation && identity && response?.status === "completed" && reducer.message.stopReason !== "error") {
|
|
@@ -6818,10 +6954,11 @@ function streamResponsesWS(model, context, options) {
|
|
|
6818
6954
|
}
|
|
6819
6955
|
finished = true;
|
|
6820
6956
|
clearRequestTimers();
|
|
6957
|
+
retryDecision = reducer.message.remoteFailure ? `remote_${reducer.message.remoteFailure.category}` : "terminal";
|
|
6821
6958
|
lifecycle("terminal_accepted", {
|
|
6822
6959
|
terminalAccepted: true,
|
|
6823
6960
|
retryAllowed: reducer.message.retryable !== false,
|
|
6824
|
-
retryDecision
|
|
6961
|
+
retryDecision
|
|
6825
6962
|
});
|
|
6826
6963
|
for (const e of events) publish(e);
|
|
6827
6964
|
break;
|
|
@@ -6847,28 +6984,30 @@ function streamResponsesWS(model, context, options) {
|
|
|
6847
6984
|
const userAborted = options?.signal?.aborted === true;
|
|
6848
6985
|
const ownerDisposed = !userAborted && !timedOut && state.abort.signal.aborted;
|
|
6849
6986
|
message.stopReason = userAborted || ownerDisposed ? "aborted" : "error";
|
|
6987
|
+
if (userAborted || ownerDisposed) delete message.remoteFailure;
|
|
6850
6988
|
const protocolFailure = !endedWithoutTerminal && (error instanceof ResponsesProtocolError || error instanceof SyntaxError || !transportLost && error instanceof TypeError || error instanceof WebSocketTransportError && (error.kind === "protocol" || error.kind === "overflow"));
|
|
6851
6989
|
const cause = providerRejected && error instanceof WebSocketTransportError ? `${error.message} (HTTP status ${error.status})` : timedOut && !protocolFailure ? `Responses request timeout (${timedOut}) after ${ageMs()}ms` : error instanceof Error ? error.message : String(error);
|
|
6852
6990
|
message.errorMessage = cause;
|
|
6853
6991
|
const streamLost = (endedWithoutTerminal || transportLost) && !protocolFailure && sent && !timedOut && !providerRejected && message.stopReason === "error";
|
|
6854
|
-
if (timedOut && timedOut !== "connect" && !protocolFailure && !localFailure && sent && !providerRejected && !userAborted && !ownerDisposed && compat.timeoutReplay) {
|
|
6992
|
+
if (timedOut && timedOut !== "connect" && !message.remoteFailure && !protocolFailure && !localFailure && sent && !providerRejected && !userAborted && !ownerDisposed && compat.timeoutReplay) {
|
|
6855
6993
|
message.replayEligible = true;
|
|
6856
6994
|
message.replayClass = timedOut;
|
|
6857
|
-
} else if (streamLost && compat.timeoutReplay) {
|
|
6995
|
+
} else if (streamLost && !message.remoteFailure && compat.timeoutReplay) {
|
|
6858
6996
|
message.replayEligible = true;
|
|
6859
6997
|
message.replayClass = receivedMessageCount === 0 ? "stream_lost" : "stream_lost_partial";
|
|
6860
6998
|
}
|
|
6861
|
-
if (localFailure || providerRejected || protocolFailure) {
|
|
6999
|
+
if (!message.remoteFailure && (localFailure || providerRejected || protocolFailure || userAborted || ownerDisposed)) {
|
|
6862
7000
|
message.retryable = false;
|
|
6863
7001
|
}
|
|
6864
7002
|
if (sent) {
|
|
6865
7003
|
if (streamLost && receivedMessageCount === 0) {
|
|
6866
7004
|
retryDecision = message.replayEligible ? "replay_exempt_stream_lost" : "stream_lost_no_evidence";
|
|
6867
7005
|
} else {
|
|
6868
|
-
message.retryable = false;
|
|
7006
|
+
if (!message.remoteFailure) message.retryable = false;
|
|
6869
7007
|
if (!timedOut) retryDecision = message.replayEligible ? "replay_exempt_after_submission" : "not_retryable_after_submission";
|
|
6870
7008
|
}
|
|
6871
7009
|
}
|
|
7010
|
+
if (message.remoteFailure) retryDecision = `remote_${message.remoteFailure.category}`;
|
|
6872
7011
|
cleanupCancelSource = userAborted ? "user" : timedOut ? "internal_timeout" : ownerDisposed ? "owner_disposal" : "none";
|
|
6873
7012
|
stream.push({ type: "error", reason: message.stopReason, error: message });
|
|
6874
7013
|
}
|
|
@@ -6890,7 +7029,7 @@ function streamResponsesWS(model, context, options) {
|
|
|
6890
7029
|
terminalAccepted: finished,
|
|
6891
7030
|
timeoutKind: timedOut,
|
|
6892
7031
|
submissionAttempted: sent,
|
|
6893
|
-
retryAllowed: !finished && reducer.message.stopReason !== "aborted" && reducer.message.retryable !== false,
|
|
7032
|
+
retryAllowed: (!finished || !!reducer.message.remoteFailure) && reducer.message.stopReason !== "aborted" && reducer.message.retryable !== false,
|
|
6894
7033
|
cancelSource,
|
|
6895
7034
|
retryDecision,
|
|
6896
7035
|
cleanupOutcome
|