@bitkyc08/opencodex 2.7.35 → 2.7.36
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.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +4 -2
- package/README.ru.md +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/ocx.mjs +52 -0
- package/gui/dist/assets/index-BpX-hoSd.css +1 -0
- package/gui/dist/assets/index-ZmFopEYw.js +52 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/cursor/cursor-errors.ts +38 -1
- package/src/adapters/cursor/discovery.ts +1 -0
- package/src/adapters/cursor/effort-map.ts +1 -0
- package/src/adapters/cursor/live-models.ts +22 -5
- package/src/adapters/cursor/live-transport.ts +82 -7
- package/src/adapters/cursor/transport.ts +2 -0
- package/src/adapters/cursor.ts +5 -2
- package/src/adapters/openai-responses.ts +64 -1
- package/src/cli/doctor.ts +10 -0
- package/src/cli/help.ts +10 -0
- package/src/cli/index.ts +88 -9
- package/src/cli/internal-dispatch.ts +20 -0
- package/src/cli/status.ts +15 -4
- package/src/cli/tray-proxy.ts +52 -0
- package/src/codex/auth-api.ts +46 -5
- package/src/codex/autostart-health.ts +149 -0
- package/src/codex/catalog/aggregation.ts +268 -0
- package/src/codex/catalog/bundled.ts +188 -0
- package/src/codex/catalog/effort.ts +263 -0
- package/src/codex/catalog/metadata.ts +176 -0
- package/src/codex/catalog/parsing.ts +399 -0
- package/src/codex/catalog/provider-fetch.ts +609 -0
- package/src/codex/catalog/sync.ts +540 -0
- package/src/codex/catalog.ts +11 -2426
- package/src/codex/inject.ts +165 -3
- package/src/codex/shim.ts +141 -8
- package/src/codex/sync.ts +17 -2
- package/src/config.ts +23 -0
- package/src/lib/errors.ts +11 -0
- package/src/providers/antigravity-models.ts +33 -0
- package/src/providers/kiro-models.ts +2 -0
- package/src/providers/registry.ts +2 -2
- package/src/responses/state.ts +69 -6
- package/src/server/auth-cors.ts +3 -0
- package/src/server/management/agent-settings-routes.ts +536 -0
- package/src/server/management/combo-routes.ts +210 -0
- package/src/server/management/config-routes.ts +302 -0
- package/src/server/management/context.ts +21 -0
- package/src/server/management/logs-usage-routes.ts +176 -0
- package/src/server/management/model-routes.ts +253 -0
- package/src/server/management/oauth-account-routes.ts +301 -0
- package/src/server/management/provider-routes.ts +408 -0
- package/src/server/management/shared.ts +186 -0
- package/src/server/management-api.ts +23 -1806
- package/src/server/responses/collaboration.ts +300 -0
- package/src/server/responses/compact.ts +342 -0
- package/src/server/responses/core.ts +1498 -0
- package/src/server/responses/encrypted-payload.ts +231 -0
- package/src/server/responses/fetch-helpers.ts +157 -0
- package/src/server/responses.ts +9 -2172
- package/src/server/startup-action-control.ts +41 -0
- package/src/server/startup-health-cache.ts +100 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/service.ts +171 -19
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +290 -0
- package/src/tray/windows.ts +628 -0
- package/src/types.ts +5 -0
- package/src/update/index.ts +43 -0
- package/src/update/job.ts +46 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +9 -2
- package/src/usage/summary.ts +42 -7
- package/gui/dist/assets/index-BunUANVE.js +0 -52
- package/gui/dist/assets/index-Sg-7L_oZ.css +0 -1
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import type { Server } from "bun";
|
|
2
|
+
import { bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type ResponsesTerminalStatus } from "../../bridge";
|
|
3
|
+
import {
|
|
4
|
+
getConfigPath,
|
|
5
|
+
multiAgentGuidanceEnabled,
|
|
6
|
+
resolveEnvValue,
|
|
7
|
+
} from "../../config";
|
|
8
|
+
import { parseRequest } from "../../responses/parser";
|
|
9
|
+
import { buildCompactV1Output, COMPACT_PROMPT, decodeCompactionSummary, extractCompactUserMessages } from "../../responses/compaction";
|
|
10
|
+
import { FORWARD_HEADERS, sanitizeReasoningInputContent } from "../../adapters/openai-responses";
|
|
11
|
+
import { expandPreviousResponseInput, previousResponseProviderState, rememberResponseState } from "../../responses/state";
|
|
12
|
+
import { routeModel } from "../../router";
|
|
13
|
+
import {
|
|
14
|
+
advanceComboAfterFailure,
|
|
15
|
+
comboDefaultEffort,
|
|
16
|
+
comboFailureDecision,
|
|
17
|
+
comboIdFromRawBody,
|
|
18
|
+
concreteComboRequestBody,
|
|
19
|
+
getCombo,
|
|
20
|
+
isComboTargetInCooldown,
|
|
21
|
+
NoAvailableComboTargetsError,
|
|
22
|
+
noteComboSuccess,
|
|
23
|
+
parseRetryAfterMs,
|
|
24
|
+
pickComboTarget,
|
|
25
|
+
targetKey,
|
|
26
|
+
} from "../../combos";
|
|
27
|
+
import { isInjectionDebugEnabled } from "../../lib/debug-settings";
|
|
28
|
+
import { injectionDebugLog } from "../../lib/injection-debug-log";
|
|
29
|
+
import { modelInList, namespacedToolName } from "../../types";
|
|
30
|
+
import type { AdapterEvent, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
|
|
31
|
+
import {
|
|
32
|
+
forceRefreshOAuthAccessSnapshot,
|
|
33
|
+
getOAuthCredentialApiBaseUrl,
|
|
34
|
+
getOAuthCredentialProjectId,
|
|
35
|
+
getValidAccessTokenSnapshot,
|
|
36
|
+
type OAuthAccessSnapshot,
|
|
37
|
+
UnsupportedOAuthProviderError,
|
|
38
|
+
} from "../../oauth";
|
|
39
|
+
import { buildWebSearchTool, planWebSearch, runWithWebSearch, shouldResolveOpenAiWebSearchSidecar } from "../../web-search";
|
|
40
|
+
import { describeImagesInPlace, planVisionSidecar, shouldResolveOpenAiVisionSidecar, stripImagesInPlace } from "../../vision";
|
|
41
|
+
import { createAdapterEventQueue, preflightAdapterEvents } from "../../adapters/run-turn-queue";
|
|
42
|
+
import {
|
|
43
|
+
applyCodexAuthContextToProvider,
|
|
44
|
+
CodexAccountCooldownError,
|
|
45
|
+
CodexAuthContextError,
|
|
46
|
+
CodexDirectAuthenticationError,
|
|
47
|
+
CodexPoolAuthenticationError,
|
|
48
|
+
CodexThreadAffinityExpiredError,
|
|
49
|
+
headersForCodexAuthContext,
|
|
50
|
+
isCodexAuthContextUsable,
|
|
51
|
+
resolveCodexAuthContext,
|
|
52
|
+
type CodexAuthContext,
|
|
53
|
+
} from "../../codex/auth-context";
|
|
54
|
+
import {
|
|
55
|
+
formatCodexProviderForLog,
|
|
56
|
+
recordCodexUpstreamOutcome,
|
|
57
|
+
type CodexUpstreamOutcome,
|
|
58
|
+
} from "../../codex/routing";
|
|
59
|
+
import { fetchWithResetRetry, fetchWithTransientRetry, applyUpstreamRecoveryInit } from "../../lib/upstream-retry";
|
|
60
|
+
import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../auth-cors";
|
|
61
|
+
import { listOpenAiForwardSidecarCandidates, resolveFirstUsableOpenAiSidecar, type ResolvedOpenAiForwardSidecar } from "../../providers/openai-sidecar";
|
|
62
|
+
import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
|
|
63
|
+
import { slugsEquivalent } from "../../providers/slug-codec";
|
|
64
|
+
import { applyOpenAiVirtualModel, resolveOpenAiCompactModel } from "../../providers/openai-virtual-models";
|
|
65
|
+
import { isUsageDebugEnabled } from "../../usage/debug";
|
|
66
|
+
import { readJsonRequestBody, DecompressedBodyTooLargeError, UnsupportedContentEncodingError } from "../request-decompress";
|
|
67
|
+
import { resolveAdapter, resolveWireProtocolOverride } from "../adapter-resolve";
|
|
68
|
+
import { hasKeyPoolFailover, rotateProviderTransportOn429 } from "../../providers/key-failover";
|
|
69
|
+
import { shouldAttemptImageTierRetry } from "../image-retry";
|
|
70
|
+
import { resolveProviderTransport } from "../../providers/xai-transport";
|
|
71
|
+
import type { WsData } from "../ws-bridge";
|
|
72
|
+
import { registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
|
|
73
|
+
import { redactSecretString } from "../../lib/redact";
|
|
74
|
+
import { readBoundedResponseBody } from "../../lib/bounded-body";
|
|
75
|
+
import { supportedLadderFor } from "../effort-policy";
|
|
76
|
+
import {
|
|
77
|
+
beginRequestAttempt,
|
|
78
|
+
catalogModelSupportsServiceTier,
|
|
79
|
+
finishRequestAttempt,
|
|
80
|
+
inspectResponseLogJson,
|
|
81
|
+
noteAttemptSend,
|
|
82
|
+
readConfiguredCodexServiceTier,
|
|
83
|
+
requestLogSpeedLabel,
|
|
84
|
+
sealRequestAttemptIdentity,
|
|
85
|
+
usageFromResponsesPayload,
|
|
86
|
+
type RequestLogContext,
|
|
87
|
+
} from "../request-log";
|
|
88
|
+
import type { AttemptRecoveryKind } from "../../usage/log";
|
|
89
|
+
import {
|
|
90
|
+
consumeForInspection,
|
|
91
|
+
consumeForResponseLogMetadata,
|
|
92
|
+
markNativePassthroughSseResponse,
|
|
93
|
+
relaySseWithFailedTail,
|
|
94
|
+
relayWithAbort,
|
|
95
|
+
sanitizePassthroughHeaders,
|
|
96
|
+
} from "../relay";
|
|
97
|
+
import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
|
|
98
|
+
import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
export function looksLikeBackendCiphertext(payload: string): boolean {
|
|
102
|
+
return payload.length >= 64 && /^[A-Za-z0-9+/=_-]+$/.test(payload);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
export const FERNET_TOKEN_RUN = /gAAAA[A-Za-z0-9_-]{60,}={0,2}/g;
|
|
108
|
+
|
|
109
|
+
export const AGENT_MESSAGE_ROUTING_ENVELOPE = /(?:^|\n)Message Type\s*:\s*NEW_TASK[^\n]*\nTask name\s*:[^\n]*\nSender\s*:[^\n]*\nPayload\s*:\s*(?:\n|$)/gi;
|
|
110
|
+
|
|
111
|
+
export const AGENT_MESSAGE_CONTROL_PREAMBLE = /(?:^|\n)\[CXC-(?:LEAF-GUARD|SKILL-AFFORDANCE)\][\s\S]*?(?=\n{2,}|$)/g;
|
|
112
|
+
|
|
113
|
+
export function hasUnreadableEncryptedAgentTask(input: unknown): boolean {
|
|
114
|
+
if (!Array.isArray(input)) return false;
|
|
115
|
+
|
|
116
|
+
return input.some(item => {
|
|
117
|
+
if (!item || typeof item !== "object" || (item as { type?: unknown }).type !== "agent_message") {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const content = (item as { content?: unknown }).content;
|
|
122
|
+
if (!Array.isArray(content)) return false;
|
|
123
|
+
|
|
124
|
+
let hasFernetTask = false;
|
|
125
|
+
const readableParts: string[] = [];
|
|
126
|
+
for (const part of content) {
|
|
127
|
+
if (!part || typeof part !== "object") continue;
|
|
128
|
+
const record = part as { type?: unknown; text?: unknown; encrypted_content?: unknown };
|
|
129
|
+
if (
|
|
130
|
+
(record.type === "input_text" || record.type === "text" || record.type === "output_text")
|
|
131
|
+
&& typeof record.text === "string"
|
|
132
|
+
) {
|
|
133
|
+
readableParts.push(record.text);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (record.type !== "encrypted_content" || typeof record.encrypted_content !== "string") {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const withoutFernet = record.encrypted_content.replace(FERNET_TOKEN_RUN, "\n\n");
|
|
141
|
+
if (withoutFernet !== record.encrypted_content) hasFernetTask = true;
|
|
142
|
+
readableParts.push(withoutFernet);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!hasFernetTask) return false;
|
|
146
|
+
const readableTask = readableParts
|
|
147
|
+
.join("\n\n")
|
|
148
|
+
.replace(AGENT_MESSAGE_ROUTING_ENVELOPE, "\n")
|
|
149
|
+
.replace(AGENT_MESSAGE_CONTROL_PREAMBLE, "\n")
|
|
150
|
+
.trim();
|
|
151
|
+
return readableTask.length === 0;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
export function encryptedSlotParts(payload: string): Array<Record<string, string>> {
|
|
158
|
+
const parts: Array<Record<string, string>> = [];
|
|
159
|
+
let last = 0;
|
|
160
|
+
for (const match of payload.matchAll(FERNET_TOKEN_RUN)) {
|
|
161
|
+
const index = match.index ?? 0;
|
|
162
|
+
const before = payload.slice(last, index);
|
|
163
|
+
if (before.trim().length > 0) parts.push({ type: "input_text", text: before });
|
|
164
|
+
parts.push({ type: "encrypted_content", encrypted_content: match[0] });
|
|
165
|
+
last = index + match[0].length;
|
|
166
|
+
}
|
|
167
|
+
const rest = payload.slice(last);
|
|
168
|
+
if (rest.trim().length > 0) parts.push({ type: "input_text", text: rest });
|
|
169
|
+
return parts.length > 0 ? parts : [{ type: "input_text", text: payload }];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
export function hasEncryptedContentPart(content: unknown): boolean {
|
|
175
|
+
return Array.isArray(content) && content.some(part => (
|
|
176
|
+
part && typeof part === "object"
|
|
177
|
+
&& (part as { type?: unknown }).type === "encrypted_content"
|
|
178
|
+
));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
export function sanitizeEncryptedContentInPlace(input: unknown): number {
|
|
184
|
+
if (!Array.isArray(input)) return 0;
|
|
185
|
+
let rewritten = 0;
|
|
186
|
+
const visit = (node: unknown): number => {
|
|
187
|
+
const before = rewritten;
|
|
188
|
+
if (Array.isArray(node)) {
|
|
189
|
+
for (let i = 0; i < node.length; i += 1) {
|
|
190
|
+
const child = node[i] as unknown;
|
|
191
|
+
if (
|
|
192
|
+
child && typeof child === "object"
|
|
193
|
+
&& (child as { type?: unknown }).type === "encrypted_content"
|
|
194
|
+
&& typeof (child as { encrypted_content?: unknown }).encrypted_content === "string"
|
|
195
|
+
) {
|
|
196
|
+
const payload = (child as { encrypted_content: string }).encrypted_content;
|
|
197
|
+
if (!looksLikeBackendCiphertext(payload)) {
|
|
198
|
+
const parts = encryptedSlotParts(payload);
|
|
199
|
+
node.splice(i, 1, ...parts);
|
|
200
|
+
i += parts.length - 1;
|
|
201
|
+
rewritten += 1;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const childRewrites = visit(child);
|
|
206
|
+
if (
|
|
207
|
+
childRewrites > 0
|
|
208
|
+
&& child && typeof child === "object"
|
|
209
|
+
&& (child as { type?: unknown }).type === "agent_message"
|
|
210
|
+
&& !hasEncryptedContentPart((child as { content?: unknown }).content)
|
|
211
|
+
) {
|
|
212
|
+
const message = child as { type: string; role?: string; id?: unknown; author?: unknown; recipient?: unknown };
|
|
213
|
+
message.type = "message";
|
|
214
|
+
message.role = "user";
|
|
215
|
+
delete message.id;
|
|
216
|
+
delete message.author;
|
|
217
|
+
delete message.recipient;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return rewritten - before;
|
|
221
|
+
}
|
|
222
|
+
if (node && typeof node === "object") {
|
|
223
|
+
for (const value of Object.values(node)) visit(value);
|
|
224
|
+
}
|
|
225
|
+
return rewritten - before;
|
|
226
|
+
};
|
|
227
|
+
visit(input);
|
|
228
|
+
return rewritten;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { Server } from "bun";
|
|
2
|
+
import { bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type ResponsesTerminalStatus } from "../../bridge";
|
|
3
|
+
import {
|
|
4
|
+
getConfigPath,
|
|
5
|
+
multiAgentGuidanceEnabled,
|
|
6
|
+
resolveEnvValue,
|
|
7
|
+
} from "../../config";
|
|
8
|
+
import { parseRequest } from "../../responses/parser";
|
|
9
|
+
import { buildCompactV1Output, COMPACT_PROMPT, decodeCompactionSummary, extractCompactUserMessages } from "../../responses/compaction";
|
|
10
|
+
import { FORWARD_HEADERS, sanitizeReasoningInputContent } from "../../adapters/openai-responses";
|
|
11
|
+
import { expandPreviousResponseInput, previousResponseProviderState, rememberResponseState } from "../../responses/state";
|
|
12
|
+
import { routeModel } from "../../router";
|
|
13
|
+
import {
|
|
14
|
+
advanceComboAfterFailure,
|
|
15
|
+
comboDefaultEffort,
|
|
16
|
+
comboFailureDecision,
|
|
17
|
+
comboIdFromRawBody,
|
|
18
|
+
concreteComboRequestBody,
|
|
19
|
+
getCombo,
|
|
20
|
+
isComboTargetInCooldown,
|
|
21
|
+
NoAvailableComboTargetsError,
|
|
22
|
+
noteComboSuccess,
|
|
23
|
+
parseRetryAfterMs,
|
|
24
|
+
pickComboTarget,
|
|
25
|
+
targetKey,
|
|
26
|
+
} from "../../combos";
|
|
27
|
+
import { isInjectionDebugEnabled } from "../../lib/debug-settings";
|
|
28
|
+
import { injectionDebugLog } from "../../lib/injection-debug-log";
|
|
29
|
+
import { modelInList, namespacedToolName } from "../../types";
|
|
30
|
+
import type { AdapterEvent, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
|
|
31
|
+
import {
|
|
32
|
+
forceRefreshOAuthAccessSnapshot,
|
|
33
|
+
getOAuthCredentialApiBaseUrl,
|
|
34
|
+
getOAuthCredentialProjectId,
|
|
35
|
+
getValidAccessTokenSnapshot,
|
|
36
|
+
type OAuthAccessSnapshot,
|
|
37
|
+
UnsupportedOAuthProviderError,
|
|
38
|
+
} from "../../oauth";
|
|
39
|
+
import { buildWebSearchTool, planWebSearch, runWithWebSearch, shouldResolveOpenAiWebSearchSidecar } from "../../web-search";
|
|
40
|
+
import { describeImagesInPlace, planVisionSidecar, shouldResolveOpenAiVisionSidecar, stripImagesInPlace } from "../../vision";
|
|
41
|
+
import { createAdapterEventQueue, preflightAdapterEvents } from "../../adapters/run-turn-queue";
|
|
42
|
+
import {
|
|
43
|
+
applyCodexAuthContextToProvider,
|
|
44
|
+
CodexAccountCooldownError,
|
|
45
|
+
CodexAuthContextError,
|
|
46
|
+
CodexDirectAuthenticationError,
|
|
47
|
+
CodexPoolAuthenticationError,
|
|
48
|
+
CodexThreadAffinityExpiredError,
|
|
49
|
+
headersForCodexAuthContext,
|
|
50
|
+
isCodexAuthContextUsable,
|
|
51
|
+
resolveCodexAuthContext,
|
|
52
|
+
type CodexAuthContext,
|
|
53
|
+
} from "../../codex/auth-context";
|
|
54
|
+
import {
|
|
55
|
+
formatCodexProviderForLog,
|
|
56
|
+
recordCodexUpstreamOutcome,
|
|
57
|
+
type CodexUpstreamOutcome,
|
|
58
|
+
} from "../../codex/routing";
|
|
59
|
+
import { fetchWithResetRetry, fetchWithTransientRetry, applyUpstreamRecoveryInit } from "../../lib/upstream-retry";
|
|
60
|
+
import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../auth-cors";
|
|
61
|
+
import { listOpenAiForwardSidecarCandidates, resolveFirstUsableOpenAiSidecar, type ResolvedOpenAiForwardSidecar } from "../../providers/openai-sidecar";
|
|
62
|
+
import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
|
|
63
|
+
import { slugsEquivalent } from "../../providers/slug-codec";
|
|
64
|
+
import { applyOpenAiVirtualModel, resolveOpenAiCompactModel } from "../../providers/openai-virtual-models";
|
|
65
|
+
import { isUsageDebugEnabled } from "../../usage/debug";
|
|
66
|
+
import { readJsonRequestBody, DecompressedBodyTooLargeError, UnsupportedContentEncodingError } from "../request-decompress";
|
|
67
|
+
import { resolveAdapter, resolveWireProtocolOverride } from "../adapter-resolve";
|
|
68
|
+
import { hasKeyPoolFailover, rotateProviderTransportOn429 } from "../../providers/key-failover";
|
|
69
|
+
import { shouldAttemptImageTierRetry } from "../image-retry";
|
|
70
|
+
import { resolveProviderTransport } from "../../providers/xai-transport";
|
|
71
|
+
import type { WsData } from "../ws-bridge";
|
|
72
|
+
import { registerTurn, trackStreamLifetime, unregisterTurn } from "../lifecycle";
|
|
73
|
+
import { redactSecretString } from "../../lib/redact";
|
|
74
|
+
import { readBoundedResponseBody } from "../../lib/bounded-body";
|
|
75
|
+
import { supportedLadderFor } from "../effort-policy";
|
|
76
|
+
import {
|
|
77
|
+
beginRequestAttempt,
|
|
78
|
+
catalogModelSupportsServiceTier,
|
|
79
|
+
finishRequestAttempt,
|
|
80
|
+
inspectResponseLogJson,
|
|
81
|
+
noteAttemptSend,
|
|
82
|
+
readConfiguredCodexServiceTier,
|
|
83
|
+
requestLogSpeedLabel,
|
|
84
|
+
sealRequestAttemptIdentity,
|
|
85
|
+
usageFromResponsesPayload,
|
|
86
|
+
type RequestLogContext,
|
|
87
|
+
} from "../request-log";
|
|
88
|
+
import type { AttemptRecoveryKind } from "../../usage/log";
|
|
89
|
+
import {
|
|
90
|
+
consumeForInspection,
|
|
91
|
+
consumeForResponseLogMetadata,
|
|
92
|
+
markNativePassthroughSseResponse,
|
|
93
|
+
relaySseWithFailedTail,
|
|
94
|
+
relayWithAbort,
|
|
95
|
+
sanitizePassthroughHeaders,
|
|
96
|
+
} from "../relay";
|
|
97
|
+
import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
|
|
98
|
+
import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
export function disableResponsesRequestTimeout(req: Request, server: Pick<Server<WsData>, "timeout"> | undefined): boolean {
|
|
102
|
+
if (!server) return false;
|
|
103
|
+
try {
|
|
104
|
+
server.timeout(req, 0);
|
|
105
|
+
return true;
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
export function safeHostLabel(url: string): string {
|
|
114
|
+
try {
|
|
115
|
+
return new URL(url).host;
|
|
116
|
+
} catch {
|
|
117
|
+
return "upstream";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
export function providerFetch(provider: OcxProviderConfig): typeof globalThis.fetch {
|
|
124
|
+
return (provider as OcxProviderConfig & { fetch?: typeof globalThis.fetch }).fetch ?? globalThis.fetch;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
export async function fetchWithHeaderTimeout(
|
|
130
|
+
url: string,
|
|
131
|
+
init: Omit<RequestInit, "signal">,
|
|
132
|
+
abortSignal: AbortSignal,
|
|
133
|
+
timeoutMs: number,
|
|
134
|
+
preferIdentityEncoding = false,
|
|
135
|
+
executor: typeof globalThis.fetch = globalThis.fetch,
|
|
136
|
+
): Promise<Response> {
|
|
137
|
+
const timeout = new AbortController();
|
|
138
|
+
const timer = setTimeout(() => {
|
|
139
|
+
if (!timeout.signal.aborted) timeout.abort(new DOMException("Timeout elapsed", "TimeoutError"));
|
|
140
|
+
}, timeoutMs);
|
|
141
|
+
const headers = new Headers(init.headers);
|
|
142
|
+
// Compressed SSE can be held until the decompressor has a complete block. Streaming calls
|
|
143
|
+
// default to identity for low-latency frame delivery, while an explicit caller choice wins.
|
|
144
|
+
if (preferIdentityEncoding && !headers.has("accept-encoding")) {
|
|
145
|
+
headers.set("accept-encoding", "identity");
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
return await executor(url, {
|
|
149
|
+
...init,
|
|
150
|
+
headers,
|
|
151
|
+
signal: AbortSignal.any([abortSignal, timeout.signal]),
|
|
152
|
+
});
|
|
153
|
+
} finally {
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|