aicodeswitch 5.2.10 → 5.2.11
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/bin/utils/managed-fields.js +2 -0
- package/dist/server/config-managed-fields.js +2 -0
- package/dist/server/conversions/pairs/responses-claude/response.js +5 -21
- package/dist/server/conversions/pairs/responses-claude/streaming.js +18 -20
- package/dist/server/conversions/pairs/responses-completions/response.js +2 -9
- package/dist/server/conversions/pairs/responses-completions/streaming.js +3 -10
- package/dist/server/conversions/utils/usage.js +28 -8
- package/dist/server/main.js +19 -4
- package/dist/ui/assets/{index-NlzYhf99.js → index-DR6cZIa7.js} +15 -15
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
|
@@ -41,6 +41,8 @@ exports.CODEX_CONFIG_MANAGED_FIELDS = [
|
|
|
41
41
|
{ path: ['enableRouteSelection'] },
|
|
42
42
|
{ path: ['model_providers', 'aicodeswitch'], isSection: true },
|
|
43
43
|
{ path: ['mcp_servers'], isSection: true, optional: true },
|
|
44
|
+
{ path: ['features'], isSection: true, optional: true },
|
|
45
|
+
{ path: ['memories'], isSection: true, optional: true },
|
|
44
46
|
];
|
|
45
47
|
/**
|
|
46
48
|
* Codex auth.json 管理字段定义
|
|
@@ -9,6 +9,7 @@ exports.claudeToResponsesResponse = claudeToResponsesResponse;
|
|
|
9
9
|
const id_js_1 = require("../../utils/id.js");
|
|
10
10
|
const stop_reasons_js_1 = require("../../utils/stop-reasons.js");
|
|
11
11
|
const mapper_js_1 = require("../../thinking/mapper.js");
|
|
12
|
+
const usage_js_1 = require("../../utils/usage.js");
|
|
12
13
|
/**
|
|
13
14
|
* Convert a Claude Messages response to an OpenAI Responses API response.
|
|
14
15
|
*/
|
|
@@ -45,26 +46,9 @@ function claudeToResponsesResponse(response) {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
const { status, incomplete_details } = (0, stop_reasons_js_1.claudeToResponsesStatus)(response.stop_reason);
|
|
48
|
-
|
|
49
|
+
// 上游无 usage 时省略 usage 字段(不伪造 0)
|
|
50
|
+
const usage = (0, usage_js_1.toResponsesUsage)(response.usage);
|
|
49
51
|
const responseId = response.id || (0, id_js_1.generateResponseId)();
|
|
50
|
-
return Object.assign(Object.assign({ id: responseId, object: 'response', status,
|
|
51
|
-
output, model: response.model || '', created_at: Math.floor(Date.now() / 1000), usage }, (incomplete_details ? { incomplete_details } : {})), { metadata: {} });
|
|
52
|
-
}
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
// Helpers
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
/**
|
|
57
|
-
* Map Claude usage to Responses API usage.
|
|
58
|
-
*/
|
|
59
|
-
function claudeToResponsesUsage(usage) {
|
|
60
|
-
var _a, _b;
|
|
61
|
-
if (!usage)
|
|
62
|
-
return { input_tokens: 0, output_tokens: 0, total_tokens: 0 };
|
|
63
|
-
const input = (_a = usage.input_tokens) !== null && _a !== void 0 ? _a : 0;
|
|
64
|
-
const output = (_b = usage.output_tokens) !== null && _b !== void 0 ? _b : 0;
|
|
65
|
-
return {
|
|
66
|
-
input_tokens: input,
|
|
67
|
-
output_tokens: output,
|
|
68
|
-
total_tokens: input + output,
|
|
69
|
-
};
|
|
52
|
+
return Object.assign(Object.assign(Object.assign({ id: responseId, object: 'response', status,
|
|
53
|
+
output, model: response.model || '', created_at: Math.floor(Date.now() / 1000) }, (usage ? { usage } : {})), (incomplete_details ? { incomplete_details } : {})), { metadata: {} });
|
|
70
54
|
}
|
|
@@ -10,6 +10,7 @@ exports.ClaudeToResponsesConverter = void 0;
|
|
|
10
10
|
const id_js_1 = require("../../utils/id.js");
|
|
11
11
|
const stop_reasons_js_1 = require("../../utils/stop-reasons.js");
|
|
12
12
|
const streaming_helpers_js_1 = require("../../utils/streaming-helpers.js");
|
|
13
|
+
const usage_js_1 = require("../../utils/usage.js");
|
|
13
14
|
/**
|
|
14
15
|
* ClaudeToResponsesConverter: Claude Messages SSE → Responses API SSE
|
|
15
16
|
*/
|
|
@@ -49,7 +50,7 @@ class ClaudeToResponsesConverter {
|
|
|
49
50
|
enumerable: true,
|
|
50
51
|
configurable: true,
|
|
51
52
|
writable: true,
|
|
52
|
-
value:
|
|
53
|
+
value: null
|
|
53
54
|
});
|
|
54
55
|
Object.defineProperty(this, "output", {
|
|
55
56
|
enumerable: true,
|
|
@@ -89,7 +90,7 @@ class ClaudeToResponsesConverter {
|
|
|
89
90
|
});
|
|
90
91
|
}
|
|
91
92
|
convertEvent(event) {
|
|
92
|
-
var _a, _b, _c, _d, _e;
|
|
93
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
93
94
|
if (!event.data)
|
|
94
95
|
return [];
|
|
95
96
|
const events = [];
|
|
@@ -99,6 +100,14 @@ class ClaudeToResponsesConverter {
|
|
|
99
100
|
case 'message_start': {
|
|
100
101
|
this.model = ((_a = data.message) === null || _a === void 0 ? void 0 : _a.model) || '';
|
|
101
102
|
this.responseId = ((_b = data.message) === null || _b === void 0 ? void 0 : _b.id) || this.responseId;
|
|
103
|
+
// Claude 的 prompt token 数在 message_start 的 message.usage.input_tokens
|
|
104
|
+
const startUsage = (_c = data.message) === null || _c === void 0 ? void 0 : _c.usage;
|
|
105
|
+
if (startUsage) {
|
|
106
|
+
this.usage = {
|
|
107
|
+
input_tokens: (_d = startUsage.input_tokens) !== null && _d !== void 0 ? _d : 0,
|
|
108
|
+
output_tokens: (_e = startUsage.output_tokens) !== null && _e !== void 0 ? _e : 0,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
102
111
|
events.push(this.makeSSE('response.created', {
|
|
103
112
|
id: this.responseId,
|
|
104
113
|
object: 'response',
|
|
@@ -236,11 +245,11 @@ class ClaudeToResponsesConverter {
|
|
|
236
245
|
break;
|
|
237
246
|
}
|
|
238
247
|
case 'message_delta': {
|
|
239
|
-
this.pendingStopReason = ((
|
|
248
|
+
this.pendingStopReason = ((_f = data.delta) === null || _f === void 0 ? void 0 : _f.stop_reason) || null;
|
|
240
249
|
if (data.usage) {
|
|
241
250
|
this.usage = {
|
|
242
|
-
input_tokens: this.usage.input_tokens,
|
|
243
|
-
output_tokens: (
|
|
251
|
+
input_tokens: (_j = (_g = data.usage.input_tokens) !== null && _g !== void 0 ? _g : (_h = this.usage) === null || _h === void 0 ? void 0 : _h.input_tokens) !== null && _j !== void 0 ? _j : 0,
|
|
252
|
+
output_tokens: (_o = (_l = (_k = data.usage.output_tokens) !== null && _k !== void 0 ? _k : data.usage.tokens) !== null && _l !== void 0 ? _l : (_m = this.usage) === null || _m === void 0 ? void 0 : _m.output_tokens) !== null && _o !== void 0 ? _o : 0,
|
|
244
253
|
};
|
|
245
254
|
}
|
|
246
255
|
break;
|
|
@@ -253,7 +262,7 @@ class ClaudeToResponsesConverter {
|
|
|
253
262
|
break;
|
|
254
263
|
}
|
|
255
264
|
}
|
|
256
|
-
catch (
|
|
265
|
+
catch (_p) {
|
|
257
266
|
// Ignore parse errors
|
|
258
267
|
}
|
|
259
268
|
return events;
|
|
@@ -315,20 +324,9 @@ class ClaudeToResponsesConverter {
|
|
|
315
324
|
this.closeText(events);
|
|
316
325
|
this.closeThinking(events);
|
|
317
326
|
const { status, incomplete_details } = (0, stop_reasons_js_1.claudeToResponsesStatus)(this.pendingStopReason);
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
status,
|
|
322
|
-
output: this.output,
|
|
323
|
-
model: this.model,
|
|
324
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
325
|
-
usage: {
|
|
326
|
-
input_tokens: this.usage.input_tokens,
|
|
327
|
-
output_tokens: this.usage.output_tokens,
|
|
328
|
-
total_tokens: this.usage.input_tokens + this.usage.output_tokens,
|
|
329
|
-
},
|
|
330
|
-
metadata: {},
|
|
331
|
-
};
|
|
327
|
+
// 上游无 usage 时省略 usage 字段(不伪造 0,避免 Codex missing field input_tokens)
|
|
328
|
+
const responsesUsage = (0, usage_js_1.toResponsesUsage)(this.usage);
|
|
329
|
+
const responseObj = Object.assign({ id: this.responseId, object: 'response', status, output: this.output, model: this.model, created_at: Math.floor(Date.now() / 1000), metadata: {} }, (responsesUsage ? { usage: responsesUsage } : {}));
|
|
332
330
|
if (incomplete_details) {
|
|
333
331
|
responseObj.incomplete_details = incomplete_details;
|
|
334
332
|
}
|
|
@@ -80,15 +80,8 @@ function completionsToResponsesResponse(response) {
|
|
|
80
80
|
const finishReason = (0, stop_reasons_js_1.completionsToResponsesFinishReason)(choice.finish_reason);
|
|
81
81
|
const status = finishReason === 'incomplete' ? 'incomplete' : 'completed';
|
|
82
82
|
const usage = (0, usage_js_1.completionsToResponsesUsage)(response.usage);
|
|
83
|
-
const result = {
|
|
84
|
-
|
|
85
|
-
object: 'response',
|
|
86
|
-
status,
|
|
87
|
-
output,
|
|
88
|
-
model: response.model,
|
|
89
|
-
usage,
|
|
90
|
-
created_at: response.created || Math.floor(Date.now() / 1000),
|
|
91
|
-
};
|
|
83
|
+
const result = Object.assign({ id: ((_m = response.id) === null || _m === void 0 ? void 0 : _m.startsWith('resp_')) ? response.id : (0, id_js_1.generateResponseId)(), object: 'response', status,
|
|
84
|
+
output, model: response.model, created_at: response.created || Math.floor(Date.now() / 1000) }, (usage ? { usage } : {}));
|
|
92
85
|
if (status === 'incomplete') {
|
|
93
86
|
result.incomplete_details = { reason: 'max_output_tokens' };
|
|
94
87
|
}
|
|
@@ -320,16 +320,9 @@ class CompletionsToResponsesConverter {
|
|
|
320
320
|
}
|
|
321
321
|
// Build full response object
|
|
322
322
|
const status = this.finishReason === 'length' ? 'incomplete' : 'completed';
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
status,
|
|
327
|
-
output: this.output,
|
|
328
|
-
model: this.model,
|
|
329
|
-
usage: this.usage ? (0, usage_js_1.completionsToResponsesUsage)(this.usage) : {},
|
|
330
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
331
|
-
metadata: {},
|
|
332
|
-
};
|
|
323
|
+
// 上游无 usage 时省略 usage 字段(不伪造 0,避免 Codex missing field input_tokens)
|
|
324
|
+
const responsesUsage = (0, usage_js_1.completionsToResponsesUsage)(this.usage);
|
|
325
|
+
const responseObj = Object.assign({ id: this.responseId, object: 'response', status, output: this.output, model: this.model, created_at: Math.floor(Date.now() / 1000), metadata: {} }, (responsesUsage ? { usage: responsesUsage } : {}));
|
|
333
326
|
if (status === 'incomplete') {
|
|
334
327
|
responseObj.incomplete_details = { reason: 'max_output_tokens' };
|
|
335
328
|
}
|
|
@@ -8,6 +8,7 @@ exports.claudeToCompletionsUsage = claudeToCompletionsUsage;
|
|
|
8
8
|
exports.geminiToClaudeUsage = geminiToClaudeUsage;
|
|
9
9
|
exports.claudeToGeminiUsage = claudeToGeminiUsage;
|
|
10
10
|
exports.responsesToClaudeUsage = responsesToClaudeUsage;
|
|
11
|
+
exports.toResponsesUsage = toResponsesUsage;
|
|
11
12
|
exports.completionsToResponsesUsage = completionsToResponsesUsage;
|
|
12
13
|
/** Map OpenAI Chat usage to Claude usage */
|
|
13
14
|
function completionsToClaudeUsage(usage) {
|
|
@@ -69,14 +70,33 @@ function responsesToClaudeUsage(usage) {
|
|
|
69
70
|
cache_creation_input_tokens: usage.cache_creation_input_tokens,
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
/**
|
|
74
|
+
* 构造标准 Responses API usage 对象(转换层兼容入口)。
|
|
75
|
+
*
|
|
76
|
+
* 真实值优先:input_tokens ?? prompt_tokens、output_tokens ?? completion_tokens、total_tokens。
|
|
77
|
+
* 覆盖上游 chat completions / claude / gemini 三种格式的字段命名归一。
|
|
78
|
+
*
|
|
79
|
+
* 仅当上游确实提供了任意 token 字段时返回归一化对象;否则返回 null(调用方应省略 usage 字段,
|
|
80
|
+
* 不伪造 0)。这是避免 Codex `ResponseCompleted: missing field input_tokens` 的关键——
|
|
81
|
+
* 既不吐空 `{}`,也不吐伪造的 `{0,0,0}`。
|
|
82
|
+
*/
|
|
83
|
+
function toResponsesUsage(usage) {
|
|
84
|
+
var _a, _b;
|
|
85
|
+
if (!usage || typeof usage !== 'object')
|
|
86
|
+
return null;
|
|
87
|
+
const input_tokens = (_a = usage.input_tokens) !== null && _a !== void 0 ? _a : usage.prompt_tokens;
|
|
88
|
+
const output_tokens = (_b = usage.output_tokens) !== null && _b !== void 0 ? _b : usage.completion_tokens;
|
|
89
|
+
const total_tokens = usage.total_tokens;
|
|
90
|
+
// 上游没返回任何 token 字段 → 不伪造,返回 null
|
|
91
|
+
if (input_tokens == null && output_tokens == null && total_tokens == null)
|
|
92
|
+
return null;
|
|
77
93
|
return {
|
|
78
|
-
input_tokens:
|
|
79
|
-
output_tokens:
|
|
80
|
-
total_tokens:
|
|
94
|
+
input_tokens: input_tokens !== null && input_tokens !== void 0 ? input_tokens : 0,
|
|
95
|
+
output_tokens: output_tokens !== null && output_tokens !== void 0 ? output_tokens : 0,
|
|
96
|
+
total_tokens: total_tokens !== null && total_tokens !== void 0 ? total_tokens : ((input_tokens !== null && input_tokens !== void 0 ? input_tokens : 0) + (output_tokens !== null && output_tokens !== void 0 ? output_tokens : 0)),
|
|
81
97
|
};
|
|
82
98
|
}
|
|
99
|
+
/** Map OpenAI Chat usage to Responses API usage(薄封装,保持现有调用方不变) */
|
|
100
|
+
function completionsToResponsesUsage(usage) {
|
|
101
|
+
return toResponsesUsage(usage);
|
|
102
|
+
}
|
package/dist/server/main.js
CHANGED
|
@@ -383,7 +383,7 @@ const DEFAULT_CODEX_REASONING_EFFORT = 'high';
|
|
|
383
383
|
const isCodexReasoningEffort = (value) => {
|
|
384
384
|
return typeof value === 'string' && VALID_CODEX_REASONING_EFFORTS.includes(value);
|
|
385
385
|
};
|
|
386
|
-
const writeCodexConfig = (_dbManager_1, ...args_1) => __awaiter(void 0, [_dbManager_1, ...args_1], void 0, function* (_dbManager, modelReasoningEffort = DEFAULT_CODEX_REASONING_EFFORT, codexDefaultModel, options = {}) {
|
|
386
|
+
const writeCodexConfig = (_dbManager_1, ...args_1) => __awaiter(void 0, [_dbManager_1, ...args_1], void 0, function* (_dbManager, modelReasoningEffort = DEFAULT_CODEX_REASONING_EFFORT, codexDefaultModel, enableMemories, options = {}) {
|
|
387
387
|
var _a;
|
|
388
388
|
try {
|
|
389
389
|
const homeDir = os_1.default.homedir();
|
|
@@ -450,6 +450,17 @@ const writeCodexConfig = (_dbManager_1, ...args_1) => __awaiter(void 0, [_dbMana
|
|
|
450
450
|
}
|
|
451
451
|
}
|
|
452
452
|
};
|
|
453
|
+
// 记忆功能配置
|
|
454
|
+
if (enableMemories) {
|
|
455
|
+
proxyConfig.features = {
|
|
456
|
+
memories: true,
|
|
457
|
+
};
|
|
458
|
+
proxyConfig.memories = {
|
|
459
|
+
generate_memories: true,
|
|
460
|
+
use_memories: true,
|
|
461
|
+
disable_on_external_context: true,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
453
464
|
// 使用智能合并
|
|
454
465
|
const mergedConfig = (0, config_merge_1.mergeTomlConfig)(proxyConfig, currentConfig, config_managed_fields_1.CODEX_CONFIG_MANAGED_FIELDS);
|
|
455
466
|
// 原子性写入合并后的配置
|
|
@@ -681,7 +692,7 @@ const syncConfigsOnServerStartup = (dbManager) => __awaiter(void 0, void 0, void
|
|
|
681
692
|
const modelReasoningEffort = isCodexReasoningEffort(config.codexModelReasoningEffort)
|
|
682
693
|
? config.codexModelReasoningEffort
|
|
683
694
|
: DEFAULT_CODEX_REASONING_EFFORT;
|
|
684
|
-
const codexWritten = yield writeCodexConfig(dbManager, modelReasoningEffort, config.codexDefaultModel);
|
|
695
|
+
const codexWritten = yield writeCodexConfig(dbManager, modelReasoningEffort, config.codexDefaultModel, config.codexEnableMemories);
|
|
685
696
|
console.log(`[Startup Config Sync] Codex config ${codexWritten ? 'written' : 'skipped'}`);
|
|
686
697
|
});
|
|
687
698
|
const syncConfigsOnGlobalConfigUpdate = (dbManager) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -694,7 +705,7 @@ const syncConfigsOnGlobalConfigUpdate = (dbManager) => __awaiter(void 0, void 0,
|
|
|
694
705
|
const modelReasoningEffort = isCodexReasoningEffort(config.codexModelReasoningEffort)
|
|
695
706
|
? config.codexModelReasoningEffort
|
|
696
707
|
: DEFAULT_CODEX_REASONING_EFFORT;
|
|
697
|
-
const codexUpdated = yield writeCodexConfig(dbManager, modelReasoningEffort, config.codexDefaultModel, { allowOverwriteRefresh: true });
|
|
708
|
+
const codexUpdated = yield writeCodexConfig(dbManager, modelReasoningEffort, config.codexDefaultModel, config.codexEnableMemories, { allowOverwriteRefresh: true });
|
|
698
709
|
console.log(`[Config Update Sync] Codex config ${codexUpdated ? 'written' : 'skipped'}`);
|
|
699
710
|
});
|
|
700
711
|
const getCentralSkillsDir = () => {
|
|
@@ -2038,7 +2049,11 @@ ${instruction}
|
|
|
2038
2049
|
: isCodexReasoningEffort(appConfig.codexModelReasoningEffort)
|
|
2039
2050
|
? appConfig.codexModelReasoningEffort
|
|
2040
2051
|
: DEFAULT_CODEX_REASONING_EFFORT;
|
|
2041
|
-
const
|
|
2052
|
+
const requestedEnableMemories = req.body.enableMemories;
|
|
2053
|
+
const enableMemories = requestedEnableMemories !== undefined
|
|
2054
|
+
? !!requestedEnableMemories
|
|
2055
|
+
: !!appConfig.codexEnableMemories;
|
|
2056
|
+
const result = yield writeCodexConfig(dbManager, modelReasoningEffort, appConfig.codexDefaultModel, enableMemories);
|
|
2042
2057
|
applyWriteLocalRecords(proxyServer);
|
|
2043
2058
|
res.json(result);
|
|
2044
2059
|
})));
|