opencode-feishu 0.7.5 → 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 CHANGED
@@ -99292,10 +99292,14 @@ async function forkOrCreateSession(client, oldSessionId, sessionKey, directory,
99292
99292
  }
99293
99293
 
99294
99294
  // src/handler/event.ts
99295
+ function maskKey(sessionKey) {
99296
+ return sessionKey.replace(/-[^-]+$/, "-***");
99297
+ }
99295
99298
  var pendingBySession = /* @__PURE__ */ new Map();
99296
99299
  var sessionErrors = /* @__PURE__ */ new Map();
99297
99300
  var sessionErrorTimeouts = /* @__PURE__ */ new Map();
99298
99301
  var SESSION_ERROR_TTL_MS = 3e4;
99302
+ var modelOverrides = /* @__PURE__ */ new Map();
99299
99303
  var forkAttempts = /* @__PURE__ */ new Map();
99300
99304
  var forkAttemptTimeouts = /* @__PURE__ */ new Map();
99301
99305
  var MAX_FORK_ATTEMPTS = 2;
@@ -99318,6 +99322,12 @@ function setForkAttempts(sessionKey, count) {
99318
99322
  }, FORK_ATTEMPTS_TTL_MS);
99319
99323
  forkAttemptTimeouts.set(sessionKey, timeoutId);
99320
99324
  }
99325
+ function getModelOverride(sessionKey) {
99326
+ return modelOverrides.get(sessionKey);
99327
+ }
99328
+ function clearModelOverride(sessionKey) {
99329
+ modelOverrides.delete(sessionKey);
99330
+ }
99321
99331
  function getSessionError(sessionId) {
99322
99332
  return sessionErrors.get(sessionId);
99323
99333
  }
@@ -99354,19 +99364,26 @@ function migratePending(oldSessionId, newSessionId) {
99354
99364
  pendingBySession.set(newSessionId, payload);
99355
99365
  }
99356
99366
  }
99357
- function isModelError(errMsg, rawError) {
99358
- if (errMsg.includes("ModelNotFound") || errMsg.includes("ProviderModelNotFound")) {
99359
- return true;
99360
- }
99361
- if (rawError && typeof rawError === "object") {
99362
- const e = rawError;
99367
+ function extractErrorFields(error) {
99368
+ if (typeof error === "string") return [error];
99369
+ if (error && typeof error === "object") {
99370
+ const e = error;
99363
99371
  const fields = [e.type, e.name, e.message].filter(Boolean).map(String);
99364
99372
  if (e.data && typeof e.data === "object" && "message" in e.data) {
99365
99373
  const dataMsg = e.data.message;
99366
99374
  if (dataMsg) fields.push(String(dataMsg));
99367
99375
  }
99368
- return fields.some((f) => f.includes("ModelNotFound") || f.includes("ProviderModelNotFound"));
99376
+ return fields;
99369
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);
99370
99387
  return false;
99371
99388
  }
99372
99389
  async function handleEvent(event, deps) {
@@ -99409,39 +99426,47 @@ async function handleEvent(event, deps) {
99409
99426
  } else {
99410
99427
  errMsg = String(error);
99411
99428
  }
99412
- const safeErrorFields = error && typeof error === "object" ? {
99413
- type: error.type,
99414
- name: error.name,
99415
- dataMessage: error.data?.message
99416
- } : { raw: String(error) };
99417
- deps.log("warn", "\u6536\u5230 session.error \u4E8B\u4EF6", {
99418
- sessionId,
99419
- error: safeErrorFields,
99420
- extractedMsg: errMsg
99421
- });
99429
+ deps.log("warn", "\u6536\u5230 session.error \u4E8B\u4EF6", { sessionId, errMsg });
99422
99430
  setSessionError(sessionId, errMsg);
99423
99431
  if (isModelError(errMsg, props.error)) {
99424
99432
  const sessionKey = invalidateCachedSession(sessionId);
99425
99433
  if (sessionKey) {
99426
99434
  const attempts = forkAttempts.get(sessionKey) ?? 0;
99427
99435
  if (attempts >= MAX_FORK_ATTEMPTS) {
99428
- deps.log("warn", "\u5DF2\u8FBE fork \u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey, attempts });
99436
+ deps.log("warn", "\u5DF2\u8FBE fork \u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey: maskKey(sessionKey), attempts });
99429
99437
  } else {
99430
99438
  setForkAttempts(sessionKey, attempts + 1);
99431
99439
  try {
99432
99440
  const newSession = await forkOrCreateSession(deps.client, sessionId, sessionKey, deps.directory, deps.log);
99433
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
+ }
99434
99459
  deps.log("warn", "\u6A21\u578B\u4E0D\u517C\u5BB9\uFF0C\u5DF2\u6062\u590D\u4F1A\u8BDD", {
99435
99460
  oldSessionId: sessionId,
99436
99461
  newSessionId: newSession.id,
99437
- sessionKey,
99462
+ sessionKey: maskKey(sessionKey),
99438
99463
  forkAttempt: attempts + 1
99439
99464
  });
99440
99465
  migratePending(sessionId, newSession.id);
99441
99466
  } catch (recoverErr) {
99442
99467
  deps.log("error", "\u4F1A\u8BDD\u6062\u590D\u5931\u8D25", {
99443
99468
  sessionId,
99444
- sessionKey,
99469
+ sessionKey: maskKey(sessionKey),
99445
99470
  error: recoverErr instanceof Error ? recoverErr.message : String(recoverErr)
99446
99471
  });
99447
99472
  }
@@ -99452,6 +99477,26 @@ async function handleEvent(event, deps) {
99452
99477
  }
99453
99478
  }
99454
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
+ }
99455
99500
  function extractPartText(part) {
99456
99501
  if (part.type === "text") return part.text ?? "";
99457
99502
  if (part.type === "reasoning" && part.text) return `\u{1F914} \u601D\u8003: ${part.text}
@@ -99487,12 +99532,14 @@ async function handleChat(ctx, deps) {
99487
99532
  shouldReply,
99488
99533
  parts
99489
99534
  });
99535
+ const modelOverride = getModelOverride(sessionKey);
99536
+ const baseBody = { parts, ...modelOverride ? { model: modelOverride } : {} };
99490
99537
  if (!shouldReply) {
99491
99538
  try {
99492
99539
  await client.session.prompt({
99493
99540
  path: { id: session.id },
99494
99541
  query,
99495
- body: { parts, noReply: true }
99542
+ body: { ...baseBody, noReply: true }
99496
99543
  });
99497
99544
  } catch (err) {
99498
99545
  log("warn", "\u9759\u9ED8\u8F6C\u53D1\u5931\u8D25", {
@@ -99527,10 +99574,11 @@ async function handleChat(ctx, deps) {
99527
99574
  await client.session.prompt({
99528
99575
  path: { id: session.id },
99529
99576
  query,
99530
- body: { parts }
99577
+ body: baseBody
99531
99578
  });
99532
99579
  const finalText = await pollForResponse(client, session.id, { timeout, pollInterval, stablePolls, query });
99533
99580
  clearForkAttempts(sessionKey);
99581
+ clearModelOverride(sessionKey);
99534
99582
  await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99535
99583
  const { autoPrompt } = config;
99536
99584
  if (autoPrompt.enabled && shouldReply) {