@oai404iao/pi-codex-runtime 0.1.0-alpha.1

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.
Files changed (49) hide show
  1. package/LICENSE +28 -0
  2. package/LICENSES/Apache-2.0.txt +201 -0
  3. package/LICENSES/OpenAI-Codex-NOTICE.txt +6 -0
  4. package/README.md +26 -0
  5. package/THIRD_PARTY_NOTICES.md +19 -0
  6. package/config.schema.json +174 -0
  7. package/models.schema.json +217 -0
  8. package/package.json +68 -0
  9. package/provenance/openai-codex-eb9dceba-reserved-tools.json +140 -0
  10. package/src/activation.ts +56 -0
  11. package/src/broker.ts +133 -0
  12. package/src/capabilities.ts +146 -0
  13. package/src/codex-http.ts +133 -0
  14. package/src/codex-identity-extension.ts +341 -0
  15. package/src/codex-request-profile.ts +45 -0
  16. package/src/codex-reserved-tools.ts +33 -0
  17. package/src/codex-wire-identity.ts +596 -0
  18. package/src/extension/provider-presentation.ts +11 -0
  19. package/src/glyphs.ts +70 -0
  20. package/src/index.ts +4 -0
  21. package/src/model-catalog/catalog.ts +636 -0
  22. package/src/model-catalog/default-models.json +252 -0
  23. package/src/model-catalog/runtime.ts +113 -0
  24. package/src/model-catalog/types.ts +95 -0
  25. package/src/provider-headers.ts +54 -0
  26. package/src/providers/openai-codex/stream-effects.ts +21 -0
  27. package/src/providers/openai-codex/types.ts +155 -0
  28. package/src/providers/responses/citations.ts +105 -0
  29. package/src/providers/responses/history.ts +144 -0
  30. package/src/providers/responses/items.ts +87 -0
  31. package/src/providers/responses/markdown.ts +92 -0
  32. package/src/providers/responses/messages.ts +169 -0
  33. package/src/providers/responses/signatures.ts +102 -0
  34. package/src/providers/responses/stream-state.ts +99 -0
  35. package/src/providers/responses/stream.ts +386 -0
  36. package/src/providers/responses/text-renderer.ts +147 -0
  37. package/src/providers/responses/text.ts +32 -0
  38. package/src/providers/responses/tool-identity.ts +25 -0
  39. package/src/providers/responses/tools.ts +14 -0
  40. package/src/providers/responses/types.ts +113 -0
  41. package/src/providers/responses/usage.ts +53 -0
  42. package/src/reserved-tools/image-generation.ts +53 -0
  43. package/src/reserved-tools/types.ts +32 -0
  44. package/src/reserved-tools/web-search.ts +269 -0
  45. package/src/session-claims.ts +19 -0
  46. package/src/settings.ts +247 -0
  47. package/src/subagent-inline.ts +8 -0
  48. package/src/tool-activation.ts +89 -0
  49. package/src/utils/theme.ts +7 -0
