Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfa61aa01a |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "telegram-codex-bot",
|
"name": "telegram-codex-bot",
|
||||||
"version": "0.1.10",
|
"version": "0.1.11",
|
||||||
"description": "Telegram bot powered by the local Codex CLI — zero-dependency, pm2-managed, with a built-in PM2 web viewer",
|
"description": "Telegram bot powered by the local Codex CLI — zero-dependency, pm2-managed, with a built-in PM2 web viewer",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
|
|||||||
+30
-7
@@ -322,21 +322,44 @@ function startBot(config) {
|
|||||||
|
|
||||||
let result;
|
let result;
|
||||||
let sessionResetNote = '';
|
let sessionResetNote = '';
|
||||||
|
let tid = existing?.threadId || null;
|
||||||
|
const MAX_ATTEMPTS = 2;
|
||||||
|
for (let attempt = 1; ; attempt++) {
|
||||||
try {
|
try {
|
||||||
result = await runCodex({ config, prompt, threadId: existing?.threadId || null, images, onProgress });
|
result = await runCodex({ config, prompt, threadId: tid, images, onProgress });
|
||||||
|
break;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 舊會話 resume 不了的情況,自動開新會話重試一次:
|
// 舊會話 resume 不了:1) 會話已被 codex 清掉 2) 換模型後 codex 拒絕跨模型 resume
|
||||||
// 1) 會話已被 codex 清掉(not found)
|
// → 清掉會話、開新會話重跑(tid=null 之後不會再進這個分支,不會無限迴圈)
|
||||||
// 2) bot 換了模型,codex 拒絕跨模型 resume(recorded with model X but resuming with Y)
|
|
||||||
const sessionGone = /session|thread|conversation/i.test(err.message) && /not.*found|找不到|no .*(session|thread)/i.test(err.message);
|
const sessionGone = /session|thread|conversation/i.test(err.message) && /not.*found|找不到|no .*(session|thread)/i.test(err.message);
|
||||||
const modelMismatch = /recorded with model/i.test(err.message);
|
const modelMismatch = /recorded with model/i.test(err.message);
|
||||||
if (existing && (sessionGone || modelMismatch)) {
|
if (tid && (sessionGone || modelMismatch)) {
|
||||||
sessions.clear(sessionKey);
|
sessions.clear(sessionKey);
|
||||||
result = await runCodex({ config, prompt, threadId: null, images, onProgress });
|
tid = null;
|
||||||
sessionResetNote = modelMismatch
|
sessionResetNote = modelMismatch
|
||||||
? '🆕 模型設定已變更,舊會話無法沿用,已自動開新會話(先前的對話記憶未帶入)。\n\n'
|
? '🆕 模型設定已變更,舊會話無法沿用,已自動開新會話(先前的對話記憶未帶入)。\n\n'
|
||||||
: '🆕 舊會話已失效,已自動開新會話。\n\n';
|
: '🆕 舊會話已失效,已自動開新會話。\n\n';
|
||||||
} else {
|
continue;
|
||||||
|
}
|
||||||
|
// 暫時性連線中斷(OpenAI 端切斷串流等)
|
||||||
|
if (err.transient) {
|
||||||
|
if (err.threadId) tid = err.threadId;
|
||||||
|
if (tid) sessions.set(sessionKey, tid); // 會話已建立,先記下來以便 resume
|
||||||
|
// 中斷前若圖已生成,直接交付,不重跑(避免重複生圖、多花時間)
|
||||||
|
if (collectGeneratedImages(tid, turnStart).length > 0) {
|
||||||
|
result = { text: '(回覆文字因連線中斷遺失,圖片如下)', threadId: tid, usage: null };
|
||||||
|
sessionResetNote += '⚠️ 連線在回覆途中中斷,但圖片已生成完畢,直接送上。\n\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (attempt < MAX_ATTEMPTS) {
|
||||||
|
await t.tg('editMessageText', {
|
||||||
|
chat_id: chatId,
|
||||||
|
message_id: statusMsg.message_id,
|
||||||
|
text: `⚠️ 連線中斷,自動重試中(${attempt + 1}/${MAX_ATTEMPTS})…`,
|
||||||
|
}).catch(() => {});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -198,7 +198,11 @@ function runCodex({ config, prompt, threadId, images = [], onProgress }) {
|
|||||||
proc.on('close', (code) => {
|
proc.on('close', (code) => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
if (turnFailedMessage) {
|
if (turnFailedMessage) {
|
||||||
return reject(new Error(`Codex 執行失敗:${turnFailedMessage}`));
|
const e = new Error(`Codex 執行失敗:${turnFailedMessage}`);
|
||||||
|
e.threadId = resultThreadId; // 會話可能已建立,讓呼叫端能 resume 重試
|
||||||
|
// 暫時性連線問題(OpenAI 端切斷串流等),呼叫端可重試
|
||||||
|
e.transient = /stream disconnected|websocket closed|Falling back from WebSockets|connection reset|ECONNRESET|socket hang up|timed out/i.test(turnFailedMessage);
|
||||||
|
return reject(e);
|
||||||
}
|
}
|
||||||
if (turnCompleted || messages.length > 0) {
|
if (turnCompleted || messages.length > 0) {
|
||||||
return resolve({ text: messages.join('\n\n'), threadId: resultThreadId, usage });
|
return resolve({ text: messages.join('\n\n'), threadId: resultThreadId, usage });
|
||||||
|
|||||||
Reference in New Issue
Block a user