ai-sdk-provider-codex-cli 1.3.1 → 2.1.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 +61 -48
- package/dist/index.d.ts +155 -26
- package/dist/index.js +429 -235
- package/package.json +9 -15
- package/dist/index.cjs +0 -5926
- package/dist/index.d.cts +0 -806
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { mkdtempSync, writeFileSync, rmSync, readFileSync } from 'fs';
|
|
|
6
6
|
import { tmpdir } from 'os';
|
|
7
7
|
import path, { join, dirname } from 'path';
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
-
import { generateId, parseProviderOptions } from '@ai-sdk/provider-utils';
|
|
9
|
+
import { generateId, parseProviderOptions, getTopLevelMediaType, isFullMediaType, detectMediaType } from '@ai-sdk/provider-utils';
|
|
10
10
|
import { createServer } from 'http';
|
|
11
11
|
import { EventEmitter } from 'events';
|
|
12
12
|
import readline from 'readline';
|
|
@@ -324,75 +324,41 @@ function validateModelId(modelId) {
|
|
|
324
324
|
if (!modelId || modelId.trim() === "") return "Model ID cannot be empty";
|
|
325
325
|
return void 0;
|
|
326
326
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (value === void 0) return "";
|
|
331
|
-
if (typeof value === "string") return value;
|
|
332
|
-
try {
|
|
333
|
-
return JSON.stringify(value);
|
|
334
|
-
} catch {
|
|
335
|
-
return "[unserializable]";
|
|
336
|
-
}
|
|
327
|
+
function isTaggedFileData(value) {
|
|
328
|
+
if (typeof value !== "object" || value === null || !("type" in value)) return false;
|
|
329
|
+
return value.type === "data" || value.type === "url" || value.type === "reference" || value.type === "text";
|
|
337
330
|
}
|
|
338
|
-
function
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
warnings: []
|
|
348
|
-
};
|
|
349
|
-
case "error-text":
|
|
350
|
-
return { text: `Tool error: ${output.value}`, warnings: [] };
|
|
351
|
-
case "error-json":
|
|
352
|
-
return { text: `Tool error: ${safeJsonStringify(output.value)}`, warnings: [] };
|
|
353
|
-
case "content": {
|
|
354
|
-
const warnings = [];
|
|
355
|
-
const parts = output.value.map((part) => {
|
|
356
|
-
if (part.type === "text") return part.text;
|
|
357
|
-
if (part.type === "file-data") {
|
|
358
|
-
return `[file-data: ${part.mediaType}${part.filename ? `, ${part.filename}` : ""}]`;
|
|
359
|
-
}
|
|
360
|
-
if (part.type === "file-url") return `[file-url: ${part.url}]`;
|
|
361
|
-
if (part.type === "file-id") return "[file-id]";
|
|
362
|
-
if (part.type === "image-data") return `[image-data: ${part.mediaType}]`;
|
|
363
|
-
if (part.type === "image-url") return `[image-url: ${part.url}]`;
|
|
364
|
-
if (part.type === "image-file-id") return "[image-file-id]";
|
|
365
|
-
warnings.push({
|
|
366
|
-
type: "unsupported",
|
|
367
|
-
feature: `tool-result.content.${String(part.type)}`,
|
|
368
|
-
details: `Unsupported tool content part "${String(part.type)}".`
|
|
369
|
-
});
|
|
370
|
-
return "[unsupported-tool-content-part]";
|
|
371
|
-
}).filter((part) => part.length > 0);
|
|
372
|
-
return { text: parts.join("\n"), warnings };
|
|
373
|
-
}
|
|
374
|
-
default:
|
|
375
|
-
return {
|
|
376
|
-
text: "[unsupported-tool-result-output]",
|
|
377
|
-
warnings: [
|
|
378
|
-
{
|
|
379
|
-
type: "unsupported",
|
|
380
|
-
feature: `tool-result.output.${String(output.type)}`,
|
|
381
|
-
details: `Unsupported tool result output type "${String(output.type)}".`
|
|
382
|
-
}
|
|
383
|
-
]
|
|
384
|
-
};
|
|
331
|
+
function resolveImageMimeType(declaredType, data) {
|
|
332
|
+
if (isFullMediaType(declaredType)) return declaredType;
|
|
333
|
+
const bytes = typeof data === "string" || data instanceof Uint8Array ? data : data instanceof ArrayBuffer ? new Uint8Array(data) : void 0;
|
|
334
|
+
if (bytes !== void 0) {
|
|
335
|
+
const detected = detectMediaType({
|
|
336
|
+
data: bytes,
|
|
337
|
+
topLevelType: getTopLevelMediaType(declaredType)
|
|
338
|
+
});
|
|
339
|
+
if (detected) return detected;
|
|
385
340
|
}
|
|
341
|
+
return "image/png";
|
|
386
342
|
}
|
|
387
343
|
function extractImageData(part) {
|
|
388
344
|
if (typeof part !== "object" || part === null) return null;
|
|
389
345
|
const p = part;
|
|
390
346
|
const isFilePart2 = p.type === "file";
|
|
391
|
-
const
|
|
392
|
-
if (isFilePart2 &&
|
|
347
|
+
const declaredType = isFilePart2 ? p.mediaType || "image/png" : p.mimeType || "image/png";
|
|
348
|
+
if (isFilePart2 && getTopLevelMediaType(declaredType).toLowerCase() !== "image") {
|
|
393
349
|
return null;
|
|
394
350
|
}
|
|
395
|
-
|
|
351
|
+
let primaryInput = isFilePart2 ? p.data : p.image;
|
|
352
|
+
if (isTaggedFileData(primaryInput)) {
|
|
353
|
+
if (primaryInput.type === "data") {
|
|
354
|
+
primaryInput = primaryInput.data;
|
|
355
|
+
} else if (primaryInput.type === "url") {
|
|
356
|
+
primaryInput = primaryInput.url;
|
|
357
|
+
} else {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const mimeType = resolveImageMimeType(declaredType, primaryInput);
|
|
396
362
|
if (typeof primaryInput === "string") {
|
|
397
363
|
return extractFromString(primaryInput, mimeType);
|
|
398
364
|
}
|
|
@@ -538,14 +504,18 @@ function asRemoteUrl(value) {
|
|
|
538
504
|
return void 0;
|
|
539
505
|
}
|
|
540
506
|
function isImageMediaType(mediaType) {
|
|
541
|
-
return mediaType.toLowerCase()
|
|
507
|
+
return getTopLevelMediaType(mediaType).toLowerCase() === "image";
|
|
542
508
|
}
|
|
543
509
|
function isFilePart(part) {
|
|
544
|
-
return part.type === "file" && typeof part.mediaType === "string";
|
|
510
|
+
return part.type === "file" && "mediaType" in part && typeof part.mediaType === "string";
|
|
545
511
|
}
|
|
546
512
|
function isCompatImagePart(part) {
|
|
547
513
|
return part.type === "image";
|
|
548
514
|
}
|
|
515
|
+
function isTaggedFileData2(value) {
|
|
516
|
+
if (typeof value !== "object" || value === null || !("type" in value)) return false;
|
|
517
|
+
return value.type === "data" || value.type === "url" || value.type === "reference" || value.type === "text";
|
|
518
|
+
}
|
|
549
519
|
function toImageReference(part) {
|
|
550
520
|
if (isFilePart(part)) {
|
|
551
521
|
if (!isImageMediaType(part.mediaType)) {
|
|
@@ -554,7 +524,42 @@ function toImageReference(part) {
|
|
|
554
524
|
warning: `Unsupported file mediaType "${part.mediaType}"; only image/* is supported.`
|
|
555
525
|
};
|
|
556
526
|
}
|
|
557
|
-
const
|
|
527
|
+
const data = part.data;
|
|
528
|
+
if (isTaggedFileData2(data)) {
|
|
529
|
+
if (data.type === "reference") {
|
|
530
|
+
return {
|
|
531
|
+
kind: "unsupported",
|
|
532
|
+
warning: "File reference data is not supported for images."
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
if (data.type === "text") {
|
|
536
|
+
return {
|
|
537
|
+
kind: "unsupported",
|
|
538
|
+
warning: "Inline text file data is not supported for images."
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
if (data.type === "url") {
|
|
542
|
+
const remote2 = asRemoteUrl(data.url);
|
|
543
|
+
if (remote2) {
|
|
544
|
+
return { kind: "remote", url: remote2 };
|
|
545
|
+
}
|
|
546
|
+
if (isFileUrlValue(data.url)) {
|
|
547
|
+
return {
|
|
548
|
+
kind: "unsupported",
|
|
549
|
+
warning: "file:// image URLs are not supported."
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
const image2 = extractImageData(part);
|
|
554
|
+
if (image2) {
|
|
555
|
+
return { kind: "local", image: image2 };
|
|
556
|
+
}
|
|
557
|
+
return {
|
|
558
|
+
kind: "unsupported",
|
|
559
|
+
warning: "Unsupported image format in message."
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
const remote = asRemoteUrl(data);
|
|
558
563
|
if (remote) {
|
|
559
564
|
return { kind: "remote", url: remote };
|
|
560
565
|
}
|
|
@@ -562,7 +567,7 @@ function toImageReference(part) {
|
|
|
562
567
|
if (image) {
|
|
563
568
|
return { kind: "local", image };
|
|
564
569
|
}
|
|
565
|
-
if (isFileUrlValue(
|
|
570
|
+
if (isFileUrlValue(data) || "url" in part && isFileUrlValue(part.url)) {
|
|
566
571
|
return {
|
|
567
572
|
kind: "unsupported",
|
|
568
573
|
warning: "file:// image URLs are not supported."
|
|
@@ -596,6 +601,90 @@ function toImageReference(part) {
|
|
|
596
601
|
return void 0;
|
|
597
602
|
}
|
|
598
603
|
|
|
604
|
+
// src/converters/tool-result-converter.ts
|
|
605
|
+
function safeJsonStringify(value) {
|
|
606
|
+
if (value === void 0) return "";
|
|
607
|
+
if (typeof value === "string") return value;
|
|
608
|
+
try {
|
|
609
|
+
return JSON.stringify(value);
|
|
610
|
+
} catch {
|
|
611
|
+
return "[unserializable]";
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
function describeTypeTag(value) {
|
|
615
|
+
if (typeof value === "object" && value !== null && "type" in value) {
|
|
616
|
+
return String(value.type);
|
|
617
|
+
}
|
|
618
|
+
return "unknown";
|
|
619
|
+
}
|
|
620
|
+
function formatToolResultOutput(output) {
|
|
621
|
+
switch (output.type) {
|
|
622
|
+
case "text":
|
|
623
|
+
return { text: output.value, warnings: [] };
|
|
624
|
+
case "json":
|
|
625
|
+
return { text: safeJsonStringify(output.value), warnings: [] };
|
|
626
|
+
case "execution-denied":
|
|
627
|
+
return {
|
|
628
|
+
text: output.reason ? `Execution denied: ${output.reason}` : "Execution denied",
|
|
629
|
+
warnings: []
|
|
630
|
+
};
|
|
631
|
+
case "error-text":
|
|
632
|
+
return { text: `Tool error: ${output.value}`, warnings: [] };
|
|
633
|
+
case "error-json":
|
|
634
|
+
return { text: `Tool error: ${safeJsonStringify(output.value)}`, warnings: [] };
|
|
635
|
+
case "content": {
|
|
636
|
+
const warnings = [];
|
|
637
|
+
const parts = output.value.map((part) => {
|
|
638
|
+
if (part.type === "text") return part.text;
|
|
639
|
+
if (part.type === "file") {
|
|
640
|
+
const prefix = isImageMediaType(part.mediaType) ? "image" : "file";
|
|
641
|
+
const data = part.data;
|
|
642
|
+
if (data.type === "data") {
|
|
643
|
+
return prefix === "image" ? `[image-data: ${part.mediaType}]` : `[file-data: ${part.mediaType}${part.filename ? `, ${part.filename}` : ""}]`;
|
|
644
|
+
}
|
|
645
|
+
if (data.type === "url") return `[${prefix}-url: ${data.url}]`;
|
|
646
|
+
if (data.type === "reference") {
|
|
647
|
+
return prefix === "image" ? "[image-file-id]" : "[file-id]";
|
|
648
|
+
}
|
|
649
|
+
if (data.type === "text") return data.text;
|
|
650
|
+
warnings.push({
|
|
651
|
+
type: "unsupported",
|
|
652
|
+
feature: "tool-result.content.file",
|
|
653
|
+
details: `Unsupported tool file content data type "${describeTypeTag(data)}".`
|
|
654
|
+
});
|
|
655
|
+
return "[unsupported-tool-content-part]";
|
|
656
|
+
}
|
|
657
|
+
if (part.type === "custom") {
|
|
658
|
+
warnings.push({
|
|
659
|
+
type: "unsupported",
|
|
660
|
+
feature: "tool-result.content.custom",
|
|
661
|
+
details: "Custom tool content parts are not supported."
|
|
662
|
+
});
|
|
663
|
+
return "";
|
|
664
|
+
}
|
|
665
|
+
warnings.push({
|
|
666
|
+
type: "unsupported",
|
|
667
|
+
feature: `tool-result.content.${describeTypeTag(part)}`,
|
|
668
|
+
details: `Unsupported tool content part "${describeTypeTag(part)}".`
|
|
669
|
+
});
|
|
670
|
+
return "[unsupported-tool-content-part]";
|
|
671
|
+
}).filter((part) => part.length > 0);
|
|
672
|
+
return { text: parts.join("\n"), warnings };
|
|
673
|
+
}
|
|
674
|
+
default:
|
|
675
|
+
return {
|
|
676
|
+
text: "[unsupported-tool-result-output]",
|
|
677
|
+
warnings: [
|
|
678
|
+
{
|
|
679
|
+
type: "unsupported",
|
|
680
|
+
feature: `tool-result.output.${describeTypeTag(output)}`,
|
|
681
|
+
details: `Unsupported tool result output type "${describeTypeTag(output)}".`
|
|
682
|
+
}
|
|
683
|
+
]
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
599
688
|
// src/converters/prompt-converter.ts
|
|
600
689
|
function isTextPart(part) {
|
|
601
690
|
return part.type === "text" && typeof part.text === "string";
|
|
@@ -730,6 +819,23 @@ function formatAssistantParts(parts) {
|
|
|
730
819
|
lines.push(`[assistant-file: ${part.mediaType}]`);
|
|
731
820
|
continue;
|
|
732
821
|
}
|
|
822
|
+
if (part.type === "custom") {
|
|
823
|
+
const kind = "kind" in part && typeof part.kind === "string" ? part.kind : void 0;
|
|
824
|
+
warnings.push({
|
|
825
|
+
type: "unsupported",
|
|
826
|
+
feature: "prompt.assistant.custom",
|
|
827
|
+
details: `Custom content parts are not supported${kind ? ` (kind "${kind}")` : ""}.`
|
|
828
|
+
});
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
if (part.type === "reasoning-file") {
|
|
832
|
+
warnings.push({
|
|
833
|
+
type: "unsupported",
|
|
834
|
+
feature: "prompt.assistant.reasoning-file",
|
|
835
|
+
details: "Reasoning file parts are not supported."
|
|
836
|
+
});
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
733
839
|
warnings.push({
|
|
734
840
|
type: "unsupported",
|
|
735
841
|
feature: `prompt.assistant.${part.type}`,
|
|
@@ -1146,7 +1252,11 @@ function mapUnsupportedSettingsWarnings(options) {
|
|
|
1146
1252
|
add(options.stopSequences?.length ? options.stopSequences : void 0, "stopSequences");
|
|
1147
1253
|
add(options.seed, "seed");
|
|
1148
1254
|
add(options.tools, "tools");
|
|
1149
|
-
|
|
1255
|
+
const toolChoice = options.toolChoice;
|
|
1256
|
+
add(
|
|
1257
|
+
toolChoice !== void 0 && toolChoice.type === "auto" ? void 0 : toolChoice,
|
|
1258
|
+
"toolChoice"
|
|
1259
|
+
);
|
|
1150
1260
|
return unsupported;
|
|
1151
1261
|
}
|
|
1152
1262
|
function mcpServersToConfigOverrides(mcpServers, rmcpClient) {
|
|
@@ -1200,6 +1310,14 @@ function mcpServersToConfigOverrides(mcpServers, rmcpClient) {
|
|
|
1200
1310
|
}
|
|
1201
1311
|
|
|
1202
1312
|
// src/exec-language-model.ts
|
|
1313
|
+
var codexReasoningEfforts = {
|
|
1314
|
+
none: true,
|
|
1315
|
+
minimal: true,
|
|
1316
|
+
low: true,
|
|
1317
|
+
medium: true,
|
|
1318
|
+
high: true,
|
|
1319
|
+
xhigh: true
|
|
1320
|
+
};
|
|
1203
1321
|
var codexCliProviderOptionsSchema = z.object({
|
|
1204
1322
|
reasoningEffort: z.enum(["none", "minimal", "low", "medium", "high", "xhigh"]).optional(),
|
|
1205
1323
|
reasoningSummary: z.enum(["auto", "detailed"]).optional(),
|
|
@@ -1240,12 +1358,9 @@ function resolveCodexPath(explicitPath, allowNpx) {
|
|
|
1240
1358
|
}
|
|
1241
1359
|
}
|
|
1242
1360
|
var ExecLanguageModel = class {
|
|
1243
|
-
specificationVersion = "
|
|
1361
|
+
specificationVersion = "v4";
|
|
1244
1362
|
provider = "codex-cli";
|
|
1245
|
-
defaultObjectGenerationMode = "json";
|
|
1246
|
-
supportsImageUrls = false;
|
|
1247
1363
|
supportedUrls = {};
|
|
1248
|
-
supportsStructuredOutputs = true;
|
|
1249
1364
|
modelId;
|
|
1250
1365
|
settings;
|
|
1251
1366
|
logger;
|
|
@@ -1874,7 +1989,22 @@ var ExecLanguageModel = class {
|
|
|
1874
1989
|
providerOptions: options.providerOptions,
|
|
1875
1990
|
schema: codexCliProviderOptionsSchema
|
|
1876
1991
|
});
|
|
1877
|
-
|
|
1992
|
+
let effectiveSettings = this.mergeSettings(providerOptions);
|
|
1993
|
+
const topLevelReasoning = options.reasoning;
|
|
1994
|
+
if (topLevelReasoning !== void 0 && topLevelReasoning !== "provider-default" && providerOptions?.reasoningEffort === void 0) {
|
|
1995
|
+
if (Object.hasOwn(codexReasoningEfforts, topLevelReasoning)) {
|
|
1996
|
+
effectiveSettings = {
|
|
1997
|
+
...effectiveSettings,
|
|
1998
|
+
reasoningEffort: topLevelReasoning
|
|
1999
|
+
};
|
|
2000
|
+
} else {
|
|
2001
|
+
warnings.push({
|
|
2002
|
+
type: "unsupported",
|
|
2003
|
+
feature: "reasoning",
|
|
2004
|
+
details: `Codex CLI does not support reasoning effort '${topLevelReasoning}'; it will be ignored.`
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
1878
2008
|
const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
|
|
1879
2009
|
const { cmd, args, env, cwd, lastMessagePath, lastMessageIsTemp, schemaPath, tempImagePaths } = this.buildArgs(images, responseFormat, effectiveSettings);
|
|
1880
2010
|
this.logger.debug(
|
|
@@ -1889,6 +2019,7 @@ var ExecLanguageModel = class {
|
|
|
1889
2019
|
controller.enqueue({ type: "stream-start", warnings });
|
|
1890
2020
|
let stderr = "";
|
|
1891
2021
|
let accumulatedText = "";
|
|
2022
|
+
let stdoutBuffer = "";
|
|
1892
2023
|
const activeTools = /* @__PURE__ */ new Map();
|
|
1893
2024
|
let responseMetadataSent = false;
|
|
1894
2025
|
let lastUsage;
|
|
@@ -2046,57 +2177,62 @@ var ExecLanguageModel = class {
|
|
|
2046
2177
|
});
|
|
2047
2178
|
controller.close();
|
|
2048
2179
|
};
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
this.logger.debug(`[codex-cli] Stream session started: ${this.sessionId}`);
|
|
2060
|
-
if (!responseMetadataSent) {
|
|
2061
|
-
responseMetadataSent = true;
|
|
2062
|
-
sendMetadata();
|
|
2063
|
-
}
|
|
2064
|
-
continue;
|
|
2180
|
+
const processLine = (line) => {
|
|
2181
|
+
const event = this.parseExperimentalJsonEvent(line);
|
|
2182
|
+
if (!event) return;
|
|
2183
|
+
this.logger.debug(`[codex-cli] Stream event: ${event.type ?? "unknown"}`);
|
|
2184
|
+
if (event.type === "thread.started" && typeof event.thread_id === "string") {
|
|
2185
|
+
this.sessionId = event.thread_id;
|
|
2186
|
+
this.logger.debug(`[codex-cli] Stream session started: ${this.sessionId}`);
|
|
2187
|
+
if (!responseMetadataSent) {
|
|
2188
|
+
responseMetadataSent = true;
|
|
2189
|
+
sendMetadata();
|
|
2065
2190
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
}
|
|
2075
|
-
if (event.type === "turn.completed") {
|
|
2076
|
-
const usageEvent = this.extractUsage(event);
|
|
2077
|
-
if (usageEvent) {
|
|
2078
|
-
lastUsage = usageEvent;
|
|
2079
|
-
}
|
|
2080
|
-
continue;
|
|
2081
|
-
}
|
|
2082
|
-
if (event.type === "turn.failed") {
|
|
2083
|
-
const errorText = event.error && typeof event.error.message === "string" && event.error.message || (typeof event.message === "string" ? event.message : void 0);
|
|
2084
|
-
turnFailureMessage = errorText ?? turnFailureMessage ?? "Codex turn failed";
|
|
2085
|
-
this.logger.error(`[codex-cli] Stream turn failed: ${turnFailureMessage}`);
|
|
2086
|
-
sendMetadata({ error: turnFailureMessage });
|
|
2087
|
-
continue;
|
|
2088
|
-
}
|
|
2089
|
-
if (event.type === "error") {
|
|
2090
|
-
const errorText = typeof event.message === "string" ? event.message : void 0;
|
|
2091
|
-
const effective = errorText ?? "Codex error";
|
|
2092
|
-
turnFailureMessage = turnFailureMessage ?? effective;
|
|
2093
|
-
this.logger.error(`[codex-cli] Stream error event: ${effective}`);
|
|
2094
|
-
sendMetadata({ error: effective });
|
|
2095
|
-
continue;
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
if (event.type === "session.created" && typeof event.session_id === "string") {
|
|
2194
|
+
this.sessionId = event.session_id;
|
|
2195
|
+
this.logger.debug(`[codex-cli] Stream session created: ${this.sessionId}`);
|
|
2196
|
+
if (!responseMetadataSent) {
|
|
2197
|
+
responseMetadataSent = true;
|
|
2198
|
+
sendMetadata();
|
|
2096
2199
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2200
|
+
return;
|
|
2201
|
+
}
|
|
2202
|
+
if (event.type === "turn.completed") {
|
|
2203
|
+
const usageEvent = this.extractUsage(event);
|
|
2204
|
+
if (usageEvent) {
|
|
2205
|
+
lastUsage = usageEvent;
|
|
2099
2206
|
}
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
if (event.type === "turn.failed") {
|
|
2210
|
+
const errorText = event.error && typeof event.error.message === "string" && event.error.message || (typeof event.message === "string" ? event.message : void 0);
|
|
2211
|
+
turnFailureMessage = errorText ?? turnFailureMessage ?? "Codex turn failed";
|
|
2212
|
+
this.logger.error(`[codex-cli] Stream turn failed: ${turnFailureMessage}`);
|
|
2213
|
+
sendMetadata({ error: turnFailureMessage });
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
if (event.type === "error") {
|
|
2217
|
+
const errorText = typeof event.message === "string" ? event.message : void 0;
|
|
2218
|
+
const effective = errorText ?? "Codex error";
|
|
2219
|
+
turnFailureMessage = turnFailureMessage ?? effective;
|
|
2220
|
+
this.logger.error(`[codex-cli] Stream error event: ${effective}`);
|
|
2221
|
+
sendMetadata({ error: effective });
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
if (event.type && event.type.startsWith("item.")) {
|
|
2225
|
+
handleItemEvent(event);
|
|
2226
|
+
}
|
|
2227
|
+
};
|
|
2228
|
+
child.stderr.on("data", (d) => stderr += String(d));
|
|
2229
|
+
child.stdout.setEncoding("utf8");
|
|
2230
|
+
child.stdout.on("data", (chunk) => {
|
|
2231
|
+
const pieces = (stdoutBuffer + chunk).split(/\r?\n/);
|
|
2232
|
+
stdoutBuffer = pieces.pop() ?? "";
|
|
2233
|
+
for (const line of pieces) {
|
|
2234
|
+
if (!line) continue;
|
|
2235
|
+
processLine(line);
|
|
2100
2236
|
}
|
|
2101
2237
|
});
|
|
2102
2238
|
child.on("error", (e) => {
|
|
@@ -2108,7 +2244,13 @@ var ExecLanguageModel = class {
|
|
|
2108
2244
|
child.on("close", (code) => {
|
|
2109
2245
|
if (options.abortSignal) options.abortSignal.removeEventListener("abort", onAbort);
|
|
2110
2246
|
cleanupTempFiles();
|
|
2111
|
-
setImmediate(() =>
|
|
2247
|
+
setImmediate(() => {
|
|
2248
|
+
if (stdoutBuffer) {
|
|
2249
|
+
processLine(stdoutBuffer);
|
|
2250
|
+
stdoutBuffer = "";
|
|
2251
|
+
}
|
|
2252
|
+
finishStream(code);
|
|
2253
|
+
});
|
|
2112
2254
|
});
|
|
2113
2255
|
},
|
|
2114
2256
|
cancel: () => {
|
|
@@ -2140,7 +2282,7 @@ function createCodexExec(options = {}) {
|
|
|
2140
2282
|
if (new.target) throw new Error("The Codex CLI provider function cannot be called with new.");
|
|
2141
2283
|
return createModel(modelId, settings);
|
|
2142
2284
|
},
|
|
2143
|
-
{ specificationVersion: "
|
|
2285
|
+
{ specificationVersion: "v4" }
|
|
2144
2286
|
);
|
|
2145
2287
|
provider.languageModel = createModel;
|
|
2146
2288
|
provider.chat = createModel;
|
|
@@ -2335,6 +2477,14 @@ function mapTool(item) {
|
|
|
2335
2477
|
dynamic: true
|
|
2336
2478
|
};
|
|
2337
2479
|
}
|
|
2480
|
+
if (type === "dynamictoolcall") {
|
|
2481
|
+
const tool2 = "tool" in item && typeof item.tool === "string" && item.tool ? item.tool : "tool";
|
|
2482
|
+
const namespace = "namespace" in item && typeof item.namespace === "string" && item.namespace ? item.namespace : void 0;
|
|
2483
|
+
return {
|
|
2484
|
+
toolName: namespace ? `${namespace}__${tool2}` : tool2,
|
|
2485
|
+
dynamic: true
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2338
2488
|
if (type === "websearch") {
|
|
2339
2489
|
return { toolName: "web_search", dynamic: true };
|
|
2340
2490
|
}
|
|
@@ -3409,6 +3559,34 @@ function isSdkMcpServer(value) {
|
|
|
3409
3559
|
}
|
|
3410
3560
|
|
|
3411
3561
|
// src/app-server/language-model.ts
|
|
3562
|
+
var CODEX_REASONING_EFFORTS = {
|
|
3563
|
+
none: true,
|
|
3564
|
+
minimal: true,
|
|
3565
|
+
low: true,
|
|
3566
|
+
medium: true,
|
|
3567
|
+
high: true,
|
|
3568
|
+
xhigh: true
|
|
3569
|
+
};
|
|
3570
|
+
function resolveReasoningEffort(args) {
|
|
3571
|
+
if (args.providerEffort !== void 0) {
|
|
3572
|
+
return { effort: args.providerEffort };
|
|
3573
|
+
}
|
|
3574
|
+
const { reasoning } = args;
|
|
3575
|
+
if (reasoning === void 0 || reasoning === "provider-default") {
|
|
3576
|
+
return { effort: args.defaultEffort };
|
|
3577
|
+
}
|
|
3578
|
+
if (Object.hasOwn(CODEX_REASONING_EFFORTS, reasoning)) {
|
|
3579
|
+
return { effort: reasoning };
|
|
3580
|
+
}
|
|
3581
|
+
return {
|
|
3582
|
+
effort: args.defaultEffort,
|
|
3583
|
+
warning: {
|
|
3584
|
+
type: "unsupported",
|
|
3585
|
+
feature: "reasoning",
|
|
3586
|
+
details: `Codex app-server does not support reasoning effort '${reasoning}'; it will be ignored.`
|
|
3587
|
+
}
|
|
3588
|
+
};
|
|
3589
|
+
}
|
|
3412
3590
|
function isThreadNotFoundError2(error) {
|
|
3413
3591
|
const message = String(error?.message ?? error);
|
|
3414
3592
|
return /thread.*not found/i.test(message);
|
|
@@ -3470,12 +3648,9 @@ function mergeAppServerMcpServers(base, override) {
|
|
|
3470
3648
|
return merged;
|
|
3471
3649
|
}
|
|
3472
3650
|
var AppServerLanguageModel = class {
|
|
3473
|
-
specificationVersion = "
|
|
3651
|
+
specificationVersion = "v4";
|
|
3474
3652
|
provider = "codex-app-server";
|
|
3475
|
-
defaultObjectGenerationMode = "json";
|
|
3476
|
-
supportsImageUrls = true;
|
|
3477
3653
|
supportedUrls = {};
|
|
3478
|
-
supportsStructuredOutputs = true;
|
|
3479
3654
|
modelId;
|
|
3480
3655
|
settings;
|
|
3481
3656
|
client;
|
|
@@ -3484,6 +3659,7 @@ var AppServerLanguageModel = class {
|
|
|
3484
3659
|
onSdkMcpServerReleased;
|
|
3485
3660
|
persistentThreadId;
|
|
3486
3661
|
persistentThreadRawEventsEnabled;
|
|
3662
|
+
rawEventsByThreadId = /* @__PURE__ */ new Map();
|
|
3487
3663
|
persistentSession;
|
|
3488
3664
|
persistentBootstrapLock = Promise.resolve();
|
|
3489
3665
|
constructor(options) {
|
|
@@ -3617,7 +3793,14 @@ var AppServerLanguageModel = class {
|
|
|
3617
3793
|
return { input, tempImagePaths };
|
|
3618
3794
|
}
|
|
3619
3795
|
async startOrResumeThread(args) {
|
|
3620
|
-
const {
|
|
3796
|
+
const {
|
|
3797
|
+
settings,
|
|
3798
|
+
providerOptions,
|
|
3799
|
+
configOverrides,
|
|
3800
|
+
developerInstructionsOverride,
|
|
3801
|
+
systemInstruction,
|
|
3802
|
+
includeRawChunks
|
|
3803
|
+
} = args;
|
|
3621
3804
|
const threadState = this.resolveTargetThreadId(settings, providerOptions);
|
|
3622
3805
|
const startThread = async (ephemeral) => {
|
|
3623
3806
|
const thread = await this.client.threadStart({
|
|
@@ -3627,7 +3810,7 @@ var AppServerLanguageModel = class {
|
|
|
3627
3810
|
sandbox: mapSandboxToThreadSandboxMode(settings),
|
|
3628
3811
|
config: configOverrides,
|
|
3629
3812
|
baseInstructions: settings.baseInstructions,
|
|
3630
|
-
developerInstructions,
|
|
3813
|
+
developerInstructions: developerInstructionsOverride ?? systemInstruction,
|
|
3631
3814
|
personality: settings.personality,
|
|
3632
3815
|
ephemeral,
|
|
3633
3816
|
experimentalRawEvents: includeRawChunks,
|
|
@@ -3646,16 +3829,18 @@ var AppServerLanguageModel = class {
|
|
|
3646
3829
|
sandbox: mapSandboxToThreadSandboxMode(settings),
|
|
3647
3830
|
config: configOverrides,
|
|
3648
3831
|
baseInstructions: settings.baseInstructions,
|
|
3649
|
-
developerInstructions,
|
|
3832
|
+
developerInstructions: developerInstructionsOverride ?? systemInstruction,
|
|
3650
3833
|
personality: settings.personality,
|
|
3651
3834
|
persistExtendedHistory: settings.persistExtendedHistory ?? false
|
|
3652
3835
|
});
|
|
3653
|
-
const
|
|
3836
|
+
const cachedRawEvents = this.rawEventsByThreadId.get(target.threadId);
|
|
3837
|
+
const knownRawEvents = cachedRawEvents ?? (target.persistent && this.persistentThreadId === target.threadId ? this.persistentThreadRawEventsEnabled : void 0);
|
|
3838
|
+
if (cachedRawEvents !== void 0) {
|
|
3839
|
+
this.rememberThreadRawEvents(target.threadId, cachedRawEvents);
|
|
3840
|
+
}
|
|
3654
3841
|
if (target.persistent) {
|
|
3655
3842
|
this.persistentThreadId = target.threadId;
|
|
3656
|
-
|
|
3657
|
-
this.persistentThreadRawEventsEnabled = void 0;
|
|
3658
|
-
}
|
|
3843
|
+
this.persistentThreadRawEventsEnabled = knownRawEvents;
|
|
3659
3844
|
}
|
|
3660
3845
|
return {
|
|
3661
3846
|
threadId: target.threadId,
|
|
@@ -3683,6 +3868,7 @@ var AppServerLanguageModel = class {
|
|
|
3683
3868
|
});
|
|
3684
3869
|
}
|
|
3685
3870
|
const newThreadId = await startThread(false);
|
|
3871
|
+
this.rememberThreadRawEvents(newThreadId, includeRawChunks);
|
|
3686
3872
|
this.persistentThreadId = newThreadId;
|
|
3687
3873
|
this.persistentThreadRawEventsEnabled = includeRawChunks;
|
|
3688
3874
|
return {
|
|
@@ -3695,6 +3881,7 @@ var AppServerLanguageModel = class {
|
|
|
3695
3881
|
}
|
|
3696
3882
|
if (!threadState.threadId) {
|
|
3697
3883
|
const newThreadId = await startThread(!threadState.persistent);
|
|
3884
|
+
this.rememberThreadRawEvents(newThreadId, includeRawChunks);
|
|
3698
3885
|
if (threadState.persistent) {
|
|
3699
3886
|
this.persistentThreadId = newThreadId;
|
|
3700
3887
|
this.persistentThreadRawEventsEnabled = includeRawChunks;
|
|
@@ -3736,12 +3923,26 @@ var AppServerLanguageModel = class {
|
|
|
3736
3923
|
}
|
|
3737
3924
|
}
|
|
3738
3925
|
}
|
|
3926
|
+
rememberThreadRawEvents(threadId, enabled) {
|
|
3927
|
+
this.rawEventsByThreadId.delete(threadId);
|
|
3928
|
+
this.rawEventsByThreadId.set(threadId, enabled);
|
|
3929
|
+
if (this.rawEventsByThreadId.size <= 256) {
|
|
3930
|
+
return;
|
|
3931
|
+
}
|
|
3932
|
+
const oldestThreadId = this.rawEventsByThreadId.keys().next().value;
|
|
3933
|
+
if (typeof oldestThreadId === "string") {
|
|
3934
|
+
this.rawEventsByThreadId.delete(oldestThreadId);
|
|
3935
|
+
}
|
|
3936
|
+
}
|
|
3739
3937
|
clearPersistentThreadState(threadId) {
|
|
3740
3938
|
if (threadId && this.persistentThreadId && this.persistentThreadId !== threadId) {
|
|
3741
3939
|
return;
|
|
3742
3940
|
}
|
|
3743
3941
|
this.persistentThreadId = void 0;
|
|
3744
3942
|
this.persistentThreadRawEventsEnabled = void 0;
|
|
3943
|
+
if (threadId) {
|
|
3944
|
+
this.rawEventsByThreadId.delete(threadId);
|
|
3945
|
+
}
|
|
3745
3946
|
if (!threadId || this.persistentSession?.threadId === threadId) {
|
|
3746
3947
|
this.persistentSession = void 0;
|
|
3747
3948
|
}
|
|
@@ -3962,7 +4163,13 @@ var AppServerLanguageModel = class {
|
|
|
3962
4163
|
providerOptions: options.providerOptions,
|
|
3963
4164
|
schema: appServerProviderOptionsSchema
|
|
3964
4165
|
});
|
|
3965
|
-
const
|
|
4166
|
+
const mergedSettings = this.mergeSettings(providerOptions);
|
|
4167
|
+
const resolvedReasoning = resolveReasoningEffort({
|
|
4168
|
+
reasoning: options.reasoning,
|
|
4169
|
+
providerEffort: providerOptions?.effort,
|
|
4170
|
+
defaultEffort: mergedSettings.effort
|
|
4171
|
+
});
|
|
4172
|
+
const settings = resolvedReasoning.effort === mergedSettings.effort ? mergedSettings : { ...mergedSettings, effort: resolvedReasoning.effort };
|
|
3966
4173
|
const sdkServerLifecycle = this.resolveThreadMode(settings, providerOptions) === "persistent" ? "provider" : "request";
|
|
3967
4174
|
const includeRawChunks = this.resolveIncludeRawChunks(
|
|
3968
4175
|
options.includeRawChunks,
|
|
@@ -3983,11 +4190,11 @@ var AppServerLanguageModel = class {
|
|
|
3983
4190
|
toolChoice: options.toolChoice
|
|
3984
4191
|
})
|
|
3985
4192
|
];
|
|
4193
|
+
if (resolvedReasoning.warning) {
|
|
4194
|
+
warnings.push(resolvedReasoning.warning);
|
|
4195
|
+
}
|
|
3986
4196
|
const developerInstructionsOverride = providerOptions?.developerInstructions ?? settings.developerInstructions;
|
|
3987
|
-
const
|
|
3988
|
-
const prompt = this.preparePrompt(options.prompt, Boolean(threadState.threadId));
|
|
3989
|
-
warnings.push(...prompt.warnings);
|
|
3990
|
-
const effectiveDeveloperInstructions = developerInstructionsOverride ?? (!threadState.threadId ? prompt.systemInstruction : void 0);
|
|
4197
|
+
const systemInstruction = collectSystemInstruction(options.prompt);
|
|
3991
4198
|
const resolvedConfig = await this.resolveConfig(settings, sdkServerLifecycle);
|
|
3992
4199
|
let releasedSdkServers = false;
|
|
3993
4200
|
const releaseUsedSdkMcpServers = () => {
|
|
@@ -4005,7 +4212,8 @@ var AppServerLanguageModel = class {
|
|
|
4005
4212
|
settings,
|
|
4006
4213
|
providerOptions,
|
|
4007
4214
|
configOverrides: resolvedConfig.configOverrides,
|
|
4008
|
-
|
|
4215
|
+
developerInstructionsOverride,
|
|
4216
|
+
systemInstruction,
|
|
4009
4217
|
includeRawChunks
|
|
4010
4218
|
});
|
|
4011
4219
|
} catch (error) {
|
|
@@ -4019,6 +4227,8 @@ var AppServerLanguageModel = class {
|
|
|
4019
4227
|
message: "includeRawChunks was requested while resuming an existing thread that may not emit raw events. Start a new thread to guarantee raw chunk events."
|
|
4020
4228
|
});
|
|
4021
4229
|
}
|
|
4230
|
+
const prompt = this.preparePrompt(options.prompt, threadResolution.resumed);
|
|
4231
|
+
warnings.push(...prompt.warnings);
|
|
4022
4232
|
let input = [];
|
|
4023
4233
|
let tempImagePaths = [];
|
|
4024
4234
|
let session;
|
|
@@ -4059,7 +4269,7 @@ var AppServerLanguageModel = class {
|
|
|
4059
4269
|
session,
|
|
4060
4270
|
abortSignal: options.abortSignal,
|
|
4061
4271
|
shouldSerializeTurnStart: threadResolution.persistent || threadResolution.explicit,
|
|
4062
|
-
hadInitialThreadId:
|
|
4272
|
+
hadInitialThreadId: threadResolution.resumed,
|
|
4063
4273
|
threadResolution: {
|
|
4064
4274
|
persistent: threadResolution.persistent,
|
|
4065
4275
|
explicit: threadResolution.explicit
|
|
@@ -4229,7 +4439,46 @@ var contextCompactionItemSchema = z.object({
|
|
|
4229
4439
|
type: z.literal("contextCompaction"),
|
|
4230
4440
|
id: z.string()
|
|
4231
4441
|
}).passthrough();
|
|
4232
|
-
var
|
|
4442
|
+
var hookPromptItemSchema = z.object({
|
|
4443
|
+
type: z.literal("hookPrompt"),
|
|
4444
|
+
id: z.string(),
|
|
4445
|
+
fragments: z.array(z.unknown())
|
|
4446
|
+
}).passthrough();
|
|
4447
|
+
var dynamicToolCallItemSchema = z.object({
|
|
4448
|
+
type: z.literal("dynamicToolCall"),
|
|
4449
|
+
id: z.string(),
|
|
4450
|
+
namespace: z.string().nullable(),
|
|
4451
|
+
tool: z.string(),
|
|
4452
|
+
arguments: z.unknown(),
|
|
4453
|
+
status: z.string(),
|
|
4454
|
+
contentItems: z.array(z.unknown()).nullable(),
|
|
4455
|
+
success: z.boolean().nullable(),
|
|
4456
|
+
durationMs: z.number().nullable()
|
|
4457
|
+
}).passthrough();
|
|
4458
|
+
var subAgentActivityItemSchema = z.object({
|
|
4459
|
+
type: z.literal("subAgentActivity"),
|
|
4460
|
+
id: z.string(),
|
|
4461
|
+
kind: z.string(),
|
|
4462
|
+
agentThreadId: z.string(),
|
|
4463
|
+
agentPath: z.string()
|
|
4464
|
+
}).passthrough();
|
|
4465
|
+
var sleepItemSchema = z.object({
|
|
4466
|
+
type: z.literal("sleep"),
|
|
4467
|
+
id: z.string(),
|
|
4468
|
+
durationMs: z.number()
|
|
4469
|
+
}).passthrough();
|
|
4470
|
+
var imageGenerationItemSchema = z.object({
|
|
4471
|
+
type: z.literal("imageGeneration"),
|
|
4472
|
+
id: z.string(),
|
|
4473
|
+
status: z.string(),
|
|
4474
|
+
revisedPrompt: z.string().nullable(),
|
|
4475
|
+
result: z.string(),
|
|
4476
|
+
savedPath: z.string().optional()
|
|
4477
|
+
}).passthrough();
|
|
4478
|
+
var unknownThreadItemSchema = z.object({
|
|
4479
|
+
type: z.string()
|
|
4480
|
+
}).passthrough();
|
|
4481
|
+
var knownThreadItemSchema = z.discriminatedUnion("type", [
|
|
4233
4482
|
userMessageItemSchema,
|
|
4234
4483
|
agentMessageItemSchema,
|
|
4235
4484
|
planItemSchema,
|
|
@@ -4237,13 +4486,19 @@ var threadItemSchema = z.discriminatedUnion("type", [
|
|
|
4237
4486
|
commandExecutionItemSchema,
|
|
4238
4487
|
fileChangeItemSchema,
|
|
4239
4488
|
mcpToolCallItemSchema,
|
|
4489
|
+
dynamicToolCallItemSchema,
|
|
4240
4490
|
collabAgentToolCallItemSchema,
|
|
4491
|
+
hookPromptItemSchema,
|
|
4492
|
+
subAgentActivityItemSchema,
|
|
4493
|
+
sleepItemSchema,
|
|
4494
|
+
imageGenerationItemSchema,
|
|
4241
4495
|
webSearchItemSchema,
|
|
4242
4496
|
imageViewItemSchema,
|
|
4243
4497
|
enteredReviewModeItemSchema,
|
|
4244
4498
|
exitedReviewModeItemSchema,
|
|
4245
4499
|
contextCompactionItemSchema
|
|
4246
4500
|
]);
|
|
4501
|
+
var threadItemSchema = knownThreadItemSchema.or(unknownThreadItemSchema);
|
|
4247
4502
|
var codexHttpStatusCodeSchema = z.object({
|
|
4248
4503
|
httpStatusCode: z.number().nullable()
|
|
4249
4504
|
}).passthrough();
|
|
@@ -4252,6 +4507,7 @@ var codexErrorInfoSchema = z.union([
|
|
|
4252
4507
|
"contextWindowExceeded",
|
|
4253
4508
|
"usageLimitExceeded",
|
|
4254
4509
|
"serverOverloaded",
|
|
4510
|
+
"cyberPolicy",
|
|
4255
4511
|
"internalServerError",
|
|
4256
4512
|
"unauthorized",
|
|
4257
4513
|
"badRequest",
|
|
@@ -4262,17 +4518,23 @@ var codexErrorInfoSchema = z.union([
|
|
|
4262
4518
|
z.object({ httpConnectionFailed: codexHttpStatusCodeSchema }).passthrough(),
|
|
4263
4519
|
z.object({ responseStreamConnectionFailed: codexHttpStatusCodeSchema }).passthrough(),
|
|
4264
4520
|
z.object({ responseStreamDisconnected: codexHttpStatusCodeSchema }).passthrough(),
|
|
4265
|
-
z.object({ responseTooManyFailedAttempts: codexHttpStatusCodeSchema }).passthrough()
|
|
4521
|
+
z.object({ responseTooManyFailedAttempts: codexHttpStatusCodeSchema }).passthrough(),
|
|
4522
|
+
z.object({ activeTurnNotSteerable: z.object({ turnKind: z.string() }).passthrough() }).passthrough(),
|
|
4523
|
+
// Forward-compat catch-alls: consumers only compare against the known string
|
|
4524
|
+
// codes above (unknown codes fall back to the generic error path), so a new
|
|
4525
|
+
// errorInfo variant must never fail validation and drop the notification.
|
|
4526
|
+
z.string(),
|
|
4527
|
+
z.record(z.string(), z.unknown())
|
|
4266
4528
|
]);
|
|
4267
4529
|
var turnSchema = z.object({
|
|
4268
4530
|
id: z.string(),
|
|
4269
4531
|
items: z.array(threadItemSchema),
|
|
4270
|
-
status: z.
|
|
4532
|
+
status: z.string(),
|
|
4271
4533
|
error: z.object({
|
|
4272
4534
|
message: z.string(),
|
|
4273
|
-
codexErrorInfo: codexErrorInfoSchema.
|
|
4274
|
-
additionalDetails: z.string().
|
|
4275
|
-
}).
|
|
4535
|
+
codexErrorInfo: codexErrorInfoSchema.nullish(),
|
|
4536
|
+
additionalDetails: z.string().nullish()
|
|
4537
|
+
}).nullish()
|
|
4276
4538
|
}).passthrough();
|
|
4277
4539
|
var threadStartedNotificationSchema = z.object({
|
|
4278
4540
|
thread: z.object({ id: z.string() }).passthrough()
|
|
@@ -4565,7 +4827,6 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4565
4827
|
activeRequestContextsByTurn = /* @__PURE__ */ new Map();
|
|
4566
4828
|
completedTurnIds = /* @__PURE__ */ new Set();
|
|
4567
4829
|
lastStderr = "";
|
|
4568
|
-
lastCrashHadStderr = false;
|
|
4569
4830
|
idleTimer;
|
|
4570
4831
|
serverCapabilities;
|
|
4571
4832
|
expectedExitSignal;
|
|
@@ -4772,7 +5033,6 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4772
5033
|
const base = resolveCodexPath2(this.settings.codexPath);
|
|
4773
5034
|
const args = [...base.args, "app-server", "--listen", "stdio://"];
|
|
4774
5035
|
this.lastStderr = "";
|
|
4775
|
-
this.lastCrashHadStderr = false;
|
|
4776
5036
|
this.expectedExitSignal = void 0;
|
|
4777
5037
|
this.child = spawn(base.cmd, args, {
|
|
4778
5038
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -4783,23 +5043,18 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4783
5043
|
},
|
|
4784
5044
|
cwd: this.settings.cwd
|
|
4785
5045
|
});
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
if (this.child === child) {
|
|
4792
|
-
this.lastStderr = stderrBuf;
|
|
5046
|
+
this.child.stderr.setEncoding("utf8");
|
|
5047
|
+
this.child.stderr.on("data", (chunk) => {
|
|
5048
|
+
this.lastStderr += String(chunk);
|
|
5049
|
+
if (this.lastStderr.length > 4e3) {
|
|
5050
|
+
this.lastStderr = this.lastStderr.slice(-4e3);
|
|
4793
5051
|
}
|
|
4794
5052
|
});
|
|
4795
|
-
child.on("error", (error) => {
|
|
5053
|
+
this.child.on("error", (error) => {
|
|
4796
5054
|
this.logger.error(`[codex-app-server] process error: ${String(error)}`);
|
|
4797
|
-
|
|
4798
|
-
const message = this.withStderrTail(base2, stderrBuf);
|
|
4799
|
-
this.lastCrashHadStderr = message !== base2;
|
|
4800
|
-
this.handleCrash(new Error(message));
|
|
5055
|
+
this.handleCrash(error);
|
|
4801
5056
|
});
|
|
4802
|
-
child.on("exit", (code, signal) => {
|
|
5057
|
+
this.child.on("exit", (code, signal) => {
|
|
4803
5058
|
const message = `codex app-server exited (code=${String(code)}, signal=${String(signal)})`;
|
|
4804
5059
|
const expected = this.state === "closed" || signal !== null && signal === this.expectedExitSignal;
|
|
4805
5060
|
this.expectedExitSignal = void 0;
|
|
@@ -4807,29 +5062,11 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4807
5062
|
this.logger.info(`[codex-app-server] ${message}`);
|
|
4808
5063
|
return;
|
|
4809
5064
|
}
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
let settled = false;
|
|
4813
|
-
const finish = () => {
|
|
4814
|
-
if (settled) return;
|
|
4815
|
-
settled = true;
|
|
4816
|
-
child.off("close", finish);
|
|
4817
|
-
clearTimeout(timer);
|
|
4818
|
-
const base2 = `codex app-server exited (code=${String(code)}, signal=${String(signal)})`;
|
|
4819
|
-
const crashMessage = this.withStderrTail(base2, stderrBuf);
|
|
4820
|
-
if (this.child === void 0) {
|
|
4821
|
-
this.lastStderr = stderrBuf;
|
|
4822
|
-
this.lastCrashHadStderr = crashMessage !== base2;
|
|
4823
|
-
}
|
|
4824
|
-
this.logger.warn(`[codex-app-server] ${crashMessage}`);
|
|
4825
|
-
this.rejectCrashedPending(crashedPending, new Error(crashMessage));
|
|
4826
|
-
};
|
|
4827
|
-
child.once("close", finish);
|
|
4828
|
-
const timer = setTimeout(finish, 120);
|
|
4829
|
-
timer.unref?.();
|
|
5065
|
+
this.logger.warn(`[codex-app-server] ${message}`);
|
|
5066
|
+
this.handleCrash(new Error(message));
|
|
4830
5067
|
});
|
|
4831
5068
|
this.stdoutReader = readline.createInterface({
|
|
4832
|
-
input: child.stdout,
|
|
5069
|
+
input: this.child.stdout,
|
|
4833
5070
|
crlfDelay: Infinity
|
|
4834
5071
|
});
|
|
4835
5072
|
this.stdoutReader.on("line", (line) => this.handleLine(line));
|
|
@@ -4851,22 +5088,12 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4851
5088
|
this.settings.connectionTimeoutMs ?? this.requestTimeoutMs
|
|
4852
5089
|
);
|
|
4853
5090
|
} catch (error) {
|
|
4854
|
-
const
|
|
4855
|
-
if (
|
|
5091
|
+
const message = String(error?.message ?? error);
|
|
5092
|
+
if (message.includes("ENOENT") || message.includes("unknown subcommand")) {
|
|
4856
5093
|
throw new Error(
|
|
4857
|
-
|
|
4858
|
-
"codex app-server requires codex CLI >= 0.144.0. Run 'codex --version' to check."
|
|
4859
|
-
)
|
|
5094
|
+
"codex app-server requires codex CLI >= 0.144.0. Run 'codex --version' to check."
|
|
4860
5095
|
);
|
|
4861
5096
|
}
|
|
4862
|
-
if (raw.includes("ENOENT") || this.lastStderr.includes("ENOENT")) {
|
|
4863
|
-
throw new Error(
|
|
4864
|
-
this.withStderrTail(
|
|
4865
|
-
"codex app-server failed to start: codex executable not found (ENOENT). Check that the codex CLI is installed and its native binary is intact \u2014 a corrupted @openai/codex npm install can cause this. Run 'codex --version' to verify."
|
|
4866
|
-
)
|
|
4867
|
-
);
|
|
4868
|
-
}
|
|
4869
|
-
const message = this.lastCrashHadStderr ? raw : this.withStderrTail(raw);
|
|
4870
5097
|
throw createAPICallError({
|
|
4871
5098
|
message: `Failed to initialize codex app-server: ${message}`,
|
|
4872
5099
|
stderr: this.lastStderr,
|
|
@@ -4928,8 +5155,8 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4928
5155
|
}
|
|
4929
5156
|
this.writeQueue = Promise.resolve();
|
|
4930
5157
|
}
|
|
4931
|
-
|
|
4932
|
-
if (this.state === "closed"
|
|
5158
|
+
handleCrash(error) {
|
|
5159
|
+
if (this.state === "closed") return;
|
|
4933
5160
|
this.state = "error";
|
|
4934
5161
|
this.clearIdleTimer();
|
|
4935
5162
|
this.stdoutReader?.close();
|
|
@@ -4939,9 +5166,11 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4939
5166
|
this.child.kill("SIGTERM");
|
|
4940
5167
|
this.child = void 0;
|
|
4941
5168
|
}
|
|
4942
|
-
const pending
|
|
4943
|
-
|
|
4944
|
-
|
|
5169
|
+
for (const [id, pending] of this.pending.entries()) {
|
|
5170
|
+
clearTimeout(pending.timer);
|
|
5171
|
+
pending.reject(
|
|
5172
|
+
new Error(`Request ${String(id)} failed after app-server crash: ${String(error)}`)
|
|
5173
|
+
);
|
|
4945
5174
|
}
|
|
4946
5175
|
this.pending.clear();
|
|
4947
5176
|
this.threadLocks.clear();
|
|
@@ -4951,41 +5180,6 @@ var AppServerRpcClient = class extends EventEmitter {
|
|
|
4951
5180
|
this.completedTurnIds.clear();
|
|
4952
5181
|
this.serverCapabilities = void 0;
|
|
4953
5182
|
this.writeQueue = Promise.resolve();
|
|
4954
|
-
return pending;
|
|
4955
|
-
}
|
|
4956
|
-
rejectCrashedPending(pending, error) {
|
|
4957
|
-
for (const [id, entry] of pending) {
|
|
4958
|
-
entry.reject(
|
|
4959
|
-
new Error(`Request ${String(id)} failed after app-server crash: ${String(error)}`)
|
|
4960
|
-
);
|
|
4961
|
-
}
|
|
4962
|
-
}
|
|
4963
|
-
handleCrash(error) {
|
|
4964
|
-
const pending = this.markCrashed();
|
|
4965
|
-
if (!pending) return;
|
|
4966
|
-
this.rejectCrashedPending(pending, error);
|
|
4967
|
-
}
|
|
4968
|
-
stderrExcerpt(raw) {
|
|
4969
|
-
if (!raw) return "";
|
|
4970
|
-
const escape = String.fromCharCode(27);
|
|
4971
|
-
const ansiEscapeSequence = new RegExp(
|
|
4972
|
-
`${escape}(?:\\[[0-?]*[ -/]*[@-~]|\\][^\\u0007]*(?:\\u0007|${escape}\\\\))`,
|
|
4973
|
-
"g"
|
|
4974
|
-
);
|
|
4975
|
-
const withoutAnsi = raw.replace(ansiEscapeSequence, "");
|
|
4976
|
-
const withoutControls = Array.from(withoutAnsi).filter((character) => {
|
|
4977
|
-
const code = character.charCodeAt(0);
|
|
4978
|
-
return character === "\n" || code >= 32 && (code < 127 || code > 159);
|
|
4979
|
-
}).join("");
|
|
4980
|
-
const excerpt = withoutControls.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).slice(-5).join("; ");
|
|
4981
|
-
if (excerpt.length > 600) {
|
|
4982
|
-
return `\u2026${excerpt.slice(-600)}`;
|
|
4983
|
-
}
|
|
4984
|
-
return excerpt;
|
|
4985
|
-
}
|
|
4986
|
-
withStderrTail(message, raw = this.lastStderr) {
|
|
4987
|
-
const excerpt = this.stderrExcerpt(raw);
|
|
4988
|
-
return excerpt ? `${message} | stderr (tail): ${excerpt}` : message;
|
|
4989
5183
|
}
|
|
4990
5184
|
handleLine(line) {
|
|
4991
5185
|
const trimmed = line.trim();
|
|
@@ -5655,7 +5849,7 @@ function createCodexAppServer(options = {}) {
|
|
|
5655
5849
|
}
|
|
5656
5850
|
return createModel(modelId, settings);
|
|
5657
5851
|
},
|
|
5658
|
-
{ specificationVersion: "
|
|
5852
|
+
{ specificationVersion: "v4" }
|
|
5659
5853
|
);
|
|
5660
5854
|
provider.languageModel = createModel;
|
|
5661
5855
|
provider.chat = createModel;
|