opencode-feishu 0.7.4 → 0.7.6
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/dist/index.js +137 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99266,12 +99266,68 @@ async function forkSession(client, oldSessionId, sessionKey, directory) {
|
|
|
99266
99266
|
}
|
|
99267
99267
|
return { id: resp.data.id, title };
|
|
99268
99268
|
}
|
|
99269
|
+
async function createFreshSession(client, sessionKey, directory) {
|
|
99270
|
+
const query = directory ? { directory } : void 0;
|
|
99271
|
+
const title = generateSessionTitle(sessionKey);
|
|
99272
|
+
const resp = await client.session.create({ query, body: { title } });
|
|
99273
|
+
if (!resp?.data?.id) {
|
|
99274
|
+
const err = resp?.error;
|
|
99275
|
+
throw new Error(
|
|
99276
|
+
`\u521B\u5EFA\u65B0\u4F1A\u8BDD\u5931\u8D25: ${err ? JSON.stringify(err) : "unknown"}`
|
|
99277
|
+
);
|
|
99278
|
+
}
|
|
99279
|
+
return { id: resp.data.id, title: resp.data.title };
|
|
99280
|
+
}
|
|
99281
|
+
async function forkOrCreateSession(client, oldSessionId, sessionKey, directory, log) {
|
|
99282
|
+
try {
|
|
99283
|
+
return await forkSession(client, oldSessionId, sessionKey, directory);
|
|
99284
|
+
} catch (forkErr) {
|
|
99285
|
+
log?.("warn", "Fork \u5931\u8D25\uFF0C\u56DE\u9000\u5230\u521B\u5EFA\u65B0\u4F1A\u8BDD", {
|
|
99286
|
+
oldSessionId,
|
|
99287
|
+
sessionKey,
|
|
99288
|
+
error: forkErr instanceof Error ? forkErr.message : String(forkErr)
|
|
99289
|
+
});
|
|
99290
|
+
return await createFreshSession(client, sessionKey, directory);
|
|
99291
|
+
}
|
|
99292
|
+
}
|
|
99269
99293
|
|
|
99270
99294
|
// src/handler/event.ts
|
|
99295
|
+
function maskKey(sessionKey) {
|
|
99296
|
+
return sessionKey.replace(/-[^-]+$/, "-***");
|
|
99297
|
+
}
|
|
99271
99298
|
var pendingBySession = /* @__PURE__ */ new Map();
|
|
99272
99299
|
var sessionErrors = /* @__PURE__ */ new Map();
|
|
99273
99300
|
var sessionErrorTimeouts = /* @__PURE__ */ new Map();
|
|
99274
99301
|
var SESSION_ERROR_TTL_MS = 3e4;
|
|
99302
|
+
var modelOverrides = /* @__PURE__ */ new Map();
|
|
99303
|
+
var forkAttempts = /* @__PURE__ */ new Map();
|
|
99304
|
+
var forkAttemptTimeouts = /* @__PURE__ */ new Map();
|
|
99305
|
+
var MAX_FORK_ATTEMPTS = 2;
|
|
99306
|
+
var FORK_ATTEMPTS_TTL_MS = 36e5;
|
|
99307
|
+
function clearForkAttempts(sessionKey) {
|
|
99308
|
+
forkAttempts.delete(sessionKey);
|
|
99309
|
+
const timer = forkAttemptTimeouts.get(sessionKey);
|
|
99310
|
+
if (timer) {
|
|
99311
|
+
clearTimeout(timer);
|
|
99312
|
+
forkAttemptTimeouts.delete(sessionKey);
|
|
99313
|
+
}
|
|
99314
|
+
}
|
|
99315
|
+
function setForkAttempts(sessionKey, count) {
|
|
99316
|
+
forkAttempts.set(sessionKey, count);
|
|
99317
|
+
const existing = forkAttemptTimeouts.get(sessionKey);
|
|
99318
|
+
if (existing) clearTimeout(existing);
|
|
99319
|
+
const timeoutId = setTimeout(() => {
|
|
99320
|
+
forkAttempts.delete(sessionKey);
|
|
99321
|
+
forkAttemptTimeouts.delete(sessionKey);
|
|
99322
|
+
}, FORK_ATTEMPTS_TTL_MS);
|
|
99323
|
+
forkAttemptTimeouts.set(sessionKey, timeoutId);
|
|
99324
|
+
}
|
|
99325
|
+
function getModelOverride(sessionKey) {
|
|
99326
|
+
return modelOverrides.get(sessionKey);
|
|
99327
|
+
}
|
|
99328
|
+
function clearModelOverride(sessionKey) {
|
|
99329
|
+
modelOverrides.delete(sessionKey);
|
|
99330
|
+
}
|
|
99275
99331
|
function getSessionError(sessionId) {
|
|
99276
99332
|
return sessionErrors.get(sessionId);
|
|
99277
99333
|
}
|
|
@@ -99308,19 +99364,26 @@ function migratePending(oldSessionId, newSessionId) {
|
|
|
99308
99364
|
pendingBySession.set(newSessionId, payload);
|
|
99309
99365
|
}
|
|
99310
99366
|
}
|
|
99311
|
-
function
|
|
99312
|
-
if (
|
|
99313
|
-
|
|
99314
|
-
|
|
99315
|
-
if (rawError && typeof rawError === "object") {
|
|
99316
|
-
const e = rawError;
|
|
99367
|
+
function extractErrorFields(error) {
|
|
99368
|
+
if (typeof error === "string") return [error];
|
|
99369
|
+
if (error && typeof error === "object") {
|
|
99370
|
+
const e = error;
|
|
99317
99371
|
const fields = [e.type, e.name, e.message].filter(Boolean).map(String);
|
|
99318
99372
|
if (e.data && typeof e.data === "object" && "message" in e.data) {
|
|
99319
99373
|
const dataMsg = e.data.message;
|
|
99320
99374
|
if (dataMsg) fields.push(String(dataMsg));
|
|
99321
99375
|
}
|
|
99322
|
-
return fields
|
|
99376
|
+
return fields;
|
|
99323
99377
|
}
|
|
99378
|
+
return [String(error)];
|
|
99379
|
+
}
|
|
99380
|
+
function isModelError(errMsg, rawError) {
|
|
99381
|
+
const check = (s) => {
|
|
99382
|
+
const l = s.toLowerCase();
|
|
99383
|
+
return l.includes("model not found") || l.includes("modelnotfound");
|
|
99384
|
+
};
|
|
99385
|
+
if (check(errMsg)) return true;
|
|
99386
|
+
if (rawError) return extractErrorFields(rawError).some(check);
|
|
99324
99387
|
return false;
|
|
99325
99388
|
}
|
|
99326
99389
|
async function handleEvent(event, deps) {
|
|
@@ -99363,35 +99426,50 @@ async function handleEvent(event, deps) {
|
|
|
99363
99426
|
} else {
|
|
99364
99427
|
errMsg = String(error);
|
|
99365
99428
|
}
|
|
99366
|
-
|
|
99367
|
-
type: error.type,
|
|
99368
|
-
name: error.name,
|
|
99369
|
-
dataMessage: error.data?.message
|
|
99370
|
-
} : { raw: String(error) };
|
|
99371
|
-
deps.log("warn", "\u6536\u5230 session.error \u4E8B\u4EF6", {
|
|
99372
|
-
sessionId,
|
|
99373
|
-
error: safeErrorFields,
|
|
99374
|
-
extractedMsg: errMsg
|
|
99375
|
-
});
|
|
99429
|
+
deps.log("warn", "\u6536\u5230 session.error \u4E8B\u4EF6", { sessionId, errMsg });
|
|
99376
99430
|
setSessionError(sessionId, errMsg);
|
|
99377
99431
|
if (isModelError(errMsg, props.error)) {
|
|
99378
99432
|
const sessionKey = invalidateCachedSession(sessionId);
|
|
99379
99433
|
if (sessionKey) {
|
|
99380
|
-
|
|
99381
|
-
|
|
99382
|
-
|
|
99383
|
-
|
|
99384
|
-
|
|
99385
|
-
|
|
99386
|
-
sessionKey
|
|
99387
|
-
|
|
99388
|
-
|
|
99389
|
-
|
|
99390
|
-
|
|
99391
|
-
|
|
99392
|
-
|
|
99393
|
-
|
|
99394
|
-
|
|
99434
|
+
const attempts = forkAttempts.get(sessionKey) ?? 0;
|
|
99435
|
+
if (attempts >= MAX_FORK_ATTEMPTS) {
|
|
99436
|
+
deps.log("warn", "\u5DF2\u8FBE fork \u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey: maskKey(sessionKey), attempts });
|
|
99437
|
+
} else {
|
|
99438
|
+
setForkAttempts(sessionKey, attempts + 1);
|
|
99439
|
+
try {
|
|
99440
|
+
const newSession = await forkOrCreateSession(deps.client, sessionId, sessionKey, deps.directory, deps.log);
|
|
99441
|
+
setCachedSession(sessionKey, newSession);
|
|
99442
|
+
modelOverrides.delete(sessionKey);
|
|
99443
|
+
try {
|
|
99444
|
+
const fallbackModel = await resolveLatestModel(deps.client, props.error ?? errMsg, deps.directory);
|
|
99445
|
+
if (fallbackModel) {
|
|
99446
|
+
modelOverrides.set(sessionKey, fallbackModel);
|
|
99447
|
+
deps.log("info", "\u5DF2\u89E3\u6790\u964D\u7EA7\u6A21\u578B", {
|
|
99448
|
+
sessionKey: maskKey(sessionKey),
|
|
99449
|
+
providerID: fallbackModel.providerID,
|
|
99450
|
+
modelID: fallbackModel.modelID
|
|
99451
|
+
});
|
|
99452
|
+
}
|
|
99453
|
+
} catch (modelErr) {
|
|
99454
|
+
deps.log("warn", "\u89E3\u6790\u964D\u7EA7\u6A21\u578B\u5931\u8D25\uFF0C\u5C06\u4F7F\u7528\u9ED8\u8BA4\u6A21\u578B", {
|
|
99455
|
+
sessionKey: maskKey(sessionKey),
|
|
99456
|
+
error: modelErr instanceof Error ? modelErr.message : String(modelErr)
|
|
99457
|
+
});
|
|
99458
|
+
}
|
|
99459
|
+
deps.log("warn", "\u6A21\u578B\u4E0D\u517C\u5BB9\uFF0C\u5DF2\u6062\u590D\u4F1A\u8BDD", {
|
|
99460
|
+
oldSessionId: sessionId,
|
|
99461
|
+
newSessionId: newSession.id,
|
|
99462
|
+
sessionKey: maskKey(sessionKey),
|
|
99463
|
+
forkAttempt: attempts + 1
|
|
99464
|
+
});
|
|
99465
|
+
migratePending(sessionId, newSession.id);
|
|
99466
|
+
} catch (recoverErr) {
|
|
99467
|
+
deps.log("error", "\u4F1A\u8BDD\u6062\u590D\u5931\u8D25", {
|
|
99468
|
+
sessionId,
|
|
99469
|
+
sessionKey: maskKey(sessionKey),
|
|
99470
|
+
error: recoverErr instanceof Error ? recoverErr.message : String(recoverErr)
|
|
99471
|
+
});
|
|
99472
|
+
}
|
|
99395
99473
|
}
|
|
99396
99474
|
}
|
|
99397
99475
|
}
|
|
@@ -99399,6 +99477,26 @@ async function handleEvent(event, deps) {
|
|
|
99399
99477
|
}
|
|
99400
99478
|
}
|
|
99401
99479
|
}
|
|
99480
|
+
async function resolveLatestModel(client, rawError, directory) {
|
|
99481
|
+
const pattern = /model not found:?\s*(\w[\w-]*)\//i;
|
|
99482
|
+
const fields = extractErrorFields(rawError);
|
|
99483
|
+
const rawProviderID = fields.map((f) => pattern.exec(f)?.[1]).find(Boolean);
|
|
99484
|
+
if (!rawProviderID) return void 0;
|
|
99485
|
+
const providerID = rawProviderID.toLowerCase();
|
|
99486
|
+
const query = directory ? { directory } : void 0;
|
|
99487
|
+
const { data } = await client.provider.list({ query });
|
|
99488
|
+
if (!data) return void 0;
|
|
99489
|
+
const defaultModelID = data.default?.[providerID];
|
|
99490
|
+
if (defaultModelID) {
|
|
99491
|
+
return { providerID, modelID: defaultModelID };
|
|
99492
|
+
}
|
|
99493
|
+
const provider = data.all?.find((p) => p.id === providerID);
|
|
99494
|
+
if (!provider?.models) return void 0;
|
|
99495
|
+
const sortedModels = Object.values(provider.models).filter((m) => m.status !== "deprecated").sort((a, b) => b.release_date.localeCompare(a.release_date));
|
|
99496
|
+
if (sortedModels.length === 0) return void 0;
|
|
99497
|
+
const best = sortedModels.find((m) => m.tool_call) ?? sortedModels[0];
|
|
99498
|
+
return { providerID, modelID: best.id };
|
|
99499
|
+
}
|
|
99402
99500
|
function extractPartText(part) {
|
|
99403
99501
|
if (part.type === "text") return part.text ?? "";
|
|
99404
99502
|
if (part.type === "reasoning" && part.text) return `\u{1F914} \u601D\u8003: ${part.text}
|
|
@@ -99434,12 +99532,14 @@ async function handleChat(ctx, deps) {
|
|
|
99434
99532
|
shouldReply,
|
|
99435
99533
|
parts
|
|
99436
99534
|
});
|
|
99535
|
+
const modelOverride = getModelOverride(sessionKey);
|
|
99536
|
+
const baseBody = { parts, ...modelOverride ? { model: modelOverride } : {} };
|
|
99437
99537
|
if (!shouldReply) {
|
|
99438
99538
|
try {
|
|
99439
99539
|
await client.session.prompt({
|
|
99440
99540
|
path: { id: session.id },
|
|
99441
99541
|
query,
|
|
99442
|
-
body: {
|
|
99542
|
+
body: { ...baseBody, noReply: true }
|
|
99443
99543
|
});
|
|
99444
99544
|
} catch (err) {
|
|
99445
99545
|
log("warn", "\u9759\u9ED8\u8F6C\u53D1\u5931\u8D25", {
|
|
@@ -99474,9 +99574,11 @@ async function handleChat(ctx, deps) {
|
|
|
99474
99574
|
await client.session.prompt({
|
|
99475
99575
|
path: { id: session.id },
|
|
99476
99576
|
query,
|
|
99477
|
-
body:
|
|
99577
|
+
body: baseBody
|
|
99478
99578
|
});
|
|
99479
99579
|
const finalText = await pollForResponse(client, session.id, { timeout, pollInterval, stablePolls, query });
|
|
99580
|
+
clearForkAttempts(sessionKey);
|
|
99581
|
+
clearModelOverride(sessionKey);
|
|
99480
99582
|
await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
|
|
99481
99583
|
const { autoPrompt } = config;
|
|
99482
99584
|
if (autoPrompt.enabled && shouldReply) {
|
|
@@ -99522,7 +99624,7 @@ async function handleChat(ctx, deps) {
|
|
|
99522
99624
|
sessionKey: sessionKey.replace(/-[^-]+$/, "-***"),
|
|
99523
99625
|
chatType,
|
|
99524
99626
|
error: thrownError,
|
|
99525
|
-
...sessionError ? { sessionError } : {}
|
|
99627
|
+
...sessionError ? { sessionError } : { sseRaceMiss: true }
|
|
99526
99628
|
});
|
|
99527
99629
|
const msg = "\u274C " + errorMessage;
|
|
99528
99630
|
await replyOrUpdate(feishuClient, chatId, placeholderId, msg);
|