@@ -0,0 +1,252 @@
1
+ {
2
+ "version": 1,
3
+ "models": [
4
+ {
5
+ "id": "openai/gpt-5.6-sol",
6
+ "enabled": true,
7
+ "responses": {
8
+ "providerShim": true,
9
+ "endpoint": "openai",
10
+ "mode": "lite",
11
+ "systemPromptPlacement": "developer",
12
+ "transport": "auto",
13
+ "websocketPrewarm": true
14
+ },
15
+ "tools": {
16
+ "parallelCalls": false,
17
+ "applyPatch": "custom",
18
+ "webSearch": {
19
+ "implementation": "standalone",
20
+ "contentTypes": ["text", "image"]
21
+ },
22
+ "imageGeneration": "standalone",
23
+ "viewImage": false
24
+ },
25
+ "compaction": "responses",
26
+ "fast": {
27
+ "serviceTier": "priority",
28
+ "costMultiplier": 2
29
+ }
30
+ },
31
+ {
32
+ "id": "openai/gpt-5.6-terra",
33
+ "extends": "openai/gpt-5.6-sol"
34
+ },
35
+ {
36
+ "id": "openai/gpt-5.6-luna",
37
+ "extends": "openai/gpt-5.6-sol"
38
+ },
39
+ {
40
+ "id": "openai/gpt-5.5",
41
+ "enabled": true,
42
+ "responses": {
43
+ "providerShim": true,
44
+ "endpoint": "openai",
45
+ "mode": "standard",
46
+ "systemPromptPlacement": "instructions",
47
+ "transport": "auto",
48
+ "websocketPrewarm": true
49
+ },
50
+ "tools": {
51
+ "parallelCalls": true,
52
+ "applyPatch": "custom",
53
+ "webSearch": {
54
+ "implementation": "hosted",
55
+ "contentTypes": ["text", "image"]
56
+ },
57
+ "imageGeneration": "standalone",
58
+ "viewImage": false
59
+ },
60
+ "compaction": "responses",
61
+ "fast": {
62
+ "serviceTier": "priority",
63
+ "costMultiplier": 2.5
64
+ }
65
+ },
66
+ {
67
+ "id": "openai/gpt-5.4",
68
+ "extends": "openai/gpt-5.5",
69
+ "fast": {
70
+ "serviceTier": "priority",
71
+ "costMultiplier": 2
72
+ }
73
+ },
74
+ {
75
+ "id": "openai/gpt-5.4-mini",
76
+ "extends": "openai/gpt-5.4",
77
+ "fast": false
78
+ },
79
+ {
80
+ "id": "openai/gpt-5.2",
81
+ "extends": "openai/gpt-5.4-mini",
82
+ "tools": {
83
+ "webSearch": {
84
+ "implementation": "hosted",
85
+ "contentTypes": ["text"]
86
+ }
87
+ }
88
+ },
89
+ {
90
+ "id": "openai/codex-auto-review",
91
+ "extends": "openai/gpt-5.4-mini"
92
+ },
93
+ {
94
+ "id": "openai/gpt-5",
95
+ "extends": "openai/gpt-5.2",
96
+ "fast": {
97
+ "serviceTier": "priority",
98
+ "costMultiplier": 2
99
+ }
100
+ },
101
+ {
102
+ "id": "openai/gpt-5-mini",
103
+ "extends": "openai/gpt-5",
104
+ "fast": false
105
+ },
106
+ {
107
+ "id": "openai/gpt-5.1",
108
+ "extends": "openai/gpt-5"
109
+ },
110
+ {
111
+ "id": "openai/gpt-5.1-codex",
112
+ "extends": "openai/gpt-5.1"
113
+ },
114
+ {
115
+ "id": "openai/gpt-5.3-codex",
116
+ "extends": "openai/gpt-5.4-mini"
117
+ },
118
+ {
119
+ "id": "openai/gpt-4.1",
120
+ "enabled": true,
121
+ "responses": {
122
+ "providerShim": true,
123
+ "endpoint": "openai",
124
+ "mode": "standard",
125
+ "systemPromptPlacement": "instructions",
126
+ "transport": "sse",
127
+ "websocketPrewarm": false
128
+ },
129
+ "tools": {
130
+ "parallelCalls": true,
131
+ "applyPatch": false,
132
+ "webSearch": false,
133
+ "imageGeneration": "hosted",
134
+ "viewImage": false
135
+ },
136
+ "compaction": "pi",
137
+ "fast": false
138
+ },
139
+ {
140
+ "id": "openai/o4-mini",
141
+ "extends": "openai/gpt-4.1",
142
+ "tools": {
143
+ "imageGeneration": false
144
+ }
145
+ },
146
+ {
147
+ "id": "openai-codex/gpt-5.6-sol",
148
+ "extends": "openai/gpt-5.6-sol",
149
+ "responses": {
150
+ "endpoint": "codex"
151
+ }
152
+ },
153
+ {
154
+ "id": "openai-codex/gpt-5.6-terra",
155
+ "extends": "openai/gpt-5.6-terra",
156
+ "responses": {
157
+ "endpoint": "codex"
158
+ }
159
+ },
160
+ {
161
+ "id": "openai-codex/gpt-5.6-luna",
162
+ "extends": "openai/gpt-5.6-luna",
163
+ "responses": {
164
+ "endpoint": "codex"
165
+ }
166
+ },
167
+ {
168
+ "id": "openai-codex/gpt-5.5",
169
+ "extends": "openai/gpt-5.5",
170
+ "responses": {
171
+ "endpoint": "codex"
172
+ }
173
+ },
174
+ {
175
+ "id": "openai-codex/gpt-5.4",
176
+ "extends": "openai/gpt-5.4",
177
+ "responses": {
178
+ "endpoint": "codex"
179
+ }
180
+ },
181
+ {
182
+ "id": "openai-codex/gpt-5.4-mini",
183
+ "extends": "openai/gpt-5.4-mini",
184
+ "responses": {
185
+ "endpoint": "codex"
186
+ }
187
+ },
188
+ {
189
+ "id": "openai-codex/gpt-5.2",
190
+ "extends": "openai/gpt-5.2",
191
+ "responses": {
192
+ "endpoint": "codex"
193
+ }
194
+ },
195
+ {
196
+ "id": "openai-codex/codex-auto-review",
197
+ "extends": "openai/codex-auto-review",
198
+ "responses": {
199
+ "endpoint": "codex"
200
+ }
201
+ },
202
+ {
203
+ "id": "openai-codex/gpt-5",
204
+ "extends": "openai/gpt-5",
205
+ "responses": {
206
+ "endpoint": "codex"
207
+ }
208
+ },
209
+ {
210
+ "id": "openai-codex/gpt-5-mini",
211
+ "extends": "openai/gpt-5-mini",
212
+ "responses": {
213
+ "endpoint": "codex"
214
+ }
215
+ },
216
+ {
217
+ "id": "openai-codex/gpt-5.1",
218
+ "extends": "openai/gpt-5.1",
219
+ "responses": {
220
+ "endpoint": "codex"
221
+ }
222
+ },
223
+ {
224
+ "id": "openai-codex/gpt-5.1-codex",
225
+ "extends": "openai/gpt-5.1-codex",
226
+ "responses": {
227
+ "endpoint": "codex"
228
+ }
229
+ },
230
+ {
231
+ "id": "openai-codex/gpt-5.3-codex",
232
+ "extends": "openai/gpt-5.3-codex",
233
+ "responses": {
234
+ "endpoint": "codex"
235
+ }
236
+ },
237
+ {
238
+ "id": "openai-codex/gpt-4.1",
239
+ "extends": "openai/gpt-4.1",
240
+ "responses": {
241
+ "endpoint": "codex"
242
+ }
243
+ },
244
+ {
245
+ "id": "openai-codex/o4-mini",
246
+ "extends": "openai/o4-mini",
247
+ "responses": {
248
+ "endpoint": "codex"
249
+ }
250
+ }
251
+ ]
252
+ }
@@ -0,0 +1,113 @@
1
+ import type { CodexRequestProfileOverride } from "../codex-request-profile.js";
2
+ import {
3
+ loadSettings,
4
+ type CodexMinimalToolsSettings,
5
+ } from "../settings.js";
6
+ import { resolveModelProfile } from "./catalog.js";
7
+ import type {
8
+ ModelIdentityLike,
9
+ ResolvedModelProfile,
10
+ ResponsesEndpoint,
11
+ } from "./types.js";
12
+
13
+ export interface ResolvedCodexModelSettings extends CodexMinimalToolsSettings {
14
+ modelProfile?: ResolvedModelProfile;
15
+ modelProfileHash?: string;
16
+ providerShimActive?: boolean;
17
+ webSearchImplementation?: "hosted" | "standalone";
18
+ imageGenerationImplementation?: "hosted" | "standalone";
19
+ fastServiceTier?: string;
20
+ fastCostMultiplier?: number;
21
+ }
22
+
23
+ function endpointUsesApiKey(endpoint: ResponsesEndpoint, model: ModelIdentityLike | undefined): boolean {
24
+ if (endpoint === "openai") return true;
25
+ if (endpoint === "codex") return false;
26
+ return model?.provider !== "openai-codex";
27
+ }
28
+
29
+ export function supportsCodexResponsesApi(model: ModelIdentityLike | undefined): boolean {
30
+ if (model?.api === "openai-responses" || model?.api === "openai-codex-responses") return true;
31
+ if (model?.api) return false;
32
+ return model?.provider === "openai" || model?.provider === "openai-codex";
33
+ }
34
+
35
+ export function loadModelSettings(
36
+ model: ModelIdentityLike | undefined,
37
+ cwd?: string,
38
+ baseSettings = loadSettings(cwd),
39
+ ): ResolvedCodexModelSettings {
40
+ const modelProfile = resolveModelProfile(model, { settings: baseSettings });
41
+ if (!modelProfile || !modelProfile.effective.enabled) {
42
+ return {
43
+ ...baseSettings,
44
+ providerShimActive: false,
45
+ nativeProviderTools: false,
46
+ openaiTransport: "sse",
47
+ openaiWebSocketPrewarm: false,
48
+ compactionMode: "pi",
49
+ requestProfile: {
50
+ responsesMode: "standard",
51
+ reasoningSummary: "auto",
52
+ systemPromptPlacement: "instructions",
53
+ patchTransport: "function",
54
+ supportsHostedTools: false,
55
+ supportsParallelTools: true,
56
+ },
57
+ apiKeyMode: model?.provider !== "openai-codex",
58
+ imageGeneration: false,
59
+ webSearchEnabled: false,
60
+ viewImage: false,
61
+ applyPatchEnabled: false,
62
+ };
63
+ }
64
+
65
+ const effective = modelProfile.effective;
66
+ const packageEnabled = baseSettings.enabled;
67
+ const providerShimActive = packageEnabled
68
+ && effective.responses.providerShim
69
+ && supportsCodexResponsesApi(model);
70
+ const configuredWebSearchImplementation = effective.tools.webSearch
71
+ ? effective.tools.webSearch.implementation
72
+ : undefined;
73
+ const configuredImageGenerationImplementation = effective.tools.imageGeneration || undefined;
74
+ const webSearchImplementation = !packageEnabled
75
+ || (configuredWebSearchImplementation === "hosted" && !providerShimActive)
76
+ ? undefined
77
+ : configuredWebSearchImplementation;
78
+ const imageGenerationImplementation = !packageEnabled
79
+ || (configuredImageGenerationImplementation === "hosted" && !providerShimActive)
80
+ ? undefined
81
+ : configuredImageGenerationImplementation;
82
+ const supportsHostedTools = webSearchImplementation === "hosted"
83
+ || imageGenerationImplementation === "hosted";
84
+ const usesProviderToolRewrite = Boolean(webSearchImplementation || imageGenerationImplementation);
85
+ const requestProfile: CodexRequestProfileOverride = {
86
+ responsesMode: effective.responses.mode,
87
+ reasoningSummary: effective.responses.reasoningSummary,
88
+ systemPromptPlacement: effective.responses.systemPromptPlacement,
89
+ patchTransport: effective.tools.applyPatch === "custom" ? "custom" : "function",
90
+ supportsHostedTools,
91
+ supportsParallelTools: effective.tools.parallelCalls,
92
+ };
93
+ return {
94
+ ...baseSettings,
95
+ providerShimActive,
96
+ nativeProviderTools: providerShimActive && usesProviderToolRewrite,
97
+ openaiTransport: effective.responses.transport,
98
+ openaiWebSocketPrewarm: effective.responses.websocketPrewarm,
99
+ compactionMode: providerShimActive ? effective.compaction : "pi",
100
+ requestProfile,
101
+ apiKeyMode: endpointUsesApiKey(effective.responses.endpoint, model),
102
+ imageGeneration: imageGenerationImplementation !== undefined,
103
+ webSearchEnabled: webSearchImplementation !== undefined,
104
+ viewImage: packageEnabled && effective.tools.viewImage,
105
+ applyPatchEnabled: packageEnabled && effective.tools.applyPatch !== false,
106
+ modelProfile,
107
+ modelProfileHash: modelProfile.profileHash,
108
+ webSearchImplementation,
109
+ imageGenerationImplementation,
110
+ fastServiceTier: providerShimActive && effective.fast ? effective.fast.serviceTier : undefined,
111
+ fastCostMultiplier: providerShimActive && effective.fast ? effective.fast.costMultiplier : undefined,
112
+ };
113
+ }
@@ -0,0 +1,95 @@
1
+ export type ResponsesEndpoint = "auto" | "openai" | "codex";
2
+ export type ResponsesMode = "standard" | "lite";
3
+ export type ReasoningSummary = "auto" | "concise" | "detailed" | "none";
4
+ export type ResponsesTransport = "sse" | "websocket" | "websocket-cached" | "auto";
5
+ export type SystemPromptPlacement = "instructions" | "developer";
6
+ export type PatchTransport = "function" | "custom";
7
+ export type WebSearchContentType = "text" | "image";
8
+ export type NativeCompactionMode = "pi" | "responses" | "responses-compact";
9
+
10
+ export interface ModelIdentityLike {
11
+ provider?: string;
12
+ id?: string;
13
+ name?: string;
14
+ api?: string;
15
+ }
16
+
17
+ export interface ResponsesProfilePatch {
18
+ providerShim?: boolean;
19
+ endpoint?: ResponsesEndpoint;
20
+ mode?: ResponsesMode;
21
+ reasoningSummary?: ReasoningSummary;
22
+ systemPromptPlacement?: SystemPromptPlacement;
23
+ transport?: ResponsesTransport;
24
+ websocketPrewarm?: boolean;
25
+ }
26
+
27
+ export interface WebSearchProfile {
28
+ implementation: "hosted" | "standalone";
29
+ contentTypes?: WebSearchContentType[];
30
+ }
31
+
32
+ export interface ModelToolsProfilePatch {
33
+ parallelCalls?: boolean;
34
+ applyPatch?: false | PatchTransport;
35
+ webSearch?: false | WebSearchProfile;
36
+ imageGeneration?: false | "hosted" | "standalone";
37
+ viewImage?: boolean;
38
+ }
39
+
40
+ export interface FastModeProfile {
41
+ serviceTier: string;
42
+ costMultiplier?: number;
43
+ }
44
+
45
+ export interface ModelProfilePatch {
46
+ id: string;
47
+ extends?: string;
48
+ enabled?: boolean;
49
+ responses?: ResponsesProfilePatch;
50
+ tools?: ModelToolsProfilePatch;
51
+ compaction?: NativeCompactionMode;
52
+ fast?: false | FastModeProfile;
53
+ }
54
+
55
+ export interface ModelCatalogFile {
56
+ $schema?: string;
57
+ version: 1;
58
+ models: ModelProfilePatch[];
59
+ }
60
+
61
+ export interface EffectiveResponsesProfile {
62
+ providerShim: boolean;
63
+ endpoint: ResponsesEndpoint;
64
+ mode: ResponsesMode;
65
+ reasoningSummary: ReasoningSummary;
66
+ systemPromptPlacement: SystemPromptPlacement;
67
+ transport: ResponsesTransport;
68
+ websocketPrewarm: boolean;
69
+ }
70
+
71
+ export interface EffectiveModelToolsProfile {
72
+ parallelCalls: boolean;
73
+ applyPatch: false | PatchTransport;
74
+ webSearch: false | WebSearchProfile;
75
+ imageGeneration: false | "hosted" | "standalone";
76
+ viewImage: boolean;
77
+ }
78
+
79
+ export interface EffectiveModelProfile {
80
+ enabled: boolean;
81
+ responses: EffectiveResponsesProfile;
82
+ tools: EffectiveModelToolsProfile;
83
+ compaction: NativeCompactionMode;
84
+ fast: false | FastModeProfile;
85
+ }
86
+
87
+ export type ModelProfileSource = "bundled" | "user" | "legacy";
88
+
89
+ export interface ResolvedModelProfile {
90
+ id: string;
91
+ sources: ModelProfileSource[];
92
+ profileHash: string;
93
+ effective: EffectiveModelProfile;
94
+ diagnostics: string[];
95
+ }
@@ -0,0 +1,54 @@
1
+ import type { ProviderHeaders } from "@earendil-works/pi-ai";
2
+
3
+ const suppressedHeaders = new WeakMap<Headers, Set<string>>();
4
+
5
+ function normalizedName(name: string): string {
6
+ return name.trim().toLowerCase();
7
+ }
8
+
9
+ export function providerHeaderDirective(
10
+ headers: ProviderHeaders | undefined,
11
+ name: string,
12
+ ): string | null | undefined {
13
+ const target = normalizedName(name);
14
+ let directive: string | null | undefined;
15
+ for (const [candidate, value] of Object.entries(headers ?? {})) {
16
+ if (normalizedName(candidate) === target) directive = value;
17
+ }
18
+ return directive;
19
+ }
20
+
21
+ export function mergeProviderHeaders(...layers: Array<ProviderHeaders | undefined>): Headers {
22
+ const headers = new Headers();
23
+ const suppressed = new Set<string>();
24
+ for (const layer of layers) {
25
+ for (const [name, value] of Object.entries(layer ?? {})) {
26
+ const normalized = normalizedName(name);
27
+ if (value === null) {
28
+ headers.delete(name);
29
+ suppressed.add(normalized);
30
+ } else {
31
+ headers.set(name, value);
32
+ suppressed.delete(normalized);
33
+ }
34
+ }
35
+ }
36
+ suppressedHeaders.set(headers, suppressed);
37
+ return headers;
38
+ }
39
+
40
+ export function isProviderHeaderSuppressed(headers: Headers, name: string): boolean {
41
+ return suppressedHeaders.get(headers)?.has(normalizedName(name)) ?? false;
42
+ }
43
+
44
+ export function setProviderDefaultHeader(headers: Headers, name: string, value: string): boolean {
45
+ if (isProviderHeaderSuppressed(headers, name) || headers.has(name)) return false;
46
+ headers.set(name, value);
47
+ return true;
48
+ }
49
+
50
+ export function setProviderGeneratedHeader(headers: Headers, name: string, value: string): boolean {
51
+ if (isProviderHeaderSuppressed(headers, name)) return false;
52
+ headers.set(name, value);
53
+ return true;
54
+ }
@@ -0,0 +1,21 @@
1
+ import type { AssistantMessage, AssistantMessageEventStream } from "@earendil-works/pi-ai/compat";
2
+ import type { StreamEventShape } from "./types.js";
3
+
4
+ export interface ProviderEventContext {
5
+ cwd: string;
6
+ requestPrompt?: string;
7
+ signal?: AbortSignal;
8
+ output: AssistantMessage;
9
+ stream: AssistantMessageEventStream;
10
+ }
11
+
12
+ /**
13
+ * A fresh observer is created for each response attempt. Events are normalized
14
+ * and continuation items captured before observation; observation is awaited
15
+ * before replay parsing. Observers must not mutate wire items or consume events.
16
+ * Optional effects own their failure policy; uncaught errors fail the stream.
17
+ */
18
+ export interface ProviderStreamEffects {
19
+ createEventObserver?: (context: ProviderEventContext) =>
20
+ (event: StreamEventShape) => void | Promise<void>;
21
+ }
@@ -0,0 +1,155 @@
1
+ import { type SimpleStreamOptions } from "@earendil-works/pi-ai/compat";
2
+ import { type ResponseCreateParamsStreaming } from "openai/resources/responses/responses.js";
3
+ import { type CodexRequestIdentity } from "../../codex-wire-identity.js";
4
+
5
+ export interface WebSocketLike {
6
+ readyState?: number;
7
+ bufferedAmount?: number;
8
+ send(data: string, callback?: (error?: Error) => void): void;
9
+ close(code?: number, reason?: string): void;
10
+ addEventListener(type: string, listener: (event: unknown) => void): void;
11
+ removeEventListener(type: string, listener: (event: unknown) => void): void;
12
+ }
13
+
14
+ export interface SessionWebSocketCacheEntry {
15
+ socket: WebSocketLike;
16
+ busy: boolean;
17
+ waiters: WebSocketAcquireWaiter[];
18
+ idleTimer?: ReturnType<typeof setTimeout>;
19
+ continuation?: CachedWebSocketContinuationState;
20
+ }
21
+
22
+ export interface WebSocketAcquireWaiter {
23
+ resolve: (acquired: AcquiredWebSocket) => void;
24
+ reject: (error: Error) => void;
25
+ signal?: AbortSignal;
26
+ onAbort?: () => void;
27
+ }
28
+
29
+ export interface AcquiredWebSocket {
30
+ socket: WebSocketLike;
31
+ entry?: SessionWebSocketCacheEntry;
32
+ reused: boolean;
33
+ release: (options?: { keep?: boolean }) => void;
34
+ }
35
+
36
+ export interface CachedWebSocketContinuationState {
37
+ lastRequestBody: ResponsesBody;
38
+ lastResponseId: string;
39
+ lastResponseItems: unknown[];
40
+ }
41
+
42
+ export interface WebSocketPrewarmRequest {
43
+ url: string;
44
+ headers: Headers;
45
+ cacheKey: string;
46
+ body: ResponsesBody;
47
+ requestMetadata: WebSocketRequestMetadata;
48
+ signal?: AbortSignal;
49
+ connectTimeoutMs?: number;
50
+ }
51
+
52
+ export interface WebSocketRequestMetadata {
53
+ /** Legacy Pi session lookup key used by exported test helpers. */
54
+ sessionId?: string;
55
+ threadId?: string;
56
+ turnId: string;
57
+ requestKind?: "turn" | "compaction" | "prewarm";
58
+ identity?: CodexRequestIdentity;
59
+ }
60
+
61
+ export type NativeToolOwnership = (name: "web_search" | "image_generation") => boolean;
62
+
63
+ export interface OpenAIResponsesProviderController {
64
+ ownsNativeTool?: NativeToolOwnership;
65
+ getCurrentTurnId(sessionId: string | undefined): string | undefined;
66
+ getRequestIdentity?(
67
+ sessionId: string | undefined,
68
+ requestKind?: CodexRequestIdentity["requestKind"],
69
+ ): CodexRequestIdentity | undefined;
70
+ }
71
+
72
+ export interface ResponsesBody {
73
+ model: string;
74
+ store: boolean;
75
+ stream: boolean;
76
+ instructions?: string;
77
+ previous_response_id?: string;
78
+ input: unknown[];
79
+ text: { verbosity: string };
80
+ include: string[];
81
+ prompt_cache_key?: string;
82
+ tool_choice: "auto";
83
+ parallel_tool_calls: boolean;
84
+ temperature?: number;
85
+ service_tier?: string;
86
+ generate?: boolean;
87
+ tools?: unknown[];
88
+ reasoning?: {
89
+ effort?: string;
90
+ summary?: string;
91
+ context?: "all_turns";
92
+ };
93
+ client_metadata?: Record<string, string>;
94
+ [key: string]: unknown;
95
+ }
96
+
97
+ interface ResponseEnvelope {
98
+ id?: string;
99
+ status?: string;
100
+ usage?: {
101
+ input_tokens?: number;
102
+ output_tokens?: number;
103
+ total_tokens?: number;
104
+ input_tokens_details?: { cached_tokens?: number };
105
+ };
106
+ service_tier?: string;
107
+ error?: { message?: string };
108
+ [key: string]: unknown;
109
+ }
110
+
111
+ export type ServiceTier = ResponseCreateParamsStreaming["service_tier"];
112
+
113
+ export type ProviderTransport = NonNullable<SimpleStreamOptions["transport"]>;
114
+
115
+ export interface NodeWebSocketModule {
116
+ WebSocket: new (url: string, options?: Record<string, unknown>) => {
117
+ readyState: number;
118
+ bufferedAmount: number;
119
+ send(data: string, callback?: (error?: Error) => void): void;
120
+ close(code?: number, reason?: string): void;
121
+ terminate?(): void;
122
+ on(type: string, listener: (...args: any[]) => void): void;
123
+ off(type: string, listener: (...args: any[]) => void): void;
124
+ };
125
+ }
126
+
127
+ export interface StreamEventShape {
128
+ type?: string;
129
+ status?: number;
130
+ status_code?: number;
131
+ sequence_number?: number;
132
+ error?: {
133
+ type?: string;
134
+ message?: string;
135
+ code?: string;
136
+ plan_type?: string;
137
+ resets_at?: number;
138
+ [key: string]: unknown;
139
+ };
140
+ response?: ResponseEnvelope;
141
+ item_id?: string;
142
+ output_index?: number;
143
+ item?: {
144
+ id?: string;
145
+ type?: string;
146
+ result?: string | null;
147
+ output_format?: string;
148
+ revised_prompt?: string;
149
+ status?: string;
150
+ [key: string]: unknown;
151
+ };
152
+ code?: string;
153
+ message?: string;
154
+ [key: string]: unknown;
155
+ }