@ai-sdk/harness-codex 1.0.126 → 1.0.129
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/CHANGELOG.md +26 -0
- package/README.md +12 -13
- package/dist/bridge/index.mjs +1248 -484
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/bridge/package.json +1 -1
- package/dist/bridge/pnpm-lock.yaml +1 -9
- package/dist/index.d.ts +1399 -0
- package/dist/index.js +46 -73
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/bridge/codex-app-server-client.ts +320 -0
- package/src/bridge/codex-app-server-driver.ts +617 -0
- package/src/bridge/codex-step-tracker.ts +2 -0
- package/src/bridge/codex-tool-filtering-hook.ts +148 -0
- package/src/bridge/codex-tool-filtering.ts +42 -0
- package/src/bridge/create-app-server-event-handler.ts +531 -0
- package/src/bridge/create-emit-stream-event.ts +27 -2
- package/src/bridge/index.ts +64 -193
- package/src/bridge/package.json +1 -1
- package/src/bridge/pnpm-lock.yaml +1 -9
- package/src/codex-bridge-protocol.ts +4 -4
- package/src/codex-harness.ts +56 -117
- package/src/bridge/cli-relay.ts +0 -268
- package/src/bridge/tool-relay-auth.ts +0 -156
- package/src/bridge/tool-relay.ts +0 -119
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
createSandboxCredentialEnvironment,
|
|
16
16
|
createBridgeErrorHandler,
|
|
17
17
|
createBridgeStartupError,
|
|
18
|
+
experimental_createBridgeUserMessageSubmitter,
|
|
18
19
|
drainBridgeProcessStream,
|
|
19
20
|
forwardBridgeProcessStream,
|
|
20
21
|
getRestrictedSandboxSession,
|
|
@@ -27,6 +28,9 @@ import {
|
|
|
27
28
|
withBridgeToken,
|
|
28
29
|
writeSkills
|
|
29
30
|
} from "@ai-sdk/harness/utils";
|
|
31
|
+
import {
|
|
32
|
+
tool
|
|
33
|
+
} from "@ai-sdk/provider-utils";
|
|
30
34
|
import { WebSocket } from "ws";
|
|
31
35
|
import { z as z2 } from "zod/v4";
|
|
32
36
|
|
|
@@ -516,10 +520,10 @@ var startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
|
516
520
|
codexConfig: z.record(z.string(), z.unknown()).optional(),
|
|
517
521
|
mcpServers: z.record(z.string(), z.unknown()).optional(),
|
|
518
522
|
headers: z.record(z.string(), z.string()).optional(),
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
+
/*
|
|
524
|
+
* The host carries this app-server thread ID in lifecycle state. Supplying it
|
|
525
|
+
* makes the bridge call `thread/resume` instead of starting a fresh thread.
|
|
526
|
+
*/
|
|
523
527
|
resumeThreadId: z.string().optional(),
|
|
524
528
|
restartThread: z.boolean().optional()
|
|
525
529
|
});
|
|
@@ -528,11 +532,8 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
528
532
|
...harnessV1BridgeInboundCommandSchemas
|
|
529
533
|
]);
|
|
530
534
|
|
|
531
|
-
// src/bridge/cli-relay.ts
|
|
532
|
-
var CLI_SHIM_FILENAME = "harness-tool.mjs";
|
|
533
|
-
|
|
534
535
|
// src/version.ts
|
|
535
|
-
var VERSION = true ? "1.0.
|
|
536
|
+
var VERSION = true ? "1.0.129" : "0.0.0-test";
|
|
536
537
|
|
|
537
538
|
// src/codex-harness.ts
|
|
538
539
|
var DEFAULT_CODEX_MODEL = "gpt-5.5";
|
|
@@ -549,7 +550,25 @@ var CODEX_BUILTIN_TOOLS = {
|
|
|
549
550
|
toolUseKind: "readonly",
|
|
550
551
|
description: "Search the web",
|
|
551
552
|
inputSchema: z2.object({ query: z2.string() })
|
|
552
|
-
})
|
|
553
|
+
}),
|
|
554
|
+
apply_patch: {
|
|
555
|
+
...tool({
|
|
556
|
+
description: "Apply a patch to files",
|
|
557
|
+
inputSchema: z2.string()
|
|
558
|
+
}),
|
|
559
|
+
toolUseKind: "edit"
|
|
560
|
+
},
|
|
561
|
+
view_image: {
|
|
562
|
+
...tool({
|
|
563
|
+
description: "View a local image file",
|
|
564
|
+
inputSchema: z2.object({
|
|
565
|
+
path: z2.string(),
|
|
566
|
+
detail: z2.enum(["high", "original"]).optional(),
|
|
567
|
+
environment_id: z2.string().optional()
|
|
568
|
+
})
|
|
569
|
+
}),
|
|
570
|
+
toolUseKind: "readonly"
|
|
571
|
+
}
|
|
553
572
|
};
|
|
554
573
|
var codexBridgeCoordsSchema = z2.object({
|
|
555
574
|
port: z2.number(),
|
|
@@ -568,17 +587,12 @@ function createCodex(settings = {}) {
|
|
|
568
587
|
specificationVersion: "harness-v1",
|
|
569
588
|
harnessId: "codex",
|
|
570
589
|
builtinTools: CODEX_BUILTIN_TOOLS,
|
|
590
|
+
supportsBuiltinToolFiltering: true,
|
|
571
591
|
supportsBuiltinToolApprovals: false,
|
|
572
592
|
lifecycleStateSchema: codexResumeStateSchema,
|
|
573
593
|
getBootstrap: getCodexBootstrap,
|
|
574
594
|
doStart: async (startOpts) => {
|
|
575
595
|
const model = DEFAULT_CODEX_MODEL;
|
|
576
|
-
if (startOpts.builtinToolFiltering != null) {
|
|
577
|
-
throw new HarnessCapabilityUnsupportedError({
|
|
578
|
-
message: "Harness 'codex' does not support built-in tool filtering controls.",
|
|
579
|
-
harnessId: "codex"
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
596
|
if (startOpts.permissionMode != null && startOpts.permissionMode !== "allow-all") {
|
|
583
597
|
throw new HarnessCapabilityUnsupportedError({
|
|
584
598
|
message: "Harness 'codex' does not support built-in tool approval requests; use permissionMode: 'allow-all'.",
|
|
@@ -654,8 +668,6 @@ function createCodex(settings = {}) {
|
|
|
654
668
|
sessionId: startOpts.sessionId
|
|
655
669
|
});
|
|
656
670
|
const bridgeStateDir = `${sessionDataDir}/bridge`;
|
|
657
|
-
const cliShimDir = `${sessionDataDir}/codex`;
|
|
658
|
-
const cliShimPath = `${cliShimDir}/${CLI_SHIM_FILENAME}`;
|
|
659
671
|
const timeoutMs = settings.startupTimeoutMs ?? 12e4;
|
|
660
672
|
const report = startOpts.observability?.report;
|
|
661
673
|
const onDiagnostic = report ? (frame) => report(
|
|
@@ -691,12 +703,12 @@ function createCodex(settings = {}) {
|
|
|
691
703
|
return createSession({
|
|
692
704
|
sessionId: startOpts.sessionId,
|
|
693
705
|
channel: attachChannel,
|
|
694
|
-
cliShimPath,
|
|
695
706
|
// The live bridge was spawned by another process; no process handle.
|
|
696
707
|
proc: void 0,
|
|
697
708
|
model,
|
|
698
709
|
reasoningEffort: settings.reasoningEffort,
|
|
699
710
|
webSearch: settings.webSearch,
|
|
711
|
+
builtinToolFiltering: startOpts.builtinToolFiltering,
|
|
700
712
|
codexConfig: settings.codexConfig,
|
|
701
713
|
mcpServers: settings.mcpServers,
|
|
702
714
|
headers: startOpts.headers,
|
|
@@ -766,7 +778,7 @@ function createCodex(settings = {}) {
|
|
|
766
778
|
abortSignal: startOpts.abortSignal
|
|
767
779
|
});
|
|
768
780
|
const proc = await toolSafeSandboxSession.spawn({
|
|
769
|
-
command: `node ${shellQuote(`${bootstrapDir}/bridge.mjs`)} --workdir ${shellQuote(workDir)} --bridge-state-dir ${shellQuote(bridgeStateDir)}
|
|
781
|
+
command: `node ${shellQuote(`${bootstrapDir}/bridge.mjs`)} --workdir ${shellQuote(workDir)} --bridge-state-dir ${shellQuote(bridgeStateDir)}`,
|
|
770
782
|
env,
|
|
771
783
|
abortSignal: startOpts.abortSignal
|
|
772
784
|
});
|
|
@@ -823,11 +835,11 @@ function createCodex(settings = {}) {
|
|
|
823
835
|
return createSession({
|
|
824
836
|
sessionId: startOpts.sessionId,
|
|
825
837
|
channel,
|
|
826
|
-
cliShimPath,
|
|
827
838
|
proc,
|
|
828
839
|
model,
|
|
829
840
|
reasoningEffort: settings.reasoningEffort,
|
|
830
841
|
webSearch: settings.webSearch,
|
|
842
|
+
builtinToolFiltering: startOpts.builtinToolFiltering,
|
|
831
843
|
codexConfig: settings.codexConfig,
|
|
832
844
|
mcpServers: settings.mcpServers,
|
|
833
845
|
headers: startOpts.headers,
|
|
@@ -949,11 +961,11 @@ function openWebSocket({
|
|
|
949
961
|
function createSession({
|
|
950
962
|
sessionId,
|
|
951
963
|
channel,
|
|
952
|
-
cliShimPath,
|
|
953
964
|
proc,
|
|
954
965
|
model,
|
|
955
966
|
reasoningEffort,
|
|
956
967
|
webSearch,
|
|
968
|
+
builtinToolFiltering,
|
|
957
969
|
codexConfig,
|
|
958
970
|
mcpServers,
|
|
959
971
|
headers,
|
|
@@ -974,7 +986,6 @@ function createSession({
|
|
|
974
986
|
let stopped = false;
|
|
975
987
|
let stopPromise;
|
|
976
988
|
let pendingResumeThreadId = seedResumeThreadOnFirstPrompt ? resumeThreadId : void 0;
|
|
977
|
-
let initialPromptGuidanceApplied = isResume;
|
|
978
989
|
let latestThreadId = resumeThreadId;
|
|
979
990
|
let latestTurnConfigurationFingerprint = turnConfigurationFingerprint;
|
|
980
991
|
channel.on("bridge-thread", (msg) => {
|
|
@@ -1002,7 +1013,6 @@ function createSession({
|
|
|
1002
1013
|
const restartThread = latestThreadId != null && (skillsResult.changed || latestTurnConfigurationFingerprint != null && latestTurnConfigurationFingerprint !== nextFingerprint);
|
|
1003
1014
|
latestTurnConfigurationFingerprint = nextFingerprint;
|
|
1004
1015
|
if (restartThread) {
|
|
1005
|
-
initialPromptGuidanceApplied = false;
|
|
1006
1016
|
pendingResumeThreadId = void 0;
|
|
1007
1017
|
}
|
|
1008
1018
|
return { restartThread };
|
|
@@ -1014,6 +1024,11 @@ function createSession({
|
|
|
1014
1024
|
pendingResolve = resolve2;
|
|
1015
1025
|
pendingReject = reject;
|
|
1016
1026
|
});
|
|
1027
|
+
const userMessageSubmitter = experimental_createBridgeUserMessageSubmitter({
|
|
1028
|
+
send: (message) => channel.send(message),
|
|
1029
|
+
onResponse: (listener) => channel.on("user-message-response", listener),
|
|
1030
|
+
onReconnect: (listener) => channel.onReconnect(listener)
|
|
1031
|
+
});
|
|
1017
1032
|
const unsubs = [];
|
|
1018
1033
|
const forward = (event) => {
|
|
1019
1034
|
try {
|
|
@@ -1040,12 +1055,14 @@ function createSession({
|
|
|
1040
1055
|
const settleSuccess = () => {
|
|
1041
1056
|
if (isSettled) return;
|
|
1042
1057
|
isSettled = true;
|
|
1058
|
+
userMessageSubmitter.close();
|
|
1043
1059
|
for (const u of unsubs) u();
|
|
1044
1060
|
pendingResolve();
|
|
1045
1061
|
};
|
|
1046
1062
|
const settleError = (err) => {
|
|
1047
1063
|
if (isSettled) return;
|
|
1048
1064
|
isSettled = true;
|
|
1065
|
+
userMessageSubmitter.close(err);
|
|
1049
1066
|
for (const u of unsubs) u();
|
|
1050
1067
|
pendingReject(err);
|
|
1051
1068
|
};
|
|
@@ -1113,6 +1130,9 @@ function createSession({
|
|
|
1113
1130
|
reason: input.reason
|
|
1114
1131
|
});
|
|
1115
1132
|
},
|
|
1133
|
+
submitUserMessage: async (text) => {
|
|
1134
|
+
await userMessageSubmitter.submit(text);
|
|
1135
|
+
},
|
|
1116
1136
|
done
|
|
1117
1137
|
};
|
|
1118
1138
|
return {
|
|
@@ -1155,26 +1175,16 @@ function createSession({
|
|
|
1155
1175
|
emit: promptOpts.emit,
|
|
1156
1176
|
abortSignal: promptOpts.abortSignal
|
|
1157
1177
|
});
|
|
1158
|
-
let promptText = extractUserText(promptOpts.prompt);
|
|
1159
|
-
if (!initialPromptGuidanceApplied) {
|
|
1160
|
-
promptText = frameInitialPromptGuidance({
|
|
1161
|
-
toolUsageBlock: tools.length > 0 ? composeToolUsageInstructions({
|
|
1162
|
-
tools,
|
|
1163
|
-
cliShimPath
|
|
1164
|
-
}) : void 0,
|
|
1165
|
-
userText: promptText
|
|
1166
|
-
});
|
|
1167
|
-
}
|
|
1168
|
-
initialPromptGuidanceApplied = true;
|
|
1169
1178
|
const startMessage = {
|
|
1170
1179
|
type: "start",
|
|
1171
|
-
prompt:
|
|
1180
|
+
prompt: extractUserText(promptOpts.prompt),
|
|
1172
1181
|
tools,
|
|
1173
1182
|
...promptOpts.responseFormat == null ? {} : { responseFormat: promptOpts.responseFormat },
|
|
1174
1183
|
...promptOpts.instructions ? { instructions: promptOpts.instructions } : {},
|
|
1175
1184
|
model: promptOpts.model ?? model,
|
|
1176
1185
|
reasoningEffort,
|
|
1177
1186
|
webSearch,
|
|
1187
|
+
...builtinToolFiltering == null ? {} : { builtinToolFiltering },
|
|
1178
1188
|
...codexConfig == null ? {} : { codexConfig },
|
|
1179
1189
|
...mcpServers == null ? {} : { mcpServers },
|
|
1180
1190
|
...headers == null ? {} : { headers },
|
|
@@ -1229,6 +1239,7 @@ function createSession({
|
|
|
1229
1239
|
model: continueOpts.model ?? model,
|
|
1230
1240
|
reasoningEffort,
|
|
1231
1241
|
webSearch,
|
|
1242
|
+
...builtinToolFiltering == null ? {} : { builtinToolFiltering },
|
|
1232
1243
|
...codexConfig == null ? {} : { codexConfig },
|
|
1233
1244
|
...mcpServers == null ? {} : { mcpServers },
|
|
1234
1245
|
...headers == null ? {} : { headers },
|
|
@@ -1409,44 +1420,6 @@ function fingerprintCodexTurnConfiguration({
|
|
|
1409
1420
|
}) {
|
|
1410
1421
|
return createHash2("sha256").update(JSON.stringify({ instructions: instructions ?? null, tools })).digest("hex");
|
|
1411
1422
|
}
|
|
1412
|
-
function frameInitialPromptGuidance({
|
|
1413
|
-
toolUsageBlock,
|
|
1414
|
-
userText
|
|
1415
|
-
}) {
|
|
1416
|
-
const blocks = [];
|
|
1417
|
-
if (toolUsageBlock) blocks.push(toolUsageBlock);
|
|
1418
|
-
if (blocks.length === 0) return userText;
|
|
1419
|
-
return `${blocks.join("\n\n")}
|
|
1420
|
-
|
|
1421
|
-
<user-message>
|
|
1422
|
-
${userText}
|
|
1423
|
-
</user-message>`;
|
|
1424
|
-
}
|
|
1425
|
-
function composeToolUsageInstructions({
|
|
1426
|
-
tools,
|
|
1427
|
-
cliShimPath
|
|
1428
|
-
}) {
|
|
1429
|
-
const lines = [
|
|
1430
|
-
"<host-tool-instructions>",
|
|
1431
|
-
"You have access to the following host-provided tools. To use one, run the following command via your built-in `bash` tool:",
|
|
1432
|
-
"",
|
|
1433
|
-
` node ${cliShimPath} <toolName> '<jsonInput>'`,
|
|
1434
|
-
"",
|
|
1435
|
-
"The script prints the JSON result to stdout. Do not invent another way to call these tools \u2014 only this CLI invocation will work. Pass the JSON input as a single-quoted argument.",
|
|
1436
|
-
"For every user request that depends on a host-provided tool, run a separate CLI invocation for each needed tool call in the current turn before answering. Do not reuse previous tool results, and do not say you used a host tool unless the command has completed in the current turn.",
|
|
1437
|
-
""
|
|
1438
|
-
];
|
|
1439
|
-
for (const toolSpec of tools) {
|
|
1440
|
-
lines.push(
|
|
1441
|
-
`- **${toolSpec.name}**${toolSpec.description ? ": " + toolSpec.description : ""}`
|
|
1442
|
-
);
|
|
1443
|
-
lines.push(
|
|
1444
|
-
` - Input schema: \`${JSON.stringify(toolSpec.inputSchema ?? {})}\``
|
|
1445
|
-
);
|
|
1446
|
-
}
|
|
1447
|
-
lines.push("</host-tool-instructions>");
|
|
1448
|
-
return lines.join("\n");
|
|
1449
|
-
}
|
|
1450
1423
|
function extractUserText(prompt) {
|
|
1451
1424
|
if (typeof prompt === "string") return prompt;
|
|
1452
1425
|
const { content } = prompt;
|