vibe-coding-master 0.7.44 → 0.7.45
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 +24 -26
- package/dist/backend/adapters/claude-adapter.js +2 -2
- package/dist/backend/adapters/codex-bridge-adapter.js +213 -0
- package/dist/backend/api/app-settings-routes.js +6 -6
- package/dist/backend/server.js +8 -8
- package/dist/backend/services/app-settings-service.js +11 -11
- package/dist/backend/services/{ccr-integration-service.js → codex-bridge-integration-service.js} +71 -71
- package/dist/backend/services/session-service.js +16 -16
- package/dist/backend/services/usage-analytics-service.js +3 -3
- package/dist/shared/types/session.js +28 -22
- package/dist-frontend/assets/index-DDmygnV6.css +32 -0
- package/dist-frontend/assets/{index-BvCmrFlN.js → index-nAV6toi8.js} +24 -24
- package/dist-frontend/index.html +2 -2
- package/package.json +1 -1
- package/scripts/{ccr-api-key-helper.mjs → codex-bridge-api-key-helper.mjs} +1 -1
- package/dist/backend/adapters/ccr-gateway-adapter.js +0 -172
- package/dist-frontend/assets/index-B0d4Z6ny.css +0 -32
package/dist/backend/services/{ccr-integration-service.js → codex-bridge-integration-service.js}
RENAMED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { CCR_GATEWAY_BASE_URL, CCR_GPT_AUTO_COMPACT_PERCENT, CCR_GPT_AUTO_COMPACT_WINDOW_TOKENS, CCR_GPT_EFFECTIVE_CONTEXT_TOKENS, CCR_GPT_MODEL_ID, createSessionModelOptions, isCcrSessionModel } from "../../shared/types/session.js";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { CODEX_BRIDGE_AUTO_COMPACT_PERCENT, CODEX_BRIDGE_AUTO_COMPACT_WINDOW_TOKENS, CODEX_BRIDGE_BASE_URL, CODEX_BRIDGE_EFFECTIVE_CONTEXT_TOKENS, createSessionModelOptions, getCodexBridgeModelId, isCodexBridgeSessionModel } from "../../shared/types/session.js";
|
|
4
4
|
import { VcmError } from "../errors.js";
|
|
5
5
|
import { resolveVcmDataDir } from "../vcm-data-dir.js";
|
|
6
6
|
const DEFAULT_CACHE_TTL_MS = 10_000;
|
|
7
|
-
const DEFAULT_API_KEY_HELPER_PATH = fileURLToPath(new URL("../../../scripts/
|
|
8
|
-
export function
|
|
7
|
+
const DEFAULT_API_KEY_HELPER_PATH = fileURLToPath(new URL("../../../scripts/codex-bridge-api-key-helper.mjs", import.meta.url));
|
|
8
|
+
export function createCodexBridgeIntegrationService(deps) {
|
|
9
9
|
const now = deps.now ?? (() => new Date());
|
|
10
10
|
const cacheTtlMs = deps.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
|
|
11
11
|
const baseEnv = deps.baseEnv ?? process.env;
|
|
12
|
-
const configDir = deps.configDir ?? path.join(resolveVcmDataDir(baseEnv), "claude", "
|
|
12
|
+
const configDir = deps.configDir ?? path.join(resolveVcmDataDir(baseEnv), "claude", "codex-bridge");
|
|
13
13
|
let cachedProbe;
|
|
14
14
|
let inFlight;
|
|
15
15
|
async function probe(force = false) {
|
|
16
|
-
const settings = await deps.settings.
|
|
16
|
+
const settings = await deps.settings.getCodexBridgeIntegrationSettings();
|
|
17
17
|
if (!settings.apiKey) {
|
|
18
18
|
throw missingApiKeyError();
|
|
19
19
|
}
|
|
@@ -24,7 +24,7 @@ export function createCcrIntegrationService(deps) {
|
|
|
24
24
|
if (inFlight) {
|
|
25
25
|
return inFlight;
|
|
26
26
|
}
|
|
27
|
-
inFlight = deps.
|
|
27
|
+
inFlight = deps.bridge.probe(settings.apiKey).then((result) => {
|
|
28
28
|
const checkedAtDate = now();
|
|
29
29
|
cachedProbe = {
|
|
30
30
|
result,
|
|
@@ -38,14 +38,15 @@ export function createCcrIntegrationService(deps) {
|
|
|
38
38
|
return inFlight;
|
|
39
39
|
}
|
|
40
40
|
async function buildStatus(options = {}) {
|
|
41
|
-
const settings = await deps.settings.
|
|
41
|
+
const settings = await deps.settings.getCodexBridgeIntegrationSettings();
|
|
42
42
|
if (!settings.enabled) {
|
|
43
43
|
return createStatus({
|
|
44
44
|
enabled: false,
|
|
45
45
|
apiKeyConfigured: Boolean(settings.apiKey),
|
|
46
46
|
connectionState: "disabled",
|
|
47
47
|
modelAvailable: false,
|
|
48
|
-
|
|
48
|
+
models: [],
|
|
49
|
+
error: settings.apiKey ? undefined : "Save a Codex Bridge API key before enabling Codex models."
|
|
49
50
|
});
|
|
50
51
|
}
|
|
51
52
|
if (!cachedProbe && options.refreshIfMissing) {
|
|
@@ -56,7 +57,8 @@ export function createCcrIntegrationService(deps) {
|
|
|
56
57
|
enabled: true,
|
|
57
58
|
apiKeyConfigured: true,
|
|
58
59
|
connectionState: "checking",
|
|
59
|
-
modelAvailable: false
|
|
60
|
+
modelAvailable: false,
|
|
61
|
+
models: []
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
return createStatus({
|
|
@@ -64,13 +66,14 @@ export function createCcrIntegrationService(deps) {
|
|
|
64
66
|
apiKeyConfigured: true,
|
|
65
67
|
connectionState: cachedProbe.result.connectionState,
|
|
66
68
|
modelAvailable: cachedProbe.result.modelAvailable,
|
|
69
|
+
models: cachedProbe.result.models,
|
|
67
70
|
checkedAt: cachedProbe.checkedAt,
|
|
68
71
|
error: cachedProbe.result.error
|
|
69
72
|
});
|
|
70
73
|
}
|
|
71
74
|
return {
|
|
72
75
|
async initialize() {
|
|
73
|
-
const settings = await deps.settings.
|
|
76
|
+
const settings = await deps.settings.getCodexBridgeIntegrationSettings();
|
|
74
77
|
if (settings.enabled) {
|
|
75
78
|
await probe(true);
|
|
76
79
|
}
|
|
@@ -80,15 +83,15 @@ export function createCcrIntegrationService(deps) {
|
|
|
80
83
|
},
|
|
81
84
|
async updateSettings(input) {
|
|
82
85
|
if (input.apiKey !== undefined && typeof input.apiKey !== "string") {
|
|
83
|
-
throw invalidSettingsError("
|
|
86
|
+
throw invalidSettingsError("Codex Bridge API key must be a string.");
|
|
84
87
|
}
|
|
85
88
|
if (input.enabled !== undefined && typeof input.enabled !== "boolean") {
|
|
86
|
-
throw invalidSettingsError("
|
|
89
|
+
throw invalidSettingsError("Codex Bridge enabled state must be a boolean.");
|
|
87
90
|
}
|
|
88
91
|
if (input.clearApiKey !== undefined && typeof input.clearApiKey !== "boolean") {
|
|
89
|
-
throw invalidSettingsError("
|
|
92
|
+
throw invalidSettingsError("Codex Bridge clear-key state must be a boolean.");
|
|
90
93
|
}
|
|
91
|
-
const current = await deps.settings.
|
|
94
|
+
const current = await deps.settings.getCodexBridgeIntegrationSettings();
|
|
92
95
|
const clearApiKey = input.clearApiKey === true;
|
|
93
96
|
const nextApiKey = clearApiKey
|
|
94
97
|
? ""
|
|
@@ -99,7 +102,7 @@ export function createCcrIntegrationService(deps) {
|
|
|
99
102
|
if (nextEnabled && !nextApiKey) {
|
|
100
103
|
throw missingApiKeyError();
|
|
101
104
|
}
|
|
102
|
-
await deps.settings.
|
|
105
|
+
await deps.settings.updateCodexBridgeIntegrationSettings({
|
|
103
106
|
enabled: nextEnabled,
|
|
104
107
|
apiKey: nextApiKey
|
|
105
108
|
});
|
|
@@ -114,64 +117,65 @@ export function createCcrIntegrationService(deps) {
|
|
|
114
117
|
return buildStatus();
|
|
115
118
|
},
|
|
116
119
|
async checkConnection() {
|
|
117
|
-
const settings = await deps.settings.
|
|
120
|
+
const settings = await deps.settings.getCodexBridgeIntegrationSettings();
|
|
118
121
|
if (!settings.enabled) {
|
|
119
122
|
throw new VcmError({
|
|
120
|
-
code: "
|
|
121
|
-
message: "
|
|
123
|
+
code: "CODEX_BRIDGE_DISABLED",
|
|
124
|
+
message: "Codex Bridge models are disabled.",
|
|
122
125
|
statusCode: 409,
|
|
123
|
-
hint: "Save the
|
|
126
|
+
hint: "Save the Codex Bridge API key and enable Codex models before checking the connection."
|
|
124
127
|
});
|
|
125
128
|
}
|
|
126
129
|
await probe(true);
|
|
127
130
|
return buildStatus();
|
|
128
131
|
},
|
|
129
132
|
async getLaunchEnvironment(model) {
|
|
130
|
-
if (!
|
|
133
|
+
if (!isCodexBridgeSessionModel(model)) {
|
|
131
134
|
return buildNativeLaunchEnvironment(baseEnv);
|
|
132
135
|
}
|
|
133
|
-
const settings = await deps.settings.
|
|
136
|
+
const settings = await deps.settings.getCodexBridgeIntegrationSettings();
|
|
134
137
|
if (!settings.enabled) {
|
|
135
138
|
throw new VcmError({
|
|
136
|
-
code: "
|
|
137
|
-
message: "
|
|
139
|
+
code: "CODEX_BRIDGE_DISABLED",
|
|
140
|
+
message: "Codex Bridge models are disabled.",
|
|
138
141
|
statusCode: 409,
|
|
139
|
-
hint: "Enable
|
|
142
|
+
hint: "Enable Codex Bridge in VCM Settings before starting this session."
|
|
140
143
|
});
|
|
141
144
|
}
|
|
142
145
|
const checked = await probe();
|
|
143
|
-
|
|
146
|
+
const modelId = getCodexBridgeModelId(model);
|
|
147
|
+
const modelAvailable = checked.result.models.some((available) => available.id === modelId);
|
|
148
|
+
if (checked.result.connectionState !== "available" || !modelAvailable) {
|
|
144
149
|
throw new VcmError({
|
|
145
|
-
code: "
|
|
146
|
-
message: checked.result.error ?? `
|
|
150
|
+
code: "CODEX_BRIDGE_MODEL_UNAVAILABLE",
|
|
151
|
+
message: checked.result.error ?? `Codex Bridge model ${modelId} is unavailable.`,
|
|
147
152
|
statusCode: 409,
|
|
148
|
-
hint: "Check
|
|
153
|
+
hint: "Check Codex Bridge on port 3456, refresh its Codex login, and verify the selected model."
|
|
149
154
|
});
|
|
150
155
|
}
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const noProxy = mergeNoProxy(deps.baseEnv?.NO_PROXY ?? deps.baseEnv?.no_proxy ?? process.env.NO_PROXY ?? process.env.no_proxy,
|
|
156
|
+
const bridgeBaseUrl = checked.result.baseUrl ?? CODEX_BRIDGE_BASE_URL;
|
|
157
|
+
const bridgeHost = new URL(bridgeBaseUrl).hostname;
|
|
158
|
+
const noProxy = mergeNoProxy(deps.baseEnv?.NO_PROXY ?? deps.baseEnv?.no_proxy ?? process.env.NO_PROXY ?? process.env.no_proxy, bridgeHost);
|
|
154
159
|
return {
|
|
155
|
-
ANTHROPIC_BASE_URL:
|
|
156
|
-
ANTHROPIC_API_BASE_URL:
|
|
157
|
-
CLAUDE_AGENT_API_BASE_URL:
|
|
160
|
+
ANTHROPIC_BASE_URL: bridgeBaseUrl,
|
|
161
|
+
ANTHROPIC_API_BASE_URL: bridgeBaseUrl,
|
|
162
|
+
CLAUDE_AGENT_API_BASE_URL: bridgeBaseUrl,
|
|
158
163
|
ANTHROPIC_AUTH_TOKEN: undefined,
|
|
159
164
|
ANTHROPIC_API_KEY: undefined,
|
|
160
|
-
ANTHROPIC_MODEL:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
ANTHROPIC_SMALL_FAST_MODEL: CCR_GPT_MODEL_ID,
|
|
165
|
+
ANTHROPIC_MODEL: modelId,
|
|
166
|
+
CODEX_BRIDGE_CLAUDE_MODEL: modelId,
|
|
167
|
+
ANTHROPIC_SMALL_FAST_MODEL: modelId,
|
|
164
168
|
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: "1",
|
|
165
|
-
CLAUDE_CODE_MAX_CONTEXT_TOKENS: String(
|
|
166
|
-
CLAUDE_CODE_AUTO_COMPACT_WINDOW: String(
|
|
167
|
-
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: String(
|
|
169
|
+
CLAUDE_CODE_MAX_CONTEXT_TOKENS: String(CODEX_BRIDGE_EFFECTIVE_CONTEXT_TOKENS),
|
|
170
|
+
CLAUDE_CODE_AUTO_COMPACT_WINDOW: String(CODEX_BRIDGE_AUTO_COMPACT_WINDOW_TOKENS),
|
|
171
|
+
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: String(CODEX_BRIDGE_AUTO_COMPACT_PERCENT),
|
|
168
172
|
CLAUDE_CONFIG_DIR: configDir,
|
|
169
173
|
NO_PROXY: noProxy,
|
|
170
174
|
no_proxy: noProxy
|
|
171
175
|
};
|
|
172
176
|
},
|
|
173
177
|
async getLaunchSettingsOverride(model) {
|
|
174
|
-
if (!
|
|
178
|
+
if (!isCodexBridgeSessionModel(model)) {
|
|
175
179
|
return undefined;
|
|
176
180
|
}
|
|
177
181
|
return {
|
|
@@ -180,51 +184,50 @@ export function createCcrIntegrationService(deps) {
|
|
|
180
184
|
}
|
|
181
185
|
};
|
|
182
186
|
}
|
|
183
|
-
const
|
|
187
|
+
const BRIDGE_BASE_URL_KEYS = [
|
|
184
188
|
"ANTHROPIC_BASE_URL",
|
|
185
189
|
"ANTHROPIC_API_BASE_URL",
|
|
186
190
|
"CLAUDE_AGENT_API_BASE_URL"
|
|
187
191
|
];
|
|
188
|
-
const
|
|
192
|
+
const BRIDGE_MODEL_KEYS = [
|
|
189
193
|
"ANTHROPIC_MODEL",
|
|
190
194
|
"ANTHROPIC_SMALL_FAST_MODEL"
|
|
191
195
|
];
|
|
192
|
-
const
|
|
193
|
-
"
|
|
194
|
-
"CODEXL_CLAUDE_CODE_MODEL",
|
|
196
|
+
const BRIDGE_ONLY_ENV_KEYS = [
|
|
197
|
+
"CODEX_BRIDGE_CLAUDE_MODEL",
|
|
195
198
|
"CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY"
|
|
196
199
|
];
|
|
197
200
|
export function buildNativeLaunchEnvironment(baseEnv) {
|
|
198
201
|
const environment = {};
|
|
199
|
-
let
|
|
202
|
+
let inheritedBridgeTakeover = false;
|
|
200
203
|
if (baseEnv.CLAUDE_CONFIG_DIR?.trim()) {
|
|
201
204
|
environment.CLAUDE_CONFIG_DIR = baseEnv.CLAUDE_CONFIG_DIR.trim();
|
|
202
205
|
}
|
|
203
|
-
for (const key of
|
|
204
|
-
if (
|
|
206
|
+
for (const key of BRIDGE_BASE_URL_KEYS) {
|
|
207
|
+
if (isCodexBridgeUrl(baseEnv[key])) {
|
|
205
208
|
environment[key] = undefined;
|
|
206
|
-
|
|
209
|
+
inheritedBridgeTakeover = true;
|
|
207
210
|
}
|
|
208
211
|
}
|
|
209
|
-
for (const key of
|
|
210
|
-
if (
|
|
212
|
+
for (const key of BRIDGE_MODEL_KEYS) {
|
|
213
|
+
if (isCodexBridgeModelName(baseEnv[key], baseEnv.CODEX_BRIDGE_CLAUDE_MODEL)) {
|
|
211
214
|
environment[key] = undefined;
|
|
212
|
-
|
|
215
|
+
inheritedBridgeTakeover = true;
|
|
213
216
|
}
|
|
214
217
|
}
|
|
215
|
-
for (const key of
|
|
218
|
+
for (const key of BRIDGE_ONLY_ENV_KEYS) {
|
|
216
219
|
if (baseEnv[key] !== undefined) {
|
|
217
220
|
environment[key] = undefined;
|
|
218
|
-
|
|
221
|
+
inheritedBridgeTakeover = true;
|
|
219
222
|
}
|
|
220
223
|
}
|
|
221
|
-
if (
|
|
224
|
+
if (inheritedBridgeTakeover) {
|
|
222
225
|
environment.ANTHROPIC_AUTH_TOKEN = undefined;
|
|
223
226
|
environment.ANTHROPIC_API_KEY = undefined;
|
|
224
227
|
}
|
|
225
228
|
return environment;
|
|
226
229
|
}
|
|
227
|
-
function
|
|
230
|
+
function isCodexBridgeUrl(value) {
|
|
228
231
|
if (!value) {
|
|
229
232
|
return false;
|
|
230
233
|
}
|
|
@@ -237,32 +240,29 @@ function isCcrGatewayUrl(value) {
|
|
|
237
240
|
return false;
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
|
-
function
|
|
241
|
-
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
return value === CCR_GPT_MODEL_ID
|
|
245
|
-
|| value.startsWith("anthropic/claude-ccr-h");
|
|
243
|
+
function isCodexBridgeModelName(value, bridgeModel) {
|
|
244
|
+
return Boolean(value && bridgeModel && value === bridgeModel);
|
|
246
245
|
}
|
|
247
246
|
function createStatus(input) {
|
|
247
|
+
const { models, ...status } = input;
|
|
248
248
|
const reason = input.error
|
|
249
|
-
?? (input.enabled ? "
|
|
249
|
+
?? (input.enabled ? "Codex Bridge models are unavailable." : "Enable Codex Bridge in Settings.");
|
|
250
250
|
return {
|
|
251
|
-
...
|
|
252
|
-
modelOptions: createSessionModelOptions(input.enabled && input.modelAvailable
|
|
251
|
+
...status,
|
|
252
|
+
modelOptions: createSessionModelOptions(models, input.enabled && input.modelAvailable ? undefined : reason)
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
255
|
function missingApiKeyError() {
|
|
256
256
|
return new VcmError({
|
|
257
|
-
code: "
|
|
258
|
-
message: "
|
|
257
|
+
code: "CODEX_BRIDGE_API_KEY_MISSING",
|
|
258
|
+
message: "Codex Bridge API key is not configured.",
|
|
259
259
|
statusCode: 400,
|
|
260
|
-
hint: "Save the
|
|
260
|
+
hint: "Save the Codex Bridge API key before enabling Codex models."
|
|
261
261
|
});
|
|
262
262
|
}
|
|
263
263
|
function invalidSettingsError(message) {
|
|
264
264
|
return new VcmError({
|
|
265
|
-
code: "
|
|
265
|
+
code: "CODEX_BRIDGE_SETTINGS_INVALID",
|
|
266
266
|
message,
|
|
267
267
|
statusCode: 400
|
|
268
268
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { ROLE_NAMES, isDispatchableRole } from "../../shared/constants.js";
|
|
4
|
-
import {
|
|
4
|
+
import { isCodexBridgeSessionModel } from "../../shared/types/session.js";
|
|
5
5
|
import { VcmError } from "../errors.js";
|
|
6
6
|
import { resolveRepoPath } from "../adapters/filesystem.js";
|
|
7
7
|
import { submitTerminalInput } from "../runtime/terminal-submit.js";
|
|
@@ -598,21 +598,21 @@ export function createSessionService(deps) {
|
|
|
598
598
|
return migrateRunningProjectToolSessionCwd(repoRoot, resumed, targetCwd);
|
|
599
599
|
}
|
|
600
600
|
async function getModelLaunchEnvironment(model) {
|
|
601
|
-
if (!deps.
|
|
602
|
-
if (
|
|
601
|
+
if (!deps.codexBridgeIntegration) {
|
|
602
|
+
if (isCodexBridgeSessionModel(model)) {
|
|
603
603
|
throw new VcmError({
|
|
604
|
-
code: "
|
|
605
|
-
message: "
|
|
604
|
+
code: "CODEX_BRIDGE_UNAVAILABLE",
|
|
605
|
+
message: "Codex Bridge integration is not available in this VCM runtime.",
|
|
606
606
|
statusCode: 409,
|
|
607
|
-
hint: "Enable and configure
|
|
607
|
+
hint: "Enable and configure Codex Bridge before starting this session."
|
|
608
608
|
});
|
|
609
609
|
}
|
|
610
610
|
return {};
|
|
611
611
|
}
|
|
612
|
-
return deps.
|
|
612
|
+
return deps.codexBridgeIntegration.getLaunchEnvironment(model);
|
|
613
613
|
}
|
|
614
614
|
async function getModelLaunchSettingsOverride(model) {
|
|
615
|
-
return deps.
|
|
615
|
+
return deps.codexBridgeIntegration?.getLaunchSettingsOverride(model);
|
|
616
616
|
}
|
|
617
617
|
function isRuntimeSessionAlive(session) {
|
|
618
618
|
if (!session || isExitedStatus(session.status) || session.pid === undefined) {
|
|
@@ -1642,7 +1642,7 @@ function normalizeClaudeModel(value) {
|
|
|
1642
1642
|
|| value === "claude-opus-4-8"
|
|
1643
1643
|
|| value === "sonnet"
|
|
1644
1644
|
|| value === "fable"
|
|
1645
|
-
|| value
|
|
1645
|
+
|| isCodexBridgeSessionModel(value)) {
|
|
1646
1646
|
return value;
|
|
1647
1647
|
}
|
|
1648
1648
|
return "default";
|
|
@@ -1660,20 +1660,20 @@ function normalizeClaudeEffort(value) {
|
|
|
1660
1660
|
}
|
|
1661
1661
|
function assertResumeProviderCompatible(session, requestedModel) {
|
|
1662
1662
|
const persistedModel = normalizeClaudeModel(session.model);
|
|
1663
|
-
if (
|
|
1663
|
+
if (isCodexBridgeSessionModel(persistedModel) !== isCodexBridgeSessionModel(requestedModel)) {
|
|
1664
1664
|
throw new VcmError({
|
|
1665
1665
|
code: "SESSION_PROVIDER_SWITCH_REQUIRES_RESTART",
|
|
1666
1666
|
message: `Cannot resume ${session.role} with a different model provider.`,
|
|
1667
1667
|
statusCode: 409,
|
|
1668
|
-
hint: "Use Restart to switch between native Claude and
|
|
1668
|
+
hint: "Use Restart to switch between native Claude and Codex Bridge models."
|
|
1669
1669
|
});
|
|
1670
1670
|
}
|
|
1671
|
-
if (
|
|
1671
|
+
if (isCodexBridgeSessionModel(requestedModel) && !session.claudeConfigDir) {
|
|
1672
1672
|
throw new VcmError({
|
|
1673
|
-
code: "
|
|
1674
|
-
message: `${session.role} was created
|
|
1673
|
+
code: "CODEX_BRIDGE_SESSION_CONFIG_MISSING",
|
|
1674
|
+
message: `${session.role} was created without isolated Codex Bridge session storage.`,
|
|
1675
1675
|
statusCode: 409,
|
|
1676
|
-
hint: "Restart this role once to create an isolated
|
|
1676
|
+
hint: "Restart this role once to create an isolated Codex Bridge session."
|
|
1677
1677
|
});
|
|
1678
1678
|
}
|
|
1679
1679
|
}
|
|
@@ -1713,7 +1713,7 @@ function buildUsageTelemetryEnvironment(apiUrl, role, model) {
|
|
|
1713
1713
|
OTEL_LOG_TOOL_DETAILS: "0",
|
|
1714
1714
|
OTEL_LOG_RAW_API_BODIES: "0"
|
|
1715
1715
|
};
|
|
1716
|
-
if (!apiUrl ||
|
|
1716
|
+
if (!apiUrl || isCodexBridgeSessionModel(model)) {
|
|
1717
1717
|
return disabled;
|
|
1718
1718
|
}
|
|
1719
1719
|
return {
|
|
@@ -76,7 +76,7 @@ function extractApiRequestEvents(payload) {
|
|
|
76
76
|
continue;
|
|
77
77
|
}
|
|
78
78
|
const model = normalizeModel(readString(attributes.model));
|
|
79
|
-
if (
|
|
79
|
+
if (isCodexBridgeModel(model)) {
|
|
80
80
|
continue;
|
|
81
81
|
}
|
|
82
82
|
const sequence = readInteger(attributes["event.sequence"]);
|
|
@@ -334,9 +334,9 @@ function normalizeModel(input) {
|
|
|
334
334
|
const model = input?.slice(0, 200).trim();
|
|
335
335
|
return model && isSafeGroupKey(model) ? model : "unknown";
|
|
336
336
|
}
|
|
337
|
-
function
|
|
337
|
+
function isCodexBridgeModel(model) {
|
|
338
338
|
const normalized = model.toLowerCase();
|
|
339
|
-
return normalized.startsWith("gpt-") || normalized.startsWith("
|
|
339
|
+
return normalized.startsWith("gpt-") || normalized.startsWith("codex-bridge:");
|
|
340
340
|
}
|
|
341
341
|
function isSafeGroupKey(value) {
|
|
342
342
|
return value !== "__proto__" && value !== "prototype" && value !== "constructor";
|
|
@@ -52,32 +52,38 @@ export const CLAUDE_MODEL_OPTIONS = [
|
|
|
52
52
|
available: true
|
|
53
53
|
}
|
|
54
54
|
];
|
|
55
|
-
export const
|
|
56
|
-
export const
|
|
57
|
-
export const
|
|
58
|
-
export const
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
export const CODEX_BRIDGE_LOCAL_BASE_URL = "http://127.0.0.1:3456";
|
|
56
|
+
export const CODEX_BRIDGE_CONTAINER_BASE_URL = "http://host.docker.internal:3456";
|
|
57
|
+
export const CODEX_BRIDGE_BASE_URL = CODEX_BRIDGE_CONTAINER_BASE_URL;
|
|
58
|
+
export const CODEX_BRIDGE_BASE_URLS = [
|
|
59
|
+
CODEX_BRIDGE_LOCAL_BASE_URL,
|
|
60
|
+
CODEX_BRIDGE_CONTAINER_BASE_URL
|
|
61
61
|
];
|
|
62
|
-
export const
|
|
63
|
-
export const
|
|
64
|
-
export const
|
|
65
|
-
export
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
export const CODEX_BRIDGE_EFFECTIVE_CONTEXT_TOKENS = 258_400;
|
|
63
|
+
export const CODEX_BRIDGE_AUTO_COMPACT_WINDOW_TOKENS = CODEX_BRIDGE_EFFECTIVE_CONTEXT_TOKENS;
|
|
64
|
+
export const CODEX_BRIDGE_AUTO_COMPACT_PERCENT = 90;
|
|
65
|
+
export function isCodexBridgeSessionModel(model) {
|
|
66
|
+
return typeof model === "string"
|
|
67
|
+
&& model.startsWith("codex-bridge:")
|
|
68
|
+
&& model.length > "codex-bridge:".length;
|
|
69
69
|
}
|
|
70
|
-
export function
|
|
70
|
+
export function toCodexBridgeSessionModel(modelId) {
|
|
71
|
+
return `codex-bridge:${modelId}`;
|
|
72
|
+
}
|
|
73
|
+
export function getCodexBridgeModelId(model) {
|
|
74
|
+
return model.slice("codex-bridge:".length);
|
|
75
|
+
}
|
|
76
|
+
export function createSessionModelOptions(codexBridgeModels = [], unavailableReason) {
|
|
71
77
|
return [
|
|
72
78
|
...CLAUDE_MODEL_OPTIONS,
|
|
73
|
-
{
|
|
74
|
-
value:
|
|
75
|
-
label:
|
|
76
|
-
description:
|
|
77
|
-
source: "
|
|
78
|
-
available:
|
|
79
|
-
...(
|
|
80
|
-
}
|
|
79
|
+
...codexBridgeModels.map((model) => ({
|
|
80
|
+
value: toCodexBridgeSessionModel(model.id),
|
|
81
|
+
label: `${model.displayName ?? model.id} (Codex Bridge)`,
|
|
82
|
+
description: `${model.id} through the host Codex Bridge`,
|
|
83
|
+
source: "codex-bridge",
|
|
84
|
+
available: unavailableReason === undefined,
|
|
85
|
+
...(unavailableReason === undefined ? {} : { unavailableReason })
|
|
86
|
+
}))
|
|
81
87
|
];
|
|
82
88
|
}
|
|
83
89
|
const BASE_EFFORT_OPTIONS = [
|