@bitkyc08/opencodex 2.7.40 → 2.7.41
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 +63 -12
- package/assets/claude-code-models.gif +0 -0
- package/gui/dist/assets/index-B2J4t3te.css +1 -0
- package/gui/dist/assets/index-BmvM6wRb.js +65 -0
- package/gui/dist/index.html +2 -2
- package/package.json +3 -2
- package/src/adapters/google.ts +48 -9
- package/src/adapters/kiro-events.ts +15 -3
- package/src/adapters/kiro.ts +292 -28
- package/src/adapters/openai-chat.ts +63 -15
- package/src/adapters/openai-responses.ts +18 -0
- package/src/bridge.ts +76 -21
- package/src/chat/outbound.ts +66 -34
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p.ts +121 -21
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/inbound-debug.ts +4 -0
- package/src/claude/model-info.ts +9 -3
- package/src/cli/account-extended.ts +34 -0
- package/src/cli/account.ts +3 -1
- package/src/cli/claude-desktop.ts +152 -0
- package/src/cli/claude.ts +37 -3
- package/src/cli/doctor.ts +187 -6
- package/src/cli/help.ts +13 -1
- package/src/cli/index.ts +151 -57
- package/src/cli/status-oauth.ts +68 -0
- package/src/cli/status.ts +4 -0
- package/src/codex/account-lifecycle.ts +31 -0
- package/src/codex/auth-api.ts +133 -26
- package/src/codex/auth-collision.ts +55 -11
- package/src/codex/auth-context.ts +50 -6
- package/src/codex/catalog/provider-fetch.ts +6 -2
- package/src/codex/home.ts +61 -1
- package/src/codex/inject.ts +28 -66
- package/src/codex/injected-marker.ts +72 -0
- package/src/codex/journal.ts +39 -3
- package/src/codex/main-account-cache.ts +25 -0
- package/src/codex/model-cache.ts +20 -1
- package/src/codex/paths.ts +5 -0
- package/src/codex/routing.ts +138 -11
- package/src/codex/subagent-model-fallback.ts +455 -0
- package/src/codex/sync.ts +17 -0
- package/src/combos/failover.ts +10 -2
- package/src/combos/index.ts +1 -0
- package/src/combos/types.ts +9 -0
- package/src/config.ts +117 -0
- package/src/grok/inject.ts +339 -0
- package/src/grok/status.ts +88 -0
- package/src/grok/sync.ts +66 -0
- package/src/lib/destination-policy.ts +13 -0
- package/src/lib/errors.ts +59 -0
- package/src/lib/privacy.ts +9 -0
- package/src/lib/process-control.ts +57 -4
- package/src/oauth/health.ts +375 -0
- package/src/oauth/index.ts +69 -22
- package/src/oauth/kiro.ts +5 -3
- package/src/oauth/log.ts +48 -0
- package/src/oauth/store.ts +55 -6
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +143 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/api-keys.ts +5 -5
- package/src/providers/derive.ts +22 -1
- package/src/providers/free-directory.ts +181 -0
- package/src/providers/key-failover.ts +2 -2
- package/src/providers/kiro-models.ts +3 -2
- package/src/providers/openai-tiers.ts +1 -1
- package/src/providers/provider-id-rewrite.ts +150 -0
- package/src/providers/registry.ts +49 -2
- package/src/responses/parser.ts +49 -20
- package/src/responses/state.ts +156 -2
- package/src/router.ts +73 -5
- package/src/server/chat-completions.ts +78 -22
- package/src/server/claude-messages.ts +8 -0
- package/src/server/images.ts +2 -1
- package/src/server/index.ts +50 -30
- package/src/server/live.ts +2 -1
- package/src/server/management/agent-settings-routes.ts +337 -18
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/combo-routes.ts +3 -3
- package/src/server/management/config-routes.ts +4 -4
- package/src/server/management/logs-usage-routes.ts +64 -4
- package/src/server/management/model-routes.ts +114 -8
- package/src/server/management/oauth-account-routes.ts +31 -5
- package/src/server/management/provider-routes.ts +42 -11
- package/src/server/management/shared.ts +81 -2
- package/src/server/management/system-routes.ts +6 -1
- package/src/server/management-api.ts +24 -7
- package/src/server/port-reclaim.ts +261 -0
- package/src/server/request-log.ts +11 -5
- package/src/server/responses/collaboration.ts +11 -6
- package/src/server/responses/compact.ts +2 -1
- package/src/server/responses/core.ts +358 -155
- package/src/server/responses/passthrough-error.ts +53 -0
- package/src/server/search.ts +2 -1
- package/src/server/system-env.ts +23 -6
- package/src/server/windows-tcp-drop.ts +174 -0
- package/src/service.ts +43 -3
- package/src/types.ts +74 -6
- package/src/update/index.ts +30 -19
- package/src/update/job.ts +30 -15
- package/src/usage/log.ts +158 -2
- package/src/usage/summary.ts +8 -4
- package/src/web-search/loop.ts +4 -1
- package/gui/dist/assets/index-CMip1DzF.css +0 -1
- package/gui/dist/assets/index-cydcmbzC.js +0 -52
package/gui/dist/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
} catch (e) {}
|
|
17
17
|
})();
|
|
18
18
|
</script>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-BmvM6wRb.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B2J4t3te.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitkyc08/opencodex",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.41",
|
|
4
4
|
"description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/package-main.mjs",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"gui/dist",
|
|
22
22
|
"assets/banner.png",
|
|
23
23
|
"assets/architecture.png",
|
|
24
|
+
"assets/claude-code-models.gif",
|
|
24
25
|
"assets/codex-app-picker.png",
|
|
25
26
|
"README.md",
|
|
26
27
|
"LICENSE"
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
"type": "git",
|
|
90
91
|
"url": "git+https://github.com/lidge-jun/opencodex.git"
|
|
91
92
|
},
|
|
92
|
-
"homepage": "https://
|
|
93
|
+
"homepage": "https://lidge-jun.github.io/opencodex/",
|
|
93
94
|
"bugs": {
|
|
94
95
|
"url": "https://github.com/lidge-jun/opencodex/issues"
|
|
95
96
|
},
|
package/src/adapters/google.ts
CHANGED
|
@@ -87,6 +87,35 @@ function toolResultImageParts(content: string | OcxContentPart[]): unknown[] {
|
|
|
87
87
|
return parts;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Antigravity translates these Gemini `contents` into Anthropic `messages` for Claude models, and
|
|
92
|
+
* Anthropic rejects a text block whose `text` is empty or absent. An empty Gemini text part reaches
|
|
93
|
+
* that upstream as `{"type":"text"}` — a proto3 empty string is omitted from the translated JSON —
|
|
94
|
+
* and 400s with `messages.N.content.M.text.text: Field required` (issue #420). An empty `parts: []`
|
|
95
|
+
* model turn fails the same way. Gemini itself accepts both shapes, which is why this only ever
|
|
96
|
+
* surfaced on Claude-on-Antigravity; the guard lives here because this is where the parts are
|
|
97
|
+
* built. Mirrors the Anthropic adapter's own empty-block guard (src/adapters/anthropic.ts).
|
|
98
|
+
*/
|
|
99
|
+
const GEMINI_EMPTY_PLACEHOLDER = "(empty)";
|
|
100
|
+
const GEMINI_EMPTY_TOOL_OUTPUT_PLACEHOLDER = "(empty tool output)";
|
|
101
|
+
|
|
102
|
+
/** A Gemini text part, or undefined when the value cannot form a valid non-empty text block. */
|
|
103
|
+
function geminiTextPart(text: unknown): { text: string } | undefined {
|
|
104
|
+
return typeof text === "string" && text.length > 0 ? { text } : undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Text for `functionResponse.response.result`. `contentPartsToText` collapses an empty array — or one
|
|
109
|
+
* holding only empty text — to its "[image]" marker, which would claim an image the turn does not
|
|
110
|
+
* actually carry (`toolResultImageParts` adds none). Fall back to the placeholder unless the content
|
|
111
|
+
* has something representable.
|
|
112
|
+
*/
|
|
113
|
+
function geminiToolResultText(content: string | OcxContentPart[]): string {
|
|
114
|
+
if (typeof content === "string") return content || GEMINI_EMPTY_TOOL_OUTPUT_PLACEHOLDER;
|
|
115
|
+
const hasContent = content.some(p => p.type === "image" || (typeof p.text === "string" && p.text.length > 0));
|
|
116
|
+
return hasContent ? contentPartsToText(content) : GEMINI_EMPTY_TOOL_OUTPUT_PLACEHOLDER;
|
|
117
|
+
}
|
|
118
|
+
|
|
90
119
|
function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?: unknown; contents: unknown[] } {
|
|
91
120
|
// Neutralize Codex's GPT-5 identity line (Gemini/Antigravity share this path) so a routed model
|
|
92
121
|
// never misreports as GPT-5/OpenAI, and never leaks the proxy identity upstream.
|
|
@@ -105,18 +134,22 @@ function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?:
|
|
|
105
134
|
case "user":
|
|
106
135
|
case "developer": {
|
|
107
136
|
if (typeof msg.content === "string") {
|
|
108
|
-
contents.push({ role: "user", parts: [{ text: msg.content }] });
|
|
137
|
+
contents.push({ role: "user", parts: [{ text: msg.content || GEMINI_EMPTY_PLACEHOLDER }] });
|
|
109
138
|
} else {
|
|
110
|
-
const parts =
|
|
139
|
+
const parts: unknown[] = [];
|
|
140
|
+
for (const p of msg.content as OcxContentPart[]) {
|
|
111
141
|
if (p.type === "image") {
|
|
112
142
|
const data = parseDataUrl(p.imageUrl);
|
|
113
143
|
// Gemini takes base64 via inline_data; a remote URL needs a mime type we don't have, so
|
|
114
144
|
// fall back to a short marker rather than inlining the URL as a huge text blob.
|
|
115
|
-
|
|
145
|
+
parts.push(data ? { inline_data: { mime_type: data.mediaType, data: data.base64 } } : { text: `[image: ${p.imageUrl}]` });
|
|
146
|
+
continue;
|
|
116
147
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
148
|
+
// Drop empty/malformed text instead of emitting `{ text: "" }` or a bare `{}` part.
|
|
149
|
+
const textPart = geminiTextPart(p.text);
|
|
150
|
+
if (textPart) parts.push(textPart);
|
|
151
|
+
}
|
|
152
|
+
contents.push({ role: "user", parts: parts.length > 0 ? parts : [{ text: GEMINI_EMPTY_PLACEHOLDER }] });
|
|
120
153
|
}
|
|
121
154
|
break;
|
|
122
155
|
}
|
|
@@ -124,8 +157,10 @@ function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?:
|
|
|
124
157
|
const aMsg = msg as OcxAssistantMessage;
|
|
125
158
|
const parts: unknown[] = [];
|
|
126
159
|
for (const p of aMsg.content) {
|
|
127
|
-
if (p.type === "text")
|
|
128
|
-
|
|
160
|
+
if (p.type === "text") {
|
|
161
|
+
const textPart = geminiTextPart((p as OcxTextContent).text);
|
|
162
|
+
if (textPart) parts.push(textPart);
|
|
163
|
+
} else if (p.type === "toolCall") {
|
|
129
164
|
const tc = p as OcxToolCall;
|
|
130
165
|
// Preserve the thought signature on the function-call part so Antigravity/Gemini-3
|
|
131
166
|
// reasoning continuity survives history-driven (stateless) turns, not just same-process
|
|
@@ -142,6 +177,10 @@ function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?:
|
|
|
142
177
|
parts.push(part);
|
|
143
178
|
}
|
|
144
179
|
}
|
|
180
|
+
// A turn with nothing Gemini can represent (e.g. thinking-only) would serialize as
|
|
181
|
+
// `parts: []`, which the Anthropic translation rejects. Skip it, as the Anthropic
|
|
182
|
+
// adapter does for its own empty assistant content.
|
|
183
|
+
if (parts.length === 0) break;
|
|
145
184
|
contents.push({ role: "model", parts });
|
|
146
185
|
break;
|
|
147
186
|
}
|
|
@@ -151,7 +190,7 @@ function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?:
|
|
|
151
190
|
// tool-result screenshots (e.g. Computer Use) ride along as inline_data instead of being
|
|
152
191
|
// flattened to a "[image]" marker the model can't actually see.
|
|
153
192
|
const responseId = geminiToolCallId(msg.toolCallId);
|
|
154
|
-
const functionResponse: Record<string, unknown> = { name: namespacedToolName(msg.toolNamespace, msg.toolName), response: { result:
|
|
193
|
+
const functionResponse: Record<string, unknown> = { name: namespacedToolName(msg.toolNamespace, msg.toolName), response: { result: geminiToolResultText(msg.content) } };
|
|
155
194
|
// Mirror the matching functionCall id so Claude-on-Antigravity can pair this result with its
|
|
156
195
|
// `tool_use` block (-> Anthropic `tool_result.tool_use_id`).
|
|
157
196
|
if (responseId !== undefined) functionResponse.id = responseId;
|
|
@@ -6,7 +6,7 @@ export type ParsedKiroEvent =
|
|
|
6
6
|
| { type: "reasoning"; data?: string }
|
|
7
7
|
| { type: "tool"; name?: string; toolUseId?: string; input?: string; stop?: boolean }
|
|
8
8
|
| { type: "truncation"; data: string }
|
|
9
|
-
| { type: "metadata"; usage?: OcxUsage; contextUsagePercentage?: number }
|
|
9
|
+
| { type: "metadata"; usage?: OcxUsage; contextUsagePercentage?: number; stopReason?: string }
|
|
10
10
|
| { type: "message_metadata"; conversationId?: string }
|
|
11
11
|
| { type: "invalid_state"; message?: string }
|
|
12
12
|
| { type: "error"; reason?: string; message?: string };
|
|
@@ -89,8 +89,18 @@ export function parseKiroEvent(eventType: string, payload: Uint8Array): ParsedKi
|
|
|
89
89
|
// Unknown event types are intentionally ignored without parsing or logging their payload.
|
|
90
90
|
if (!KNOWN_EVENT_TYPES.has(eventType)) return null;
|
|
91
91
|
const parsed = parseObject(eventType, payload);
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
// A metadataEvent's `stopReason` is Kiro's own terminal verdict and must reach the parser
|
|
93
|
+
// intact. The generic truncation sniffer matches substrings ("max_tokens", "length",
|
|
94
|
+
// "context_length") across several keys, so it would swallow MAX_TOKENS before the switch
|
|
95
|
+
// below ever runs. Gate on position rather than on the value: a value allowlist would keep
|
|
96
|
+
// eating future reasons such as LENGTH_LIMIT, which matches the pattern today.
|
|
97
|
+
const nativeStopReason = eventType === "metadataEvent"
|
|
98
|
+
? optionalString(eventType, parsed, "stopReason")
|
|
99
|
+
: undefined;
|
|
100
|
+
if (nativeStopReason === undefined) {
|
|
101
|
+
const truncationReason = kiroTruncationReason(parsed);
|
|
102
|
+
if (truncationReason) return { type: "truncation", data: truncationReason };
|
|
103
|
+
}
|
|
94
104
|
|
|
95
105
|
switch (eventType) {
|
|
96
106
|
case "assistantResponseEvent":
|
|
@@ -141,12 +151,14 @@ export function parseKiroEvent(eventType: string, payload: Uint8Array): ParsedKi
|
|
|
141
151
|
) {
|
|
142
152
|
return malformed(eventType, "contextUsagePercentage must be a finite number");
|
|
143
153
|
}
|
|
154
|
+
const stopReason = optionalString(eventType, parsed, "stopReason");
|
|
144
155
|
return {
|
|
145
156
|
type: "metadata",
|
|
146
157
|
...(parseTokenUsage(eventType, parsed.tokenUsage) !== undefined
|
|
147
158
|
? { usage: parseTokenUsage(eventType, parsed.tokenUsage) }
|
|
148
159
|
: {}),
|
|
149
160
|
...(typeof contextUsagePercentage === "number" ? { contextUsagePercentage } : {}),
|
|
161
|
+
...(stopReason !== undefined ? { stopReason } : {}),
|
|
150
162
|
};
|
|
151
163
|
}
|
|
152
164
|
case "invalidStateEvent":
|