@oai404iao/pi-codex-minimal-tools 1.3.0 → 1.4.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 +21 -0
- package/package.json +6 -2
- package/src/codex-identity-extension.ts +339 -0
- package/src/codex-wire-identity.ts +532 -118
- package/src/index.ts +2 -0
- package/src/provider-shim.ts +270 -97
- package/src/subagent-inline.ts +8 -0
- package/src/tools/web-search.ts +37 -7
package/src/index.ts
CHANGED
|
@@ -225,6 +225,8 @@ function registerTools(
|
|
|
225
225
|
}) as never);
|
|
226
226
|
pi.registerTool(createWebSearchToolDefinition({
|
|
227
227
|
getCurrentTurnId: (sessionId) => providerController?.getCurrentTurnId(sessionId),
|
|
228
|
+
getRequestIdentity: (sessionId) =>
|
|
229
|
+
providerController?.getRequestIdentity?.(sessionId),
|
|
228
230
|
}) as never);
|
|
229
231
|
pi.registerTool({
|
|
230
232
|
renderShell: "self",
|
package/src/provider-shim.ts
CHANGED
|
@@ -40,11 +40,15 @@ import { createCodexReservedNamespaceTool } from "./codex-reserved-tools.js";
|
|
|
40
40
|
import { rewriteNativeOpenAiTools } from "./provider-native-tools.js";
|
|
41
41
|
import {
|
|
42
42
|
captureCodexTurnState,
|
|
43
|
-
codexInstallationIdFor,
|
|
44
43
|
codexTurnStateFor,
|
|
44
|
+
currentCodexTurn,
|
|
45
|
+
isUuidV7,
|
|
46
|
+
resolveCodexRequestIdentity,
|
|
45
47
|
resolveCodexWireIdentity,
|
|
48
|
+
type CodexRequestIdentity,
|
|
46
49
|
uuidV7,
|
|
47
50
|
} from "./codex-wire-identity.js";
|
|
51
|
+
import { installCodexIdentityLifecycle } from "./codex-identity-extension.js";
|
|
48
52
|
import { applyFastModeServiceTier } from "./fast-mode.js";
|
|
49
53
|
import {
|
|
50
54
|
hasCodexRequestAuth,
|
|
@@ -217,14 +221,20 @@ interface SessionStartupPrewarmTask {
|
|
|
217
221
|
}
|
|
218
222
|
|
|
219
223
|
interface WebSocketRequestMetadata {
|
|
224
|
+
/** Legacy Pi session lookup key used by exported test helpers. */
|
|
220
225
|
sessionId?: string;
|
|
221
226
|
threadId?: string;
|
|
222
227
|
turnId: string;
|
|
223
228
|
requestKind?: "turn" | "compaction" | "prewarm";
|
|
229
|
+
identity?: CodexRequestIdentity;
|
|
224
230
|
}
|
|
225
231
|
|
|
226
232
|
export interface OpenAIResponsesProviderController {
|
|
227
233
|
getCurrentTurnId(sessionId: string | undefined): string | undefined;
|
|
234
|
+
getRequestIdentity?(
|
|
235
|
+
sessionId: string | undefined,
|
|
236
|
+
requestKind?: CodexRequestIdentity["requestKind"],
|
|
237
|
+
): CodexRequestIdentity | undefined;
|
|
228
238
|
}
|
|
229
239
|
|
|
230
240
|
let fsPromisesPromise: Promise<typeof import("node:fs/promises")> | undefined;
|
|
@@ -568,6 +578,14 @@ function headersToRecord(headers: Headers): Record<string, string> {
|
|
|
568
578
|
return Object.fromEntries(headers.entries());
|
|
569
579
|
}
|
|
570
580
|
|
|
581
|
+
function providerHeadersToHeaders(headers: ProviderHeaders): Headers {
|
|
582
|
+
const result = new Headers();
|
|
583
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
584
|
+
if (typeof value === "string") result.set(name, value);
|
|
585
|
+
}
|
|
586
|
+
return result;
|
|
587
|
+
}
|
|
588
|
+
|
|
571
589
|
function createCodexRequestId(): string {
|
|
572
590
|
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
573
591
|
return globalThis.crypto.randomUUID();
|
|
@@ -617,16 +635,39 @@ function applyWireIdentityHeaders(
|
|
|
617
635
|
headers: Headers,
|
|
618
636
|
sessionId: string | undefined,
|
|
619
637
|
threadId: string | undefined,
|
|
638
|
+
requestIdentity?: CodexRequestIdentity,
|
|
620
639
|
): void {
|
|
621
|
-
const wire = wireIdentityFor(sessionId, threadId);
|
|
640
|
+
const wire = requestIdentity ?? wireIdentityFor(sessionId, threadId);
|
|
622
641
|
if (!wire) return;
|
|
623
642
|
setProviderGeneratedHeader(headers, "session-id", wire.sessionId);
|
|
624
643
|
setProviderGeneratedHeader(headers, "thread-id", wire.threadId);
|
|
625
644
|
setProviderGeneratedHeader(headers, "x-codex-window-id", wire.windowId);
|
|
626
645
|
setProviderGeneratedHeader(headers, "x-client-request-id", wire.threadId);
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
646
|
+
const turnState = requestIdentity?.turnState
|
|
647
|
+
?? (sessionId ? codexTurnStateFor(sessionId) : undefined);
|
|
648
|
+
if (turnState) {
|
|
649
|
+
setProviderGeneratedHeader(headers, "x-codex-turn-state", turnState);
|
|
650
|
+
}
|
|
651
|
+
if (requestIdentity?.parentThreadId) {
|
|
652
|
+
setProviderGeneratedHeader(
|
|
653
|
+
headers,
|
|
654
|
+
"x-codex-parent-thread-id",
|
|
655
|
+
requestIdentity.parentThreadId,
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
if (requestIdentity?.subagentKind) {
|
|
659
|
+
setProviderGeneratedHeader(
|
|
660
|
+
headers,
|
|
661
|
+
"x-openai-subagent",
|
|
662
|
+
requestIdentity.subagentKind,
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
if (requestIdentity) {
|
|
666
|
+
setProviderGeneratedHeader(
|
|
667
|
+
headers,
|
|
668
|
+
"x-codex-turn-metadata",
|
|
669
|
+
buildCodexTurnMetadataJson(requestIdentity),
|
|
670
|
+
);
|
|
630
671
|
}
|
|
631
672
|
}
|
|
632
673
|
|
|
@@ -639,6 +680,7 @@ export function buildSSEHeaders(
|
|
|
639
680
|
sessionId: string | undefined,
|
|
640
681
|
profile: CodexRequestProfile,
|
|
641
682
|
threadId?: string,
|
|
683
|
+
requestIdentity?: CodexRequestIdentity,
|
|
642
684
|
): Headers {
|
|
643
685
|
const headers = buildBaseCodexHeaders(modelHeaders, additionalHeaders, accountId, token);
|
|
644
686
|
setProviderDefaultHeader(headers, "OpenAI-Beta", "responses=experimental");
|
|
@@ -648,7 +690,7 @@ export function buildSSEHeaders(
|
|
|
648
690
|
setProviderDefaultHeader(headers, X_OPENAI_INTERNAL_CODEX_RESPONSES_LITE, "true");
|
|
649
691
|
}
|
|
650
692
|
|
|
651
|
-
applyWireIdentityHeaders(headers, sessionId, threadId);
|
|
693
|
+
applyWireIdentityHeaders(headers, sessionId, threadId, requestIdentity);
|
|
652
694
|
|
|
653
695
|
return headers;
|
|
654
696
|
}
|
|
@@ -684,6 +726,7 @@ export function buildWebSocketHeaders(
|
|
|
684
726
|
token: string,
|
|
685
727
|
sessionId: string,
|
|
686
728
|
threadId = sessionId,
|
|
729
|
+
requestIdentity?: CodexRequestIdentity,
|
|
687
730
|
): Headers {
|
|
688
731
|
const headers = buildBaseCodexHeaders(modelHeaders, additionalHeaders, accountId, token);
|
|
689
732
|
headers.delete("accept");
|
|
@@ -694,13 +737,34 @@ export function buildWebSocketHeaders(
|
|
|
694
737
|
setProviderDefaultHeader(headers, "x-client-request-id", threadId);
|
|
695
738
|
setProviderDefaultHeader(headers, "session-id", sessionId);
|
|
696
739
|
setProviderDefaultHeader(headers, "thread-id", threadId);
|
|
697
|
-
const wire = wireIdentityFor(sessionId, threadId);
|
|
740
|
+
const wire = requestIdentity ?? wireIdentityFor(sessionId, threadId);
|
|
698
741
|
if (wire) {
|
|
699
742
|
setProviderGeneratedHeader(headers, "session-id", wire.sessionId);
|
|
700
743
|
setProviderGeneratedHeader(headers, "thread-id", wire.threadId);
|
|
701
744
|
setProviderGeneratedHeader(headers, "x-codex-window-id", wire.windowId);
|
|
702
745
|
setProviderGeneratedHeader(headers, "x-client-request-id", wire.threadId);
|
|
703
746
|
}
|
|
747
|
+
if (requestIdentity?.parentThreadId) {
|
|
748
|
+
setProviderGeneratedHeader(
|
|
749
|
+
headers,
|
|
750
|
+
"x-codex-parent-thread-id",
|
|
751
|
+
requestIdentity.parentThreadId,
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
if (requestIdentity?.subagentKind) {
|
|
755
|
+
setProviderGeneratedHeader(
|
|
756
|
+
headers,
|
|
757
|
+
"x-openai-subagent",
|
|
758
|
+
requestIdentity.subagentKind,
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
if (requestIdentity) {
|
|
762
|
+
setProviderGeneratedHeader(
|
|
763
|
+
headers,
|
|
764
|
+
"x-codex-turn-metadata",
|
|
765
|
+
buildCodexTurnMetadataJson(requestIdentity),
|
|
766
|
+
);
|
|
767
|
+
}
|
|
704
768
|
return headers;
|
|
705
769
|
}
|
|
706
770
|
|
|
@@ -872,26 +936,52 @@ export function withResponsesLiteWebSocketMetadata<T extends { client_metadata?:
|
|
|
872
936
|
* this blob (privacy normalization); once it honors client-supplied values,
|
|
873
937
|
* this keeps the shape identical to the CLI.
|
|
874
938
|
*/
|
|
875
|
-
function buildCodexTurnMetadataJson(
|
|
876
|
-
sessionId: string,
|
|
877
|
-
threadId: string | undefined,
|
|
878
|
-
turnId: string,
|
|
879
|
-
requestKind: "turn" | "compaction" | "prewarm",
|
|
880
|
-
): string {
|
|
881
|
-
const wire = wireIdentityFor(sessionId, threadId);
|
|
882
|
-
if (!wire) return "";
|
|
939
|
+
function buildCodexTurnMetadataJson(identity: CodexRequestIdentity): string {
|
|
883
940
|
const payload: Record<string, string | number> = {
|
|
884
|
-
installation_id:
|
|
885
|
-
session_id:
|
|
886
|
-
thread_id:
|
|
887
|
-
turn_id: turnId,
|
|
888
|
-
window_id:
|
|
889
|
-
request_kind: requestKind,
|
|
890
|
-
|
|
941
|
+
installation_id: identity.installationId,
|
|
942
|
+
session_id: identity.sessionId,
|
|
943
|
+
thread_id: identity.threadId,
|
|
944
|
+
turn_id: identity.turnId,
|
|
945
|
+
window_id: identity.windowId,
|
|
946
|
+
request_kind: identity.requestKind,
|
|
947
|
+
...(identity.turnStartedAtMs !== undefined
|
|
948
|
+
? { turn_started_at_unix_ms: identity.turnStartedAtMs }
|
|
949
|
+
: {}),
|
|
950
|
+
...(identity.agentName ? { agent_name: identity.agentName } : {}),
|
|
951
|
+
...(identity.forkedFromThreadId
|
|
952
|
+
? { forked_from_thread_id: identity.forkedFromThreadId }
|
|
953
|
+
: {}),
|
|
954
|
+
...(identity.parentThreadId
|
|
955
|
+
? { parent_thread_id: identity.parentThreadId }
|
|
956
|
+
: {}),
|
|
957
|
+
...(identity.parentTurnId
|
|
958
|
+
? { parent_turn_id: identity.parentTurnId }
|
|
959
|
+
: {}),
|
|
960
|
+
...(identity.rootTurnId
|
|
961
|
+
? { root_turn_id: identity.rootTurnId }
|
|
962
|
+
: {}),
|
|
963
|
+
...(identity.subagentKind
|
|
964
|
+
? { subagent_kind: identity.subagentKind }
|
|
965
|
+
: {}),
|
|
891
966
|
};
|
|
892
967
|
return JSON.stringify(payload);
|
|
893
968
|
}
|
|
894
969
|
|
|
970
|
+
function identityForRequestMetadata(
|
|
971
|
+
metadata: WebSocketRequestMetadata,
|
|
972
|
+
): CodexRequestIdentity | undefined {
|
|
973
|
+
if (metadata.identity) return metadata.identity;
|
|
974
|
+
const explicit: Record<string, unknown> = {
|
|
975
|
+
turn_id: metadata.turnId,
|
|
976
|
+
};
|
|
977
|
+
if (isUuidV7(metadata.threadId)) explicit.thread_id = metadata.threadId;
|
|
978
|
+
return resolveCodexRequestIdentity(
|
|
979
|
+
metadata.sessionId,
|
|
980
|
+
explicit,
|
|
981
|
+
metadata.requestKind ?? "turn",
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
|
|
895
985
|
/**
|
|
896
986
|
* Inject the Codex-compatible `client_metadata` for an SSE request, sourced
|
|
897
987
|
* from the same (session, thread, turn) metadata as the WebSocket path. The
|
|
@@ -899,56 +989,78 @@ function buildCodexTurnMetadataJson(
|
|
|
899
989
|
* Lite flag) stay out: SSE carries the Lite header and turn-state header.
|
|
900
990
|
*/
|
|
901
991
|
export function withSseRequestMetadata(body: ResponsesBody, metadata: WebSocketRequestMetadata): ResponsesBody {
|
|
902
|
-
const
|
|
903
|
-
if (!
|
|
904
|
-
const turnMetadata = buildCodexTurnMetadataJson(
|
|
905
|
-
metadata.sessionId,
|
|
906
|
-
metadata.threadId,
|
|
907
|
-
metadata.turnId,
|
|
908
|
-
metadata.requestKind ?? "turn",
|
|
909
|
-
);
|
|
992
|
+
const identity = identityForRequestMetadata(metadata);
|
|
993
|
+
if (!identity) return body;
|
|
994
|
+
const turnMetadata = buildCodexTurnMetadataJson(identity);
|
|
910
995
|
return {
|
|
911
996
|
...body,
|
|
912
997
|
client_metadata: {
|
|
913
998
|
...body.client_metadata,
|
|
914
|
-
session_id:
|
|
915
|
-
thread_id:
|
|
916
|
-
"x-codex-window-id":
|
|
917
|
-
turn_id:
|
|
918
|
-
"x-codex-installation-id":
|
|
999
|
+
session_id: identity.sessionId,
|
|
1000
|
+
thread_id: identity.threadId,
|
|
1001
|
+
"x-codex-window-id": identity.windowId,
|
|
1002
|
+
turn_id: identity.turnId,
|
|
1003
|
+
"x-codex-installation-id": identity.installationId,
|
|
1004
|
+
...(identity.parentThreadId
|
|
1005
|
+
? { "x-codex-parent-thread-id": identity.parentThreadId }
|
|
1006
|
+
: {}),
|
|
1007
|
+
...(identity.parentTurnId
|
|
1008
|
+
? { parent_turn_id: identity.parentTurnId }
|
|
1009
|
+
: {}),
|
|
1010
|
+
...(identity.rootTurnId
|
|
1011
|
+
? { root_turn_id: identity.rootTurnId }
|
|
1012
|
+
: {}),
|
|
1013
|
+
...(identity.subagentKind
|
|
1014
|
+
? { "x-openai-subagent": identity.subagentKind }
|
|
1015
|
+
: {}),
|
|
919
1016
|
...(turnMetadata ? { "x-codex-turn-metadata": turnMetadata } : {}),
|
|
920
1017
|
},
|
|
921
1018
|
};
|
|
922
1019
|
}
|
|
923
1020
|
|
|
924
1021
|
function withWebSocketRequestMetadata(body: ResponsesBody, metadata: WebSocketRequestMetadata): ResponsesBody {
|
|
925
|
-
const
|
|
926
|
-
const
|
|
927
|
-
const turnMetadata = metadata.sessionId
|
|
928
|
-
? buildCodexTurnMetadataJson(
|
|
929
|
-
metadata.sessionId,
|
|
930
|
-
metadata.threadId,
|
|
931
|
-
metadata.turnId,
|
|
932
|
-
metadata.requestKind ?? "turn",
|
|
933
|
-
)
|
|
934
|
-
: "";
|
|
1022
|
+
const identity = identityForRequestMetadata(metadata);
|
|
1023
|
+
const turnMetadata = identity ? buildCodexTurnMetadataJson(identity) : "";
|
|
935
1024
|
return {
|
|
936
1025
|
...body,
|
|
937
1026
|
client_metadata: {
|
|
938
1027
|
...body.client_metadata,
|
|
939
|
-
...(
|
|
940
|
-
...(
|
|
941
|
-
...(
|
|
942
|
-
turn_id: metadata.turnId,
|
|
943
|
-
...(
|
|
1028
|
+
...(identity ? { session_id: identity.sessionId } : {}),
|
|
1029
|
+
...(identity ? { thread_id: identity.threadId } : {}),
|
|
1030
|
+
...(identity ? { "x-codex-window-id": identity.windowId } : {}),
|
|
1031
|
+
turn_id: identity?.turnId ?? metadata.turnId,
|
|
1032
|
+
...(identity
|
|
1033
|
+
? { "x-codex-installation-id": identity.installationId }
|
|
1034
|
+
: {}),
|
|
1035
|
+
...(identity?.parentThreadId
|
|
1036
|
+
? { "x-codex-parent-thread-id": identity.parentThreadId }
|
|
1037
|
+
: {}),
|
|
1038
|
+
...(identity?.parentTurnId
|
|
1039
|
+
? { parent_turn_id: identity.parentTurnId }
|
|
1040
|
+
: {}),
|
|
1041
|
+
...(identity?.rootTurnId
|
|
1042
|
+
? { root_turn_id: identity.rootTurnId }
|
|
1043
|
+
: {}),
|
|
1044
|
+
...(identity?.subagentKind
|
|
1045
|
+
? { "x-openai-subagent": identity.subagentKind }
|
|
1046
|
+
: {}),
|
|
944
1047
|
...(turnMetadata ? { "x-codex-turn-metadata": turnMetadata } : {}),
|
|
945
|
-
...(turnState
|
|
1048
|
+
...(identity?.turnState
|
|
1049
|
+
? { "x-codex-turn-state": identity.turnState }
|
|
1050
|
+
: {}),
|
|
946
1051
|
[WS_STREAM_REQUEST_START_MS_CLIENT_METADATA_KEY]: Date.now().toString(),
|
|
947
1052
|
},
|
|
948
1053
|
};
|
|
949
1054
|
}
|
|
950
1055
|
|
|
951
1056
|
export function buildRequestBody<TApi extends Api>(model: Model<TApi>, context: Context, profile: CodexRequestProfile, options?: SimpleStreamOptions): ResponsesBody {
|
|
1057
|
+
const requestIdentity = resolveCodexRequestIdentity(
|
|
1058
|
+
options?.sessionId,
|
|
1059
|
+
options?.metadata as Record<string, unknown> | undefined,
|
|
1060
|
+
// Only the session-scoped prompt cache key is needed here. Do not
|
|
1061
|
+
// synthesize a logical turn while constructing startup/prewarm bodies.
|
|
1062
|
+
"prewarm",
|
|
1063
|
+
);
|
|
952
1064
|
const messages = convertResponsesMessages(model, context, new Set([...CODEX_TOOL_CALL_PROVIDERS, model.provider]), {
|
|
953
1065
|
includeSystemPrompt: false,
|
|
954
1066
|
});
|
|
@@ -997,7 +1109,7 @@ export function buildRequestBody<TApi extends Api>(model: Model<TApi>, context:
|
|
|
997
1109
|
input: [],
|
|
998
1110
|
text: { verbosity: ((options as { textVerbosity?: string } | undefined)?.textVerbosity ?? "low") as string },
|
|
999
1111
|
include: ["reasoning.encrypted_content"],
|
|
1000
|
-
prompt_cache_key:
|
|
1112
|
+
prompt_cache_key: requestIdentity?.sessionId ?? options?.sessionId,
|
|
1001
1113
|
tool_choice: "auto",
|
|
1002
1114
|
parallel_tool_calls: profile.supportsParallelTools,
|
|
1003
1115
|
};
|
|
@@ -2131,8 +2243,14 @@ function isPreviousResponseNotFoundError(error: unknown): boolean {
|
|
|
2131
2243
|
}
|
|
2132
2244
|
|
|
2133
2245
|
function webSocketHeaderIdentity(headers: Headers): string {
|
|
2246
|
+
const requestScoped = new Set([
|
|
2247
|
+
"x-codex-turn-metadata",
|
|
2248
|
+
"x-codex-turn-state",
|
|
2249
|
+
"x-codex-window-id",
|
|
2250
|
+
]);
|
|
2134
2251
|
return shortHash(
|
|
2135
2252
|
[...headers.entries()]
|
|
2253
|
+
.filter(([name]) => !requestScoped.has(name.toLowerCase()))
|
|
2136
2254
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
2137
2255
|
.map(([name, value]) => `${name}:${value}`)
|
|
2138
2256
|
.join("\n"),
|
|
@@ -2535,11 +2653,17 @@ function buildJsonHeaders(
|
|
|
2535
2653
|
accountId: string | undefined,
|
|
2536
2654
|
apiKey: string,
|
|
2537
2655
|
sessionId?: string,
|
|
2656
|
+
requestIdentity?: CodexRequestIdentity,
|
|
2538
2657
|
): Headers {
|
|
2539
2658
|
const headers = buildBaseCodexHeaders(modelHeaders, additionalHeaders, accountId, apiKey);
|
|
2540
2659
|
setProviderDefaultHeader(headers, "accept", "application/json");
|
|
2541
2660
|
setProviderDefaultHeader(headers, "content-type", "application/json");
|
|
2542
|
-
applyWireIdentityHeaders(
|
|
2661
|
+
applyWireIdentityHeaders(
|
|
2662
|
+
headers,
|
|
2663
|
+
sessionId,
|
|
2664
|
+
requestIdentity?.threadId ?? sessionId,
|
|
2665
|
+
requestIdentity,
|
|
2666
|
+
);
|
|
2543
2667
|
return headers;
|
|
2544
2668
|
}
|
|
2545
2669
|
|
|
@@ -2929,6 +3053,7 @@ async function requestCodexCompactionTriggerWithTransport(
|
|
|
2929
3053
|
options: {
|
|
2930
3054
|
sessionId?: string;
|
|
2931
3055
|
turnId?: string;
|
|
3056
|
+
requestIdentity?: CodexRequestIdentity;
|
|
2932
3057
|
signal?: AbortSignal;
|
|
2933
3058
|
settings: ResolvedCodexModelSettings;
|
|
2934
3059
|
maxRetries?: number;
|
|
@@ -2939,9 +3064,17 @@ async function requestCodexCompactionTriggerWithTransport(
|
|
|
2939
3064
|
const responsesMode = resolveCodexRequestProfile(options.settings.requestProfile).responsesMode;
|
|
2940
3065
|
const sseUrl = resolveCodexUrl(model.baseUrl, { apiKeyMode: options.settings.apiKeyMode });
|
|
2941
3066
|
const requestMetadata: WebSocketRequestMetadata = {
|
|
2942
|
-
...(options.sessionId ? { sessionId: options.sessionId
|
|
2943
|
-
|
|
3067
|
+
...(options.sessionId ? { sessionId: options.sessionId } : {}),
|
|
3068
|
+
...(options.requestIdentity?.threadId
|
|
3069
|
+
? { threadId: options.requestIdentity.threadId }
|
|
3070
|
+
: {}),
|
|
3071
|
+
turnId: options.requestIdentity?.turnId
|
|
3072
|
+
|| options.turnId
|
|
3073
|
+
|| createPiTurnId(),
|
|
2944
3074
|
requestKind: "compaction",
|
|
3075
|
+
...(options.requestIdentity
|
|
3076
|
+
? { identity: options.requestIdentity }
|
|
3077
|
+
: {}),
|
|
2945
3078
|
};
|
|
2946
3079
|
if (transport === "sse") {
|
|
2947
3080
|
return requestCodexCompactionTrigger(
|
|
@@ -3083,6 +3216,11 @@ export async function requestOpenAINativeCompaction(
|
|
|
3083
3216
|
auth,
|
|
3084
3217
|
apiKeyMode: settings.apiKeyMode,
|
|
3085
3218
|
});
|
|
3219
|
+
const requestIdentity = resolveCodexRequestIdentity(
|
|
3220
|
+
options.sessionId,
|
|
3221
|
+
options.turnId ? { turn_id: options.turnId } : undefined,
|
|
3222
|
+
"compaction",
|
|
3223
|
+
);
|
|
3086
3224
|
let body = applyFastModeServiceTier(buildRequestBody(model, context, profile, {
|
|
3087
3225
|
apiKey: options.apiKey,
|
|
3088
3226
|
headers: options.headers,
|
|
@@ -3116,8 +3254,12 @@ export async function requestOpenAINativeCompaction(
|
|
|
3116
3254
|
options.apiKey,
|
|
3117
3255
|
options.sessionId,
|
|
3118
3256
|
profile,
|
|
3257
|
+
requestIdentity?.threadId,
|
|
3258
|
+
requestIdentity,
|
|
3119
3259
|
), settings, model);
|
|
3120
|
-
const requestId =
|
|
3260
|
+
const requestId = requestIdentity?.threadId
|
|
3261
|
+
?? options.sessionId
|
|
3262
|
+
?? createCodexRequestId();
|
|
3121
3263
|
const websocketHeaders = applyConfiguredResponsesFeatureHeaders(buildWebSocketHeaders(
|
|
3122
3264
|
model.headers,
|
|
3123
3265
|
options.headers,
|
|
@@ -3125,6 +3267,7 @@ export async function requestOpenAINativeCompaction(
|
|
|
3125
3267
|
options.apiKey,
|
|
3126
3268
|
requestId,
|
|
3127
3269
|
requestId,
|
|
3270
|
+
requestIdentity,
|
|
3128
3271
|
), settings, model);
|
|
3129
3272
|
const item = await requestCodexCompactionTriggerWithTransport(
|
|
3130
3273
|
model,
|
|
@@ -3133,6 +3276,7 @@ export async function requestOpenAINativeCompaction(
|
|
|
3133
3276
|
{
|
|
3134
3277
|
sessionId: options.sessionId,
|
|
3135
3278
|
turnId: options.turnId,
|
|
3279
|
+
requestIdentity,
|
|
3136
3280
|
signal: options.signal,
|
|
3137
3281
|
settings,
|
|
3138
3282
|
maxRetries: options.maxRetries,
|
|
@@ -3148,6 +3292,7 @@ export async function requestOpenAINativeCompaction(
|
|
|
3148
3292
|
accountId,
|
|
3149
3293
|
options.apiKey,
|
|
3150
3294
|
options.sessionId,
|
|
3295
|
+
requestIdentity,
|
|
3151
3296
|
);
|
|
3152
3297
|
if (profile.responsesMode === "lite") {
|
|
3153
3298
|
setProviderGeneratedHeader(headers, X_OPENAI_INTERNAL_CODEX_RESPONSES_LITE, "true");
|
|
@@ -3688,15 +3833,16 @@ function createCodexStream<TApi extends Api>(
|
|
|
3688
3833
|
auth,
|
|
3689
3834
|
apiKeyMode: apiKeyTransport,
|
|
3690
3835
|
});
|
|
3836
|
+
const requestIdentity = resolveCodexRequestIdentity(
|
|
3837
|
+
options?.sessionId,
|
|
3838
|
+
options?.metadata as Record<string, unknown> | undefined,
|
|
3839
|
+
"turn",
|
|
3840
|
+
);
|
|
3691
3841
|
let body = applyFastModeServiceTier(
|
|
3692
3842
|
buildRequestBody(model, context, requestProfile, options),
|
|
3693
3843
|
settings,
|
|
3694
3844
|
model,
|
|
3695
3845
|
);
|
|
3696
|
-
const nextBody = await options?.onPayload?.(body, model);
|
|
3697
|
-
if (nextBody !== undefined) {
|
|
3698
|
-
body = nextBody as ResponsesBody;
|
|
3699
|
-
}
|
|
3700
3846
|
if (settings.nativeProviderTools) {
|
|
3701
3847
|
const webSearch = settings.modelProfile.effective.tools.webSearch;
|
|
3702
3848
|
body = rewriteNativeOpenAiTools(body, {
|
|
@@ -3710,46 +3856,59 @@ function createCodexStream<TApi extends Api>(
|
|
|
3710
3856
|
: false,
|
|
3711
3857
|
}).payload;
|
|
3712
3858
|
}
|
|
3859
|
+
const nextBody = await options?.onPayload?.(body, model);
|
|
3860
|
+
if (nextBody !== undefined) {
|
|
3861
|
+
body = nextBody as ResponsesBody;
|
|
3862
|
+
}
|
|
3713
3863
|
options = withRequestServiceTier(options, body.service_tier);
|
|
3714
3864
|
ensureWebSearchDetailsIncluded(body);
|
|
3715
3865
|
|
|
3716
|
-
const
|
|
3717
|
-
const
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
const
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
?? deps.getCurrentTurnId?.(options?.sessionId)
|
|
3725
|
-
?? createPiTurnId();
|
|
3726
|
-
const websocketRequestId = websocketThreadId || websocketSessionId || createCodexRequestId();
|
|
3866
|
+
const websocketSessionId = requestIdentity?.sessionId ?? options?.sessionId;
|
|
3867
|
+
const websocketThreadId = requestIdentity?.threadId ?? options?.sessionId;
|
|
3868
|
+
const websocketTurnId = requestIdentity?.turnId
|
|
3869
|
+
|| deps.getCurrentTurnId?.(options?.sessionId)
|
|
3870
|
+
|| createPiTurnId();
|
|
3871
|
+
const websocketRequestId = websocketThreadId
|
|
3872
|
+
|| websocketSessionId
|
|
3873
|
+
|| createCodexRequestId();
|
|
3727
3874
|
const websocketRequestMetadata: WebSocketRequestMetadata = {
|
|
3728
|
-
...(
|
|
3875
|
+
...(options?.sessionId ? { sessionId: options.sessionId } : {}),
|
|
3729
3876
|
...(websocketThreadId ? { threadId: websocketThreadId } : {}),
|
|
3730
3877
|
turnId: websocketTurnId,
|
|
3878
|
+
...(requestIdentity ? { identity: requestIdentity } : {}),
|
|
3731
3879
|
};
|
|
3732
|
-
|
|
3880
|
+
let sseHeaders = applyConfiguredResponsesFeatureHeaders(
|
|
3733
3881
|
buildSSEHeaders(
|
|
3734
3882
|
model.headers,
|
|
3735
3883
|
requestHeaders,
|
|
3736
3884
|
accountId,
|
|
3737
3885
|
apiKey,
|
|
3738
|
-
|
|
3886
|
+
options?.sessionId,
|
|
3739
3887
|
requestProfile,
|
|
3740
|
-
websocketThreadId
|
|
3888
|
+
websocketThreadId,
|
|
3889
|
+
requestIdentity,
|
|
3741
3890
|
),
|
|
3742
3891
|
settings,
|
|
3743
3892
|
model as Model<Api>,
|
|
3744
3893
|
);
|
|
3745
|
-
|
|
3894
|
+
let websocketHeaders = applyConfiguredResponsesFeatureHeaders(buildWebSocketHeaders(
|
|
3746
3895
|
model.headers,
|
|
3747
3896
|
requestHeaders,
|
|
3748
3897
|
accountId,
|
|
3749
3898
|
apiKey,
|
|
3750
|
-
|
|
3751
|
-
websocketThreadId
|
|
3899
|
+
options?.sessionId ?? websocketRequestId,
|
|
3900
|
+
websocketThreadId ?? websocketRequestId,
|
|
3901
|
+
requestIdentity,
|
|
3752
3902
|
), settings, model as Model<Api>);
|
|
3903
|
+
const transformHeaders = (
|
|
3904
|
+
options as
|
|
3905
|
+
| (SimpleStreamOptions & {
|
|
3906
|
+
transformHeaders?: (
|
|
3907
|
+
headers: ProviderHeaders,
|
|
3908
|
+
) => ProviderHeaders | Promise<ProviderHeaders>;
|
|
3909
|
+
})
|
|
3910
|
+
| undefined
|
|
3911
|
+
)?.transformHeaders;
|
|
3753
3912
|
const bodyJson = JSON.stringify(withSseRequestMetadata(body, websocketRequestMetadata));
|
|
3754
3913
|
const responseHeaderTimeoutMs = responseHeaderTimeoutMsFromOptions(options);
|
|
3755
3914
|
const configuredTransport: ProviderTransport = settings.openaiTransport;
|
|
@@ -3771,6 +3930,13 @@ function createCodexStream<TApi extends Api>(
|
|
|
3771
3930
|
&& websocketHttpFallbackSessions.has(fallbackKey);
|
|
3772
3931
|
|
|
3773
3932
|
if (transport !== "sse" && !sessionFellBackToHttp) {
|
|
3933
|
+
if (transformHeaders) {
|
|
3934
|
+
websocketHeaders = providerHeadersToHeaders(
|
|
3935
|
+
await transformHeaders(
|
|
3936
|
+
headersToRecord(websocketHeaders),
|
|
3937
|
+
),
|
|
3938
|
+
);
|
|
3939
|
+
}
|
|
3774
3940
|
const startupPrewarmTask = options?.sessionId
|
|
3775
3941
|
? deps.getStartupPrewarm?.(options.sessionId, model as Model<Api>)
|
|
3776
3942
|
: undefined;
|
|
@@ -3860,6 +4026,11 @@ function createCodexStream<TApi extends Api>(
|
|
|
3860
4026
|
let lastError: Error | undefined;
|
|
3861
4027
|
const sseUrl = resolveCodexUrl(model.baseUrl, { apiKeyMode: apiKeyTransport });
|
|
3862
4028
|
const sseDispatcher = await proxyDispatcherForUrl(sseUrl);
|
|
4029
|
+
if (transformHeaders) {
|
|
4030
|
+
sseHeaders = providerHeadersToHeaders(
|
|
4031
|
+
await transformHeaders(headersToRecord(sseHeaders)),
|
|
4032
|
+
);
|
|
4033
|
+
}
|
|
3863
4034
|
|
|
3864
4035
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
3865
4036
|
if (options?.signal?.aborted) {
|
|
@@ -3962,9 +4133,9 @@ export function registerOpenAIResponsesProviders(
|
|
|
3962
4133
|
pi: ExtensionAPI,
|
|
3963
4134
|
options: { getCurrentCwd: () => string },
|
|
3964
4135
|
): OpenAIResponsesProviderController {
|
|
4136
|
+
installCodexIdentityLifecycle(pi);
|
|
3965
4137
|
const pendingActivities: PendingActivity[] = [];
|
|
3966
4138
|
const imagePreviewCache = new Map<string, CachedImagePreview>();
|
|
3967
|
-
const activeTurnIds = new Map<string, string>();
|
|
3968
4139
|
const startupPrewarms = new Map<string, StartupPrewarmState>();
|
|
3969
4140
|
const sessionStartupPrewarmTasks = new Map<string, SessionStartupPrewarmTask>();
|
|
3970
4141
|
let sessionGeneration = 0;
|
|
@@ -4015,6 +4186,11 @@ export function registerOpenAIResponsesProviders(
|
|
|
4015
4186
|
}
|
|
4016
4187
|
|
|
4017
4188
|
const profile = resolveCodexRequestProfile(settings.requestProfile);
|
|
4189
|
+
const requestIdentity = resolveCodexRequestIdentity(
|
|
4190
|
+
sessionId,
|
|
4191
|
+
undefined,
|
|
4192
|
+
"prewarm",
|
|
4193
|
+
);
|
|
4018
4194
|
// Match Codex startup prewarm: snapshot only stable request context.
|
|
4019
4195
|
// Conversation history and the first user message are sent by the first
|
|
4020
4196
|
// real request as an incremental continuation from this response.
|
|
@@ -4069,7 +4245,8 @@ export function registerOpenAIResponsesProviders(
|
|
|
4069
4245
|
}),
|
|
4070
4246
|
auth.apiKey ?? "",
|
|
4071
4247
|
sessionId,
|
|
4072
|
-
sessionId,
|
|
4248
|
+
requestIdentity?.threadId ?? sessionId,
|
|
4249
|
+
requestIdentity,
|
|
4073
4250
|
), settings, model);
|
|
4074
4251
|
const cacheKey = webSocketCacheKey(
|
|
4075
4252
|
sessionId,
|
|
@@ -4105,9 +4282,10 @@ export function registerOpenAIResponsesProviders(
|
|
|
4105
4282
|
body,
|
|
4106
4283
|
requestMetadata: {
|
|
4107
4284
|
sessionId,
|
|
4108
|
-
threadId: sessionId,
|
|
4109
|
-
turnId:
|
|
4285
|
+
threadId: requestIdentity?.threadId ?? sessionId,
|
|
4286
|
+
turnId: requestIdentity?.turnId ?? "",
|
|
4110
4287
|
requestKind: "prewarm",
|
|
4288
|
+
...(requestIdentity ? { identity: requestIdentity } : {}),
|
|
4111
4289
|
},
|
|
4112
4290
|
signal: abortController.signal,
|
|
4113
4291
|
connectTimeoutMs: WEBSOCKET_PREWARM_TIMEOUT_MS,
|
|
@@ -4179,7 +4357,8 @@ export function registerOpenAIResponsesProviders(
|
|
|
4179
4357
|
}
|
|
4180
4358
|
return createCodexStream(model, context, streamOptions, {
|
|
4181
4359
|
getCurrentCwd: options.getCurrentCwd,
|
|
4182
|
-
getCurrentTurnId: (sessionId) =>
|
|
4360
|
+
getCurrentTurnId: (sessionId) =>
|
|
4361
|
+
currentCodexTurn(sessionId)?.turnId,
|
|
4183
4362
|
getStartupPrewarm: (sessionId, requestModel) => {
|
|
4184
4363
|
const task = sessionStartupPrewarmTasks.get(sessionId);
|
|
4185
4364
|
return task
|
|
@@ -4227,7 +4406,6 @@ export function registerOpenAIResponsesProviders(
|
|
|
4227
4406
|
sessionGeneration++;
|
|
4228
4407
|
abortStartupPrewarms();
|
|
4229
4408
|
ensureProviderShimForModel(ctx?.model as Model<Api> | undefined, ctx?.cwd);
|
|
4230
|
-
activeTurnIds.clear();
|
|
4231
4409
|
clearPendingMessages();
|
|
4232
4410
|
const generation = sessionGeneration;
|
|
4233
4411
|
// Do not block session startup. The first provider request naturally
|
|
@@ -4252,34 +4430,26 @@ export function registerOpenAIResponsesProviders(
|
|
|
4252
4430
|
ensureProviderShimForModel(ctx?.model as Model<Api> | undefined, ctx?.cwd);
|
|
4253
4431
|
});
|
|
4254
4432
|
|
|
4255
|
-
pi.on("session_shutdown", async () => {
|
|
4433
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
4256
4434
|
sessionGeneration++;
|
|
4257
4435
|
abortStartupPrewarms();
|
|
4258
4436
|
if (pendingActivities.length > 0) {
|
|
4259
4437
|
flushPendingMessages();
|
|
4260
4438
|
}
|
|
4261
|
-
|
|
4262
|
-
|
|
4439
|
+
closeProviderWebSocketSessions(
|
|
4440
|
+
ctx?.sessionManager?.getSessionId?.(),
|
|
4441
|
+
);
|
|
4263
4442
|
clearPendingMessages();
|
|
4264
4443
|
});
|
|
4265
4444
|
|
|
4266
4445
|
pi.on("before_agent_start", async (_event, ctx) => {
|
|
4267
4446
|
ensureProviderShimForModel(ctx.model as Model<Api> | undefined, ctx.cwd);
|
|
4268
|
-
const sessionId = ctx?.sessionManager?.getSessionId();
|
|
4269
|
-
if (!sessionId) return;
|
|
4270
|
-
const turnId = createPiTurnId();
|
|
4271
|
-
activeTurnIds.set(sessionId, turnId);
|
|
4272
4447
|
});
|
|
4273
4448
|
|
|
4274
4449
|
pi.on("agent_end", async (_event, ctx) => {
|
|
4275
4450
|
schedulePendingMessageFlush();
|
|
4276
4451
|
});
|
|
4277
4452
|
|
|
4278
|
-
pi.on("agent_settled", async (_event, ctx) => {
|
|
4279
|
-
const sessionId = ctx?.sessionManager?.getSessionId();
|
|
4280
|
-
if (sessionId) activeTurnIds.delete(sessionId);
|
|
4281
|
-
});
|
|
4282
|
-
|
|
4283
4453
|
pi.registerMessageRenderer<ImageDisplayMessageDetails>(IMAGE_SAVE_DISPLAY_MESSAGE_TYPE, (message, options, theme) => {
|
|
4284
4454
|
const savedImage = message.details?.savedImages?.[0];
|
|
4285
4455
|
const textContent = typeof message.content === "string"
|
|
@@ -4332,7 +4502,10 @@ export function registerOpenAIResponsesProviders(
|
|
|
4332
4502
|
|
|
4333
4503
|
return {
|
|
4334
4504
|
getCurrentTurnId(sessionId) {
|
|
4335
|
-
return
|
|
4505
|
+
return currentCodexTurn(sessionId)?.turnId;
|
|
4506
|
+
},
|
|
4507
|
+
getRequestIdentity(sessionId, requestKind = "turn") {
|
|
4508
|
+
return resolveCodexRequestIdentity(sessionId, undefined, requestKind);
|
|
4336
4509
|
},
|
|
4337
4510
|
};
|
|
4338
4511
|
}
|