codeksei 0.1.0 → 0.1.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.
- package/LICENSE +661 -661
- package/README.en.md +109 -47
- package/README.md +79 -58
- package/bin/cyberboss.js +1 -1
- package/package.json +86 -86
- package/scripts/open_shared_wechat_thread.sh +77 -77
- package/scripts/open_wechat_thread.sh +108 -108
- package/scripts/shared-common.js +144 -144
- package/scripts/shared-open.js +14 -14
- package/scripts/shared-start.js +5 -5
- package/scripts/shared-status.js +27 -27
- package/scripts/show_shared_status.sh +45 -45
- package/scripts/start_shared_app_server.sh +52 -52
- package/scripts/start_shared_wechat.sh +94 -94
- package/scripts/timeline-screenshot.sh +14 -14
- package/src/adapters/channel/weixin/account-store.js +99 -99
- package/src/adapters/channel/weixin/api-v2.js +50 -50
- package/src/adapters/channel/weixin/api.js +169 -169
- package/src/adapters/channel/weixin/context-token-store.js +84 -84
- package/src/adapters/channel/weixin/index.js +618 -604
- package/src/adapters/channel/weixin/legacy.js +579 -566
- package/src/adapters/channel/weixin/media-mime.js +22 -22
- package/src/adapters/channel/weixin/media-receive.js +370 -370
- package/src/adapters/channel/weixin/media-send.js +102 -102
- package/src/adapters/channel/weixin/message-utils-v2.js +282 -282
- package/src/adapters/channel/weixin/message-utils.js +199 -199
- package/src/adapters/channel/weixin/redact.js +41 -41
- package/src/adapters/channel/weixin/reminder-queue-store.js +101 -101
- package/src/adapters/channel/weixin/sync-buffer-store.js +35 -35
- package/src/adapters/runtime/codex/events.js +215 -215
- package/src/adapters/runtime/codex/index.js +109 -104
- package/src/adapters/runtime/codex/message-utils.js +95 -95
- package/src/adapters/runtime/codex/model-catalog.js +106 -106
- package/src/adapters/runtime/codex/protocol-leak-monitor.js +75 -75
- package/src/adapters/runtime/codex/rpc-client.js +339 -339
- package/src/adapters/runtime/codex/session-store.js +286 -286
- package/src/app/channel-send-file-cli.js +57 -57
- package/src/app/diary-write-cli.js +236 -88
- package/src/app/note-sync-cli.js +2 -2
- package/src/app/reminder-write-cli.js +215 -210
- package/src/app/review-cli.js +7 -5
- package/src/app/system-checkin-poller.js +64 -64
- package/src/app/system-send-cli.js +129 -129
- package/src/app/timeline-event-cli.js +28 -25
- package/src/app/timeline-screenshot-cli.js +103 -100
- package/src/core/app.js +1763 -1763
- package/src/core/branding.js +2 -1
- package/src/core/command-registry.js +381 -369
- package/src/core/config.js +30 -14
- package/src/core/default-targets.js +163 -163
- package/src/core/durable-note-schema.js +9 -8
- package/src/core/instructions-template.js +17 -16
- package/src/core/note-sync.js +8 -7
- package/src/core/path-utils.js +54 -0
- package/src/core/project-radar.js +11 -10
- package/src/core/review.js +48 -50
- package/src/core/stream-delivery.js +1162 -983
- package/src/core/system-message-dispatcher.js +68 -68
- package/src/core/system-message-queue-store.js +128 -128
- package/src/core/thread-state-store.js +96 -96
- package/src/core/timeline-screenshot-queue-store.js +134 -134
- package/src/core/timezone.js +436 -0
- package/src/core/workspace-bootstrap.js +9 -1
- package/src/index.js +148 -146
- package/src/integrations/timeline/index.js +130 -74
- package/src/integrations/timeline/state-sync.js +240 -0
- package/templates/weixin-instructions.md +12 -38
- package/templates/weixin-operations.md +29 -31
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const { renderInstructionTemplate } = require("../../../core/instructions-template");
|
|
3
|
-
const { CodexRpcClient } = require("./rpc-client");
|
|
4
|
-
const { mapCodexMessageToRuntimeEvent } = require("./events");
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const { renderInstructionTemplate } = require("../../../core/instructions-template");
|
|
3
|
+
const { CodexRpcClient } = require("./rpc-client");
|
|
4
|
+
const { mapCodexMessageToRuntimeEvent } = require("./events");
|
|
5
5
|
const {
|
|
6
6
|
extractAssistantText,
|
|
7
7
|
extractFailureText,
|
|
@@ -13,21 +13,21 @@ const {
|
|
|
13
13
|
const { SessionStore } = require("./session-store");
|
|
14
14
|
const { resolveCodexWorkspaceRoot } = require("../../../core/workspace-alias");
|
|
15
15
|
const { buildWorkspaceContinuityInstructions } = require("../../../core/workspace-bootstrap");
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
function createCodexRuntimeAdapter(config) {
|
|
18
18
|
const sessionStore = new SessionStore({ filePath: config.sessionsFile });
|
|
19
19
|
let client = null;
|
|
20
20
|
let readyState = null;
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
function ensureClient() {
|
|
23
|
-
if (!client) {
|
|
24
|
-
client = new CodexRpcClient({
|
|
25
|
-
endpoint: config.codexEndpoint,
|
|
26
|
-
codexCommand: config.codexCommand,
|
|
27
|
-
env: process.env,
|
|
28
|
-
extraWritableRoots: [config.stateDir],
|
|
29
|
-
});
|
|
30
|
-
}
|
|
23
|
+
if (!client) {
|
|
24
|
+
client = new CodexRpcClient({
|
|
25
|
+
endpoint: config.codexEndpoint,
|
|
26
|
+
codexCommand: config.codexCommand,
|
|
27
|
+
env: process.env,
|
|
28
|
+
extraWritableRoots: [config.stateDir],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
31
|
return client;
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -84,42 +84,42 @@ function createCodexRuntimeAdapter(config) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
return {
|
|
87
|
-
describe() {
|
|
88
|
-
return {
|
|
89
|
-
id: "codex",
|
|
90
|
-
kind: "runtime",
|
|
91
|
-
endpoint: config.codexEndpoint || "(spawn)",
|
|
92
|
-
sessionsFile: config.sessionsFile,
|
|
93
|
-
};
|
|
94
|
-
},
|
|
95
|
-
createClient() {
|
|
96
|
-
return ensureClient();
|
|
97
|
-
},
|
|
98
|
-
onEvent(listener) {
|
|
99
|
-
if (typeof listener !== "function") {
|
|
100
|
-
return () => {};
|
|
101
|
-
}
|
|
102
|
-
const runtimeClient = ensureClient();
|
|
103
|
-
return runtimeClient.onMessage((message) => {
|
|
104
|
-
const event = mapCodexMessageToRuntimeEvent(message);
|
|
105
|
-
if (event) {
|
|
106
|
-
listener(event, message);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
},
|
|
110
|
-
getSessionStore() {
|
|
111
|
-
return sessionStore;
|
|
112
|
-
},
|
|
87
|
+
describe() {
|
|
88
|
+
return {
|
|
89
|
+
id: "codex",
|
|
90
|
+
kind: "runtime",
|
|
91
|
+
endpoint: config.codexEndpoint || "(spawn)",
|
|
92
|
+
sessionsFile: config.sessionsFile,
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
createClient() {
|
|
96
|
+
return ensureClient();
|
|
97
|
+
},
|
|
98
|
+
onEvent(listener) {
|
|
99
|
+
if (typeof listener !== "function") {
|
|
100
|
+
return () => {};
|
|
101
|
+
}
|
|
102
|
+
const runtimeClient = ensureClient();
|
|
103
|
+
return runtimeClient.onMessage((message) => {
|
|
104
|
+
const event = mapCodexMessageToRuntimeEvent(message);
|
|
105
|
+
if (event) {
|
|
106
|
+
listener(event, message);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
getSessionStore() {
|
|
111
|
+
return sessionStore;
|
|
112
|
+
},
|
|
113
113
|
async initialize() {
|
|
114
114
|
return ensureInitialized();
|
|
115
115
|
},
|
|
116
|
-
async close() {
|
|
117
|
-
if (client) {
|
|
118
|
-
await client.close();
|
|
119
|
-
}
|
|
120
|
-
readyState = null;
|
|
121
|
-
client = null;
|
|
122
|
-
},
|
|
116
|
+
async close() {
|
|
117
|
+
if (client) {
|
|
118
|
+
await client.close();
|
|
119
|
+
}
|
|
120
|
+
readyState = null;
|
|
121
|
+
client = null;
|
|
122
|
+
},
|
|
123
123
|
async respondApproval({ requestId, decision }) {
|
|
124
124
|
return withRuntimeReconnect(async (runtimeClient) => {
|
|
125
125
|
const normalizedDecision = decision === "accept" ? "accept" : "decline";
|
|
@@ -320,23 +320,28 @@ function buildInstructionBlocks(config = {}, workspaceRoot = "") {
|
|
|
320
320
|
function loadWechatInstructions(config = {}) {
|
|
321
321
|
const persona = loadInstructionFile(config.weixinInstructionsFile, config);
|
|
322
322
|
const operations = loadInstructionFile(config.weixinOperationsFile, config);
|
|
323
|
-
|
|
323
|
+
const personaOverlay = loadInstructionFile(config.weixinInstructionsOverlayFile, config);
|
|
324
|
+
const operationsOverlay = loadInstructionFile(config.weixinOperationsOverlayFile, config);
|
|
325
|
+
return [persona, operations, personaOverlay, operationsOverlay].filter(Boolean).join("\n\n").trim();
|
|
324
326
|
}
|
|
325
|
-
|
|
327
|
+
|
|
326
328
|
function loadInstructionFile(filePath, config = {}) {
|
|
327
|
-
const normalizedPath = typeof filePath === "string" ? filePath.trim() : "";
|
|
328
|
-
if (!normalizedPath) {
|
|
329
|
-
return "";
|
|
330
|
-
}
|
|
331
|
-
try {
|
|
332
|
-
const raw = fs.readFileSync(normalizedPath, "utf8");
|
|
333
|
-
return renderInstructionTemplate(raw, config).trim();
|
|
334
|
-
} catch {
|
|
335
|
-
return "";
|
|
336
|
-
}
|
|
329
|
+
const normalizedPath = typeof filePath === "string" ? filePath.trim() : "";
|
|
330
|
+
if (!normalizedPath) {
|
|
331
|
+
return "";
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
const raw = fs.readFileSync(normalizedPath, "utf8");
|
|
335
|
+
return renderInstructionTemplate(raw, config).trim();
|
|
336
|
+
} catch {
|
|
337
|
+
return "";
|
|
338
|
+
}
|
|
337
339
|
}
|
|
338
340
|
|
|
339
|
-
module.exports = {
|
|
341
|
+
module.exports = {
|
|
342
|
+
createCodexRuntimeAdapter,
|
|
343
|
+
loadWechatInstructions,
|
|
344
|
+
};
|
|
340
345
|
|
|
341
346
|
async function startThreadWithWorkspaceDiagnostics({
|
|
342
347
|
runtimeClient,
|
|
@@ -436,47 +441,47 @@ function formatErrorMessage(error) {
|
|
|
436
441
|
}
|
|
437
442
|
|
|
438
443
|
function waitForTurnCompletion(client, threadId) {
|
|
439
|
-
return new Promise((resolve, reject) => {
|
|
440
|
-
let activeTurnId = "";
|
|
441
|
-
const itemOrder = [];
|
|
442
|
-
const completedTextByItemId = new Map();
|
|
443
|
-
|
|
444
|
-
const cleanup = () => {
|
|
445
|
-
unsubscribe();
|
|
446
|
-
clearTimeout(timer);
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
const timer = setTimeout(() => {
|
|
450
|
-
cleanup();
|
|
451
|
-
reject(new Error("codex turn timed out"));
|
|
452
|
-
}, 10 * 60_000);
|
|
453
|
-
|
|
454
|
-
const unsubscribe = client.onMessage((message) => {
|
|
455
|
-
const params = message?.params || {};
|
|
456
|
-
if (extractThreadIdFromParams(params) !== threadId) {
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
if ((message?.method === "turn/started" || message?.method === "turn/start") && !activeTurnId) {
|
|
461
|
-
activeTurnId = extractTurnIdFromParams(params);
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
if (isAssistantItemCompleted(message)) {
|
|
466
|
-
const itemId = typeof params?.item?.id === "string" ? params.item.id.trim() : `item-${itemOrder.length + 1}`;
|
|
467
|
-
if (!completedTextByItemId.has(itemId)) {
|
|
468
|
-
itemOrder.push(itemId);
|
|
469
|
-
}
|
|
470
|
-
completedTextByItemId.set(itemId, extractAssistantText(params));
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
if (message?.method === "turn/failed") {
|
|
475
|
-
cleanup();
|
|
476
|
-
reject(new Error(extractFailureText(params)));
|
|
477
|
-
return;
|
|
478
|
-
}
|
|
479
|
-
|
|
444
|
+
return new Promise((resolve, reject) => {
|
|
445
|
+
let activeTurnId = "";
|
|
446
|
+
const itemOrder = [];
|
|
447
|
+
const completedTextByItemId = new Map();
|
|
448
|
+
|
|
449
|
+
const cleanup = () => {
|
|
450
|
+
unsubscribe();
|
|
451
|
+
clearTimeout(timer);
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const timer = setTimeout(() => {
|
|
455
|
+
cleanup();
|
|
456
|
+
reject(new Error("codex turn timed out"));
|
|
457
|
+
}, 10 * 60_000);
|
|
458
|
+
|
|
459
|
+
const unsubscribe = client.onMessage((message) => {
|
|
460
|
+
const params = message?.params || {};
|
|
461
|
+
if (extractThreadIdFromParams(params) !== threadId) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if ((message?.method === "turn/started" || message?.method === "turn/start") && !activeTurnId) {
|
|
466
|
+
activeTurnId = extractTurnIdFromParams(params);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (isAssistantItemCompleted(message)) {
|
|
471
|
+
const itemId = typeof params?.item?.id === "string" ? params.item.id.trim() : `item-${itemOrder.length + 1}`;
|
|
472
|
+
if (!completedTextByItemId.has(itemId)) {
|
|
473
|
+
itemOrder.push(itemId);
|
|
474
|
+
}
|
|
475
|
+
completedTextByItemId.set(itemId, extractAssistantText(params));
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (message?.method === "turn/failed") {
|
|
480
|
+
cleanup();
|
|
481
|
+
reject(new Error(extractFailureText(params)));
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
480
485
|
if (message?.method === "turn/completed") {
|
|
481
486
|
const completedTurnId = extractTurnIdFromParams(params);
|
|
482
487
|
if (activeTurnId && completedTurnId && completedTurnId !== activeTurnId) {
|
|
@@ -497,6 +502,6 @@ function waitForTurnCompletion(client, threadId) {
|
|
|
497
502
|
text: String(text || "").trim() || "已完成。",
|
|
498
503
|
});
|
|
499
504
|
}
|
|
500
|
-
});
|
|
501
|
-
});
|
|
502
|
-
}
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
}
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
function extractThreadId(response) {
|
|
2
|
-
return response?.result?.thread?.id || null;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
function extractThreadIdFromParams(params) {
|
|
6
|
-
return normalizeIdentifier(params?.threadId);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function extractTurnIdFromParams(params) {
|
|
10
|
-
return normalizeIdentifier(params?.turnId || params?.turn?.id);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function isAssistantItemCompleted(message) {
|
|
14
|
-
return message?.method === "item/completed"
|
|
15
|
-
&& normalizeIdentifier(message?.params?.item?.type).toLowerCase() === "agentmessage";
|
|
16
|
-
}
|
|
17
|
-
|
|
1
|
+
function extractThreadId(response) {
|
|
2
|
+
return response?.result?.thread?.id || null;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function extractThreadIdFromParams(params) {
|
|
6
|
+
return normalizeIdentifier(params?.threadId);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function extractTurnIdFromParams(params) {
|
|
10
|
+
return normalizeIdentifier(params?.turnId || params?.turn?.id);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isAssistantItemCompleted(message) {
|
|
14
|
+
return message?.method === "item/completed"
|
|
15
|
+
&& normalizeIdentifier(message?.params?.item?.type).toLowerCase() === "agentmessage";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
18
|
function extractAssistantText(params) {
|
|
19
|
-
const directText = [
|
|
20
|
-
params?.delta,
|
|
21
|
-
params?.item?.text,
|
|
22
|
-
];
|
|
23
|
-
for (const value of directText) {
|
|
24
|
-
if (typeof value === "string" && value.length > 0) {
|
|
25
|
-
return normalizeLineEndings(value);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const contentObjects = [
|
|
30
|
-
params?.item?.content,
|
|
31
|
-
params?.content,
|
|
32
|
-
];
|
|
33
|
-
for (const content of contentObjects) {
|
|
34
|
-
const extracted = extractRawTextFromContent(content);
|
|
35
|
-
if (extracted) {
|
|
36
|
-
return extracted;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
19
|
+
const directText = [
|
|
20
|
+
params?.delta,
|
|
21
|
+
params?.item?.text,
|
|
22
|
+
];
|
|
23
|
+
for (const value of directText) {
|
|
24
|
+
if (typeof value === "string" && value.length > 0) {
|
|
25
|
+
return normalizeLineEndings(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const contentObjects = [
|
|
30
|
+
params?.item?.content,
|
|
31
|
+
params?.content,
|
|
32
|
+
];
|
|
33
|
+
for (const content of contentObjects) {
|
|
34
|
+
const extracted = extractRawTextFromContent(content);
|
|
35
|
+
if (extracted) {
|
|
36
|
+
return extracted;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
40
|
return "";
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -55,16 +55,16 @@ function extractAssistantPhase(params) {
|
|
|
55
55
|
}
|
|
56
56
|
return "";
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
function extractFailureText(params) {
|
|
60
|
-
const rawMessage = normalizeIdentifier(params?.turn?.error?.message || params?.error?.message);
|
|
61
|
-
return rawMessage ? `执行失败:${rawMessage}` : "执行失败";
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function normalizeIdentifier(value) {
|
|
65
|
-
return typeof value === "string" ? value.trim() : "";
|
|
66
|
-
}
|
|
67
|
-
|
|
58
|
+
|
|
59
|
+
function extractFailureText(params) {
|
|
60
|
+
const rawMessage = normalizeIdentifier(params?.turn?.error?.message || params?.error?.message);
|
|
61
|
+
return rawMessage ? `执行失败:${rawMessage}` : "执行失败";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalizeIdentifier(value) {
|
|
65
|
+
return typeof value === "string" ? value.trim() : "";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
68
|
function normalizeLineEndings(value) {
|
|
69
69
|
return String(value || "").replace(/\r\n/g, "\n");
|
|
70
70
|
}
|
|
@@ -82,53 +82,53 @@ function normalizeAssistantPhase(value) {
|
|
|
82
82
|
}
|
|
83
83
|
return "";
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
function extractRawTextFromContent(content) {
|
|
87
|
-
if (typeof content === "string" && content.length > 0) {
|
|
88
|
-
return normalizeLineEndings(content);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (!content) {
|
|
92
|
-
return "";
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (Array.isArray(content)) {
|
|
96
|
-
const parts = [];
|
|
97
|
-
for (const entry of content) {
|
|
98
|
-
if (typeof entry === "string" && entry.length > 0) {
|
|
99
|
-
parts.push(normalizeLineEndings(entry));
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
if (!entry || typeof entry !== "object") {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
const entryType = String(entry.type || "").toLowerCase();
|
|
106
|
-
if (entryType === "text" && typeof entry.text === "string" && entry.text.length > 0) {
|
|
107
|
-
parts.push(normalizeLineEndings(entry.text));
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
if (typeof entry.text === "string" && entry.text.length > 0) {
|
|
111
|
-
parts.push(normalizeLineEndings(entry.text));
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (typeof entry.value === "string" && entry.value.length > 0) {
|
|
115
|
-
parts.push(normalizeLineEndings(entry.value));
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return parts.join("");
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (typeof content !== "object") {
|
|
122
|
-
return "";
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (typeof content.text === "string" && content.text.length > 0) {
|
|
126
|
-
return normalizeLineEndings(content.text);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return "";
|
|
130
|
-
}
|
|
131
|
-
|
|
85
|
+
|
|
86
|
+
function extractRawTextFromContent(content) {
|
|
87
|
+
if (typeof content === "string" && content.length > 0) {
|
|
88
|
+
return normalizeLineEndings(content);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!content) {
|
|
92
|
+
return "";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (Array.isArray(content)) {
|
|
96
|
+
const parts = [];
|
|
97
|
+
for (const entry of content) {
|
|
98
|
+
if (typeof entry === "string" && entry.length > 0) {
|
|
99
|
+
parts.push(normalizeLineEndings(entry));
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!entry || typeof entry !== "object") {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const entryType = String(entry.type || "").toLowerCase();
|
|
106
|
+
if (entryType === "text" && typeof entry.text === "string" && entry.text.length > 0) {
|
|
107
|
+
parts.push(normalizeLineEndings(entry.text));
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (typeof entry.text === "string" && entry.text.length > 0) {
|
|
111
|
+
parts.push(normalizeLineEndings(entry.text));
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (typeof entry.value === "string" && entry.value.length > 0) {
|
|
115
|
+
parts.push(normalizeLineEndings(entry.value));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return parts.join("");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (typeof content !== "object") {
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (typeof content.text === "string" && content.text.length > 0) {
|
|
126
|
+
return normalizeLineEndings(content.text);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
132
|
module.exports = {
|
|
133
133
|
extractAssistantPhase,
|
|
134
134
|
extractAssistantText,
|
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
function extractModelCatalogFromListResponse(response) {
|
|
2
|
-
const candidates = Array.isArray(response?.result?.data)
|
|
3
|
-
? response.result.data
|
|
4
|
-
: Array.isArray(response?.data)
|
|
5
|
-
? response.data
|
|
6
|
-
: [];
|
|
7
|
-
return normalizeModelCatalog(candidates);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function resolveEffectiveModelForEffort(models, currentModel) {
|
|
11
|
-
if (!Array.isArray(models) || !models.length) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
const normalizedCurrent = normalizeText(currentModel).toLowerCase();
|
|
15
|
-
if (normalizedCurrent) {
|
|
16
|
-
const matched = findModelByQuery(models, normalizedCurrent);
|
|
17
|
-
if (matched) {
|
|
18
|
-
return matched;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return models.find((item) => item.isDefault) || models[0];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function findModelByQuery(models, query) {
|
|
25
|
-
const normalizedQuery = normalizeText(query).toLowerCase();
|
|
26
|
-
if (!normalizedQuery || !Array.isArray(models)) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
return models.find((item) => (
|
|
30
|
-
normalizeText(item?.model).toLowerCase() === normalizedQuery
|
|
31
|
-
|| normalizeText(item?.id).toLowerCase() === normalizedQuery
|
|
32
|
-
)) || null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function normalizeModelCatalog(models) {
|
|
36
|
-
if (!Array.isArray(models)) {
|
|
37
|
-
return [];
|
|
38
|
-
}
|
|
39
|
-
const normalized = [];
|
|
40
|
-
const seen = new Set();
|
|
41
|
-
for (const model of models) {
|
|
42
|
-
if (!model || typeof model !== "object") {
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
const modelId = normalizeText(model.model);
|
|
46
|
-
const id = normalizeText(model.id);
|
|
47
|
-
const normalizedModel = modelId || id;
|
|
48
|
-
if (!normalizedModel) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const dedupeKey = normalizedModel.toLowerCase();
|
|
52
|
-
if (seen.has(dedupeKey)) {
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
seen.add(dedupeKey);
|
|
56
|
-
normalized.push({
|
|
57
|
-
id,
|
|
58
|
-
model: normalizedModel,
|
|
59
|
-
displayName: normalizeText(model.displayName || model.display_name),
|
|
60
|
-
supportedReasoningEfforts: normalizeReasoningEfforts(
|
|
61
|
-
model.supportedReasoningEfforts || model.supported_reasoning_efforts
|
|
62
|
-
),
|
|
63
|
-
defaultReasoningEffort: normalizeText(model.defaultReasoningEffort || model.default_reasoning_effort),
|
|
64
|
-
isDefault: !!(model.isDefault || model.is_default),
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
return normalized;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function normalizeReasoningEfforts(efforts) {
|
|
71
|
-
if (!Array.isArray(efforts)) {
|
|
72
|
-
return [];
|
|
73
|
-
}
|
|
74
|
-
const result = [];
|
|
75
|
-
const seen = new Set();
|
|
76
|
-
for (const effort of efforts) {
|
|
77
|
-
const normalized = normalizeText(
|
|
78
|
-
typeof effort === "string"
|
|
79
|
-
? effort
|
|
80
|
-
: effort?.reasoningEffort || effort?.reasoning_effort
|
|
81
|
-
);
|
|
82
|
-
if (!normalized) {
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
const key = normalized.toLowerCase();
|
|
86
|
-
if (seen.has(key)) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
seen.add(key);
|
|
90
|
-
result.push(normalized);
|
|
91
|
-
}
|
|
92
|
-
return result;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function normalizeText(value) {
|
|
96
|
-
return typeof value === "string" ? value.trim() : "";
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
module.exports = {
|
|
100
|
-
extractModelCatalogFromListResponse,
|
|
101
|
-
findModelByQuery,
|
|
102
|
-
normalizeModelCatalog,
|
|
103
|
-
normalizeText,
|
|
104
|
-
resolveEffectiveModelForEffort,
|
|
105
|
-
};
|
|
106
|
-
|
|
1
|
+
function extractModelCatalogFromListResponse(response) {
|
|
2
|
+
const candidates = Array.isArray(response?.result?.data)
|
|
3
|
+
? response.result.data
|
|
4
|
+
: Array.isArray(response?.data)
|
|
5
|
+
? response.data
|
|
6
|
+
: [];
|
|
7
|
+
return normalizeModelCatalog(candidates);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function resolveEffectiveModelForEffort(models, currentModel) {
|
|
11
|
+
if (!Array.isArray(models) || !models.length) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const normalizedCurrent = normalizeText(currentModel).toLowerCase();
|
|
15
|
+
if (normalizedCurrent) {
|
|
16
|
+
const matched = findModelByQuery(models, normalizedCurrent);
|
|
17
|
+
if (matched) {
|
|
18
|
+
return matched;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return models.find((item) => item.isDefault) || models[0];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function findModelByQuery(models, query) {
|
|
25
|
+
const normalizedQuery = normalizeText(query).toLowerCase();
|
|
26
|
+
if (!normalizedQuery || !Array.isArray(models)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return models.find((item) => (
|
|
30
|
+
normalizeText(item?.model).toLowerCase() === normalizedQuery
|
|
31
|
+
|| normalizeText(item?.id).toLowerCase() === normalizedQuery
|
|
32
|
+
)) || null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeModelCatalog(models) {
|
|
36
|
+
if (!Array.isArray(models)) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const normalized = [];
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
for (const model of models) {
|
|
42
|
+
if (!model || typeof model !== "object") {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const modelId = normalizeText(model.model);
|
|
46
|
+
const id = normalizeText(model.id);
|
|
47
|
+
const normalizedModel = modelId || id;
|
|
48
|
+
if (!normalizedModel) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const dedupeKey = normalizedModel.toLowerCase();
|
|
52
|
+
if (seen.has(dedupeKey)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
seen.add(dedupeKey);
|
|
56
|
+
normalized.push({
|
|
57
|
+
id,
|
|
58
|
+
model: normalizedModel,
|
|
59
|
+
displayName: normalizeText(model.displayName || model.display_name),
|
|
60
|
+
supportedReasoningEfforts: normalizeReasoningEfforts(
|
|
61
|
+
model.supportedReasoningEfforts || model.supported_reasoning_efforts
|
|
62
|
+
),
|
|
63
|
+
defaultReasoningEffort: normalizeText(model.defaultReasoningEffort || model.default_reasoning_effort),
|
|
64
|
+
isDefault: !!(model.isDefault || model.is_default),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return normalized;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeReasoningEfforts(efforts) {
|
|
71
|
+
if (!Array.isArray(efforts)) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const result = [];
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
for (const effort of efforts) {
|
|
77
|
+
const normalized = normalizeText(
|
|
78
|
+
typeof effort === "string"
|
|
79
|
+
? effort
|
|
80
|
+
: effort?.reasoningEffort || effort?.reasoning_effort
|
|
81
|
+
);
|
|
82
|
+
if (!normalized) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const key = normalized.toLowerCase();
|
|
86
|
+
if (seen.has(key)) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
seen.add(key);
|
|
90
|
+
result.push(normalized);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function normalizeText(value) {
|
|
96
|
+
return typeof value === "string" ? value.trim() : "";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = {
|
|
100
|
+
extractModelCatalogFromListResponse,
|
|
101
|
+
findModelByQuery,
|
|
102
|
+
normalizeModelCatalog,
|
|
103
|
+
normalizeText,
|
|
104
|
+
resolveEffectiveModelForEffort,
|
|
105
|
+
};
|
|
106
|
+
|