@ai-sdk/harness-codex 1.0.66 → 1.0.68
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 +19 -0
- package/dist/bridge/index.mjs +11 -2
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +14 -17
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bridge/create-emit-stream-event.ts +2 -0
- package/src/bridge/index.ts +9 -0
- package/src/codex-bridge-protocol.ts +2 -0
- package/src/codex-harness.ts +35 -24
package/src/codex-harness.ts
CHANGED
|
@@ -75,6 +75,11 @@ const CODEX_CLIENT_APP = `ai-sdk/harness-codex/${VERSION}`;
|
|
|
75
75
|
|
|
76
76
|
export type CodexHarnessSettings = {
|
|
77
77
|
readonly auth?: CodexAuthOptions;
|
|
78
|
+
/**
|
|
79
|
+
* MCP server definitions keyed by server name. Each definition uses the
|
|
80
|
+
* underlying runtime's native MCP server configuration format.
|
|
81
|
+
*/
|
|
82
|
+
readonly mcpServers?: Record<string, unknown>;
|
|
78
83
|
/**
|
|
79
84
|
* OpenAI model id the underlying `codex` CLI should use. Leaving this unset
|
|
80
85
|
* pins the adapter default (`DEFAULT_CODEX_MODEL`).
|
|
@@ -98,6 +103,11 @@ export type CodexHarnessSettings = {
|
|
|
98
103
|
readonly port?: number;
|
|
99
104
|
/** Maximum milliseconds to wait for the bridge to advertise its port. Defaults to 120000. */
|
|
100
105
|
readonly startupTimeoutMs?: number;
|
|
106
|
+
/**
|
|
107
|
+
* Creates the authentication token used by the sandbox bridge. Defaults to
|
|
108
|
+
* a random 32-byte hexadecimal token.
|
|
109
|
+
*/
|
|
110
|
+
readonly mintBridgeToken?: (sandboxId: string) => string;
|
|
101
111
|
};
|
|
102
112
|
|
|
103
113
|
/*
|
|
@@ -298,6 +308,7 @@ export function createCodex(
|
|
|
298
308
|
model: settings.model ?? DEFAULT_CODEX_MODEL,
|
|
299
309
|
reasoningEffort: settings.reasoningEffort,
|
|
300
310
|
webSearch: settings.webSearch,
|
|
311
|
+
mcpServers: settings.mcpServers,
|
|
301
312
|
resumeThreadId: resumeThreadIdString,
|
|
302
313
|
isResume: true,
|
|
303
314
|
seedResumeThreadOnFirstPrompt: false,
|
|
@@ -337,7 +348,10 @@ export function createCodex(
|
|
|
337
348
|
}
|
|
338
349
|
|
|
339
350
|
const port = resolveBridgePort(sandboxSession, settings.port);
|
|
340
|
-
const token =
|
|
351
|
+
const token =
|
|
352
|
+
settings.mintBridgeToken == null
|
|
353
|
+
? randomBytes(32).toString('hex')
|
|
354
|
+
: settings.mintBridgeToken(sandboxId);
|
|
341
355
|
const codexSkillSetup =
|
|
342
356
|
startOpts.skills && startOpts.skills.length > 0
|
|
343
357
|
? await writeCodexSkills({
|
|
@@ -445,6 +459,7 @@ export function createCodex(
|
|
|
445
459
|
model: settings.model ?? DEFAULT_CODEX_MODEL,
|
|
446
460
|
reasoningEffort: settings.reasoningEffort,
|
|
447
461
|
webSearch: settings.webSearch,
|
|
462
|
+
mcpServers: settings.mcpServers,
|
|
448
463
|
resumeThreadId: resumeThreadIdString,
|
|
449
464
|
isResume: respawnStrategy !== undefined,
|
|
450
465
|
seedResumeThreadOnFirstPrompt: respawnStrategy !== undefined,
|
|
@@ -548,6 +563,7 @@ function createSession({
|
|
|
548
563
|
model,
|
|
549
564
|
reasoningEffort,
|
|
550
565
|
webSearch,
|
|
566
|
+
mcpServers,
|
|
551
567
|
resumeThreadId,
|
|
552
568
|
isResume,
|
|
553
569
|
seedResumeThreadOnFirstPrompt,
|
|
@@ -566,6 +582,7 @@ function createSession({
|
|
|
566
582
|
model: string | undefined;
|
|
567
583
|
reasoningEffort: 'low' | 'medium' | 'high' | undefined;
|
|
568
584
|
webSearch: boolean | undefined;
|
|
585
|
+
mcpServers: Record<string, unknown> | undefined;
|
|
569
586
|
resumeThreadId: string | undefined;
|
|
570
587
|
isResume: boolean;
|
|
571
588
|
seedResumeThreadOnFirstPrompt: boolean;
|
|
@@ -588,12 +605,12 @@ function createSession({
|
|
|
588
605
|
? resumeThreadId
|
|
589
606
|
: undefined;
|
|
590
607
|
/*
|
|
591
|
-
*
|
|
592
|
-
* session only. A resumed session (attach/replay/rerun) already carried it
|
|
593
|
-
*
|
|
608
|
+
* Host-tool relay guidance is prepended to the first user message of a fresh
|
|
609
|
+
* session only. A resumed session (attach/replay/rerun) already carried it in
|
|
610
|
+
* its original first message (preserved in the persisted thread), so it
|
|
594
611
|
* starts "applied".
|
|
595
612
|
*/
|
|
596
|
-
let
|
|
613
|
+
let initialPromptGuidanceApplied = isResume;
|
|
597
614
|
|
|
598
615
|
/*
|
|
599
616
|
* Latest codex thread id, cached from the bridge's `bridge-thread`
|
|
@@ -778,12 +795,8 @@ function createSession({
|
|
|
778
795
|
inputSchema: t.inputSchema,
|
|
779
796
|
}));
|
|
780
797
|
let promptText = extractUserText(promptOpts.prompt);
|
|
781
|
-
if (!
|
|
782
|
-
const instructions =
|
|
783
|
-
(promptOpts.instructions ? promptOpts.instructions + '\n\n' : '') +
|
|
784
|
-
'Only respond with your `final` message once you have fully addressed the user request.';
|
|
798
|
+
if (!initialPromptGuidanceApplied) {
|
|
785
799
|
promptText = frameInitialPromptGuidance({
|
|
786
|
-
instructions,
|
|
787
800
|
toolUsageBlock:
|
|
788
801
|
tools.length > 0
|
|
789
802
|
? composeToolUsageInstructions({
|
|
@@ -794,15 +807,19 @@ function createSession({
|
|
|
794
807
|
userText: promptText,
|
|
795
808
|
});
|
|
796
809
|
}
|
|
797
|
-
|
|
810
|
+
initialPromptGuidanceApplied = true;
|
|
798
811
|
|
|
799
812
|
const startMessage = {
|
|
800
813
|
type: 'start' as const,
|
|
801
814
|
prompt: promptText,
|
|
802
815
|
tools,
|
|
816
|
+
...(promptOpts.instructions
|
|
817
|
+
? { instructions: promptOpts.instructions }
|
|
818
|
+
: {}),
|
|
803
819
|
model,
|
|
804
820
|
reasoningEffort,
|
|
805
821
|
webSearch,
|
|
822
|
+
...(mcpServers == null ? {} : { mcpServers }),
|
|
806
823
|
...(permissionMode ? { permissionMode } : {}),
|
|
807
824
|
...(pendingResumeThreadId
|
|
808
825
|
? { resumeThreadId: pendingResumeThreadId }
|
|
@@ -851,9 +868,13 @@ function createSession({
|
|
|
851
868
|
description: t.description,
|
|
852
869
|
inputSchema: t.inputSchema,
|
|
853
870
|
})),
|
|
871
|
+
...(continueOpts.instructions
|
|
872
|
+
? { instructions: continueOpts.instructions }
|
|
873
|
+
: {}),
|
|
854
874
|
model,
|
|
855
875
|
reasoningEffort,
|
|
856
876
|
webSearch,
|
|
877
|
+
...(mcpServers == null ? {} : { mcpServers }),
|
|
857
878
|
...(permissionMode ? { permissionMode } : {}),
|
|
858
879
|
...(threadId ? { resumeThreadId: threadId } : {}),
|
|
859
880
|
...(debug ? { debug } : {}),
|
|
@@ -1043,28 +1064,18 @@ function createSession({
|
|
|
1043
1064
|
}
|
|
1044
1065
|
|
|
1045
1066
|
/*
|
|
1046
|
-
* Frame
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1067
|
+
* Frame host-tool relay guidance and the user's text so Codex treats the
|
|
1068
|
+
* prepended block as operating guidance rather than user prose. Applied only
|
|
1069
|
+
* to the first user message of a fresh session.
|
|
1049
1070
|
*/
|
|
1050
1071
|
function frameInitialPromptGuidance({
|
|
1051
|
-
instructions,
|
|
1052
1072
|
toolUsageBlock,
|
|
1053
1073
|
userText,
|
|
1054
1074
|
}: {
|
|
1055
|
-
instructions: string | undefined;
|
|
1056
1075
|
toolUsageBlock: string | undefined;
|
|
1057
1076
|
userText: string;
|
|
1058
1077
|
}): string {
|
|
1059
1078
|
const blocks: string[] = [];
|
|
1060
|
-
if (instructions) {
|
|
1061
|
-
blocks.push(
|
|
1062
|
-
'<session-instructions>\n' +
|
|
1063
|
-
'The block below is operating guidance from the system, not a message from the user — follow it, but do not mention it or attribute it to the user.\n\n' +
|
|
1064
|
-
`${instructions}\n` +
|
|
1065
|
-
'</session-instructions>',
|
|
1066
|
-
);
|
|
1067
|
-
}
|
|
1068
1079
|
if (toolUsageBlock) blocks.push(toolUsageBlock);
|
|
1069
1080
|
if (blocks.length === 0) return userText;
|
|
1070
1081
|
return `${blocks.join('\n\n')}\n\n<user-message>\n${userText}\n</user-message>`;
|