opencode-feishu 0.7.8 → 0.7.10

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
@@ -99181,30 +99181,30 @@ var pendingBySession = /* @__PURE__ */ new Map();
99181
99181
  var sessionErrors = /* @__PURE__ */ new Map();
99182
99182
  var sessionErrorTimeouts = /* @__PURE__ */ new Map();
99183
99183
  var SESSION_ERROR_TTL_MS = 3e4;
99184
- var forkAttempts = /* @__PURE__ */ new Map();
99185
- var forkAttemptTimeouts = /* @__PURE__ */ new Map();
99186
- var MAX_FORK_ATTEMPTS = 2;
99187
- var FORK_ATTEMPTS_TTL_MS = 36e5;
99188
- function clearForkAttempts(sessionKey) {
99189
- forkAttempts.delete(sessionKey);
99190
- const timer = forkAttemptTimeouts.get(sessionKey);
99184
+ var retryAttempts = /* @__PURE__ */ new Map();
99185
+ var retryAttemptTimeouts = /* @__PURE__ */ new Map();
99186
+ var MAX_RETRY_ATTEMPTS = 2;
99187
+ var RETRY_ATTEMPTS_TTL_MS = 36e5;
99188
+ function clearRetryAttempts(sessionKey) {
99189
+ retryAttempts.delete(sessionKey);
99190
+ const timer = retryAttemptTimeouts.get(sessionKey);
99191
99191
  if (timer) {
99192
99192
  clearTimeout(timer);
99193
- forkAttemptTimeouts.delete(sessionKey);
99193
+ retryAttemptTimeouts.delete(sessionKey);
99194
99194
  }
99195
99195
  }
99196
- function getForkAttempts(sessionKey) {
99197
- return forkAttempts.get(sessionKey) ?? 0;
99196
+ function getRetryAttempts(sessionKey) {
99197
+ return retryAttempts.get(sessionKey) ?? 0;
99198
99198
  }
99199
- function setForkAttempts(sessionKey, count) {
99200
- forkAttempts.set(sessionKey, count);
99201
- const existing = forkAttemptTimeouts.get(sessionKey);
99199
+ function setRetryAttempts(sessionKey, count) {
99200
+ retryAttempts.set(sessionKey, count);
99201
+ const existing = retryAttemptTimeouts.get(sessionKey);
99202
99202
  if (existing) clearTimeout(existing);
99203
99203
  const timeoutId = setTimeout(() => {
99204
- forkAttempts.delete(sessionKey);
99205
- forkAttemptTimeouts.delete(sessionKey);
99206
- }, FORK_ATTEMPTS_TTL_MS);
99207
- forkAttemptTimeouts.set(sessionKey, timeoutId);
99204
+ retryAttempts.delete(sessionKey);
99205
+ retryAttemptTimeouts.delete(sessionKey);
99206
+ }, RETRY_ATTEMPTS_TTL_MS);
99207
+ retryAttemptTimeouts.set(sessionKey, timeoutId);
99208
99208
  }
99209
99209
  function getSessionError(sessionId) {
99210
99210
  return sessionErrors.get(sessionId);
@@ -99314,22 +99314,8 @@ function extractPartText(part) {
99314
99314
  var SESSION_KEY_PREFIX = "feishu";
99315
99315
  var TITLE_PREFIX = "Feishu";
99316
99316
  var sessionCache = /* @__PURE__ */ new Map();
99317
- var sessionIdToKeyCache = /* @__PURE__ */ new Map();
99318
99317
  function setCachedSession(sessionKey, session) {
99319
- const oldSession = sessionCache.get(sessionKey);
99320
- if (oldSession && oldSession.id !== session.id) {
99321
- sessionIdToKeyCache.delete(oldSession.id);
99322
- }
99323
99318
  sessionCache.set(sessionKey, session);
99324
- sessionIdToKeyCache.set(session.id, sessionKey);
99325
- }
99326
- function invalidateCachedSession(sessionId) {
99327
- const sessionKey = sessionIdToKeyCache.get(sessionId);
99328
- if (sessionKey) {
99329
- sessionCache.delete(sessionKey);
99330
- sessionIdToKeyCache.delete(sessionId);
99331
- }
99332
- return sessionKey;
99333
99319
  }
99334
99320
  function buildSessionKey(chatType, id) {
99335
99321
  return `${SESSION_KEY_PREFIX}-${chatType}-${id}`;
@@ -99373,57 +99359,6 @@ async function getOrCreateSession(client, sessionKey, directory) {
99373
99359
  setCachedSession(sessionKey, session);
99374
99360
  return session;
99375
99361
  }
99376
- async function forkSession(client, oldSessionId, sessionKey, directory) {
99377
- const query = directory ? { directory } : void 0;
99378
- const resp = await client.session.fork({
99379
- path: { id: oldSessionId },
99380
- query,
99381
- body: {}
99382
- });
99383
- if (!resp?.data?.id) {
99384
- const err = resp?.error;
99385
- throw new Error(
99386
- `Fork \u4F1A\u8BDD\u5931\u8D25: ${err ? JSON.stringify(err) : "unknown"}`
99387
- );
99388
- }
99389
- const title = generateSessionTitle(sessionKey);
99390
- const updateResp = await client.session.update({
99391
- path: { id: resp.data.id },
99392
- query,
99393
- body: { title }
99394
- });
99395
- if (!updateResp?.data?.id) {
99396
- const err = updateResp?.error;
99397
- throw new Error(
99398
- `\u66F4\u65B0 forked session \u6807\u9898\u5931\u8D25: ${err ? JSON.stringify(err) : "unknown"}`
99399
- );
99400
- }
99401
- return { id: resp.data.id, title };
99402
- }
99403
- async function createFreshSession(client, sessionKey, directory) {
99404
- const query = directory ? { directory } : void 0;
99405
- const title = generateSessionTitle(sessionKey);
99406
- const resp = await client.session.create({ query, body: { title } });
99407
- if (!resp?.data?.id) {
99408
- const err = resp?.error;
99409
- throw new Error(
99410
- `\u521B\u5EFA\u65B0\u4F1A\u8BDD\u5931\u8D25: ${err ? JSON.stringify(err) : "unknown"}`
99411
- );
99412
- }
99413
- return { id: resp.data.id, title: resp.data.title };
99414
- }
99415
- async function forkOrCreateSession(client, oldSessionId, sessionKey, directory, log) {
99416
- try {
99417
- return await forkSession(client, oldSessionId, sessionKey, directory);
99418
- } catch (forkErr) {
99419
- log?.("warn", "Fork \u5931\u8D25\uFF0C\u56DE\u9000\u5230\u521B\u5EFA\u65B0\u4F1A\u8BDD", {
99420
- oldSessionId,
99421
- sessionKey,
99422
- error: forkErr instanceof Error ? forkErr.message : String(forkErr)
99423
- });
99424
- return await createFreshSession(client, sessionKey, directory);
99425
- }
99426
- }
99427
99362
 
99428
99363
  // src/handler/chat.ts
99429
99364
  var SSE_RACE_WAIT_MS = 100;
@@ -99542,7 +99477,7 @@ async function handleChat(ctx, deps) {
99542
99477
  sessionId: session.id,
99543
99478
  output: finalText || "(empty)"
99544
99479
  });
99545
- clearForkAttempts(sessionKey);
99480
+ clearRetryAttempts(sessionKey);
99546
99481
  await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99547
99482
  await runAutoPromptLoop(session.id);
99548
99483
  } catch (err) {
@@ -99557,61 +99492,46 @@ async function handleChat(ctx, deps) {
99557
99492
  }
99558
99493
  }
99559
99494
  if (sessionError && isModelError(sessionError.fields)) {
99560
- const attempts = getForkAttempts(sessionKey);
99561
- if (attempts < MAX_FORK_ATTEMPTS) {
99562
- setForkAttempts(sessionKey, attempts + 1);
99495
+ const attempts = getRetryAttempts(sessionKey);
99496
+ if (attempts < MAX_RETRY_ATTEMPTS) {
99563
99497
  try {
99564
- invalidateCachedSession(session.id);
99565
- const newSession = await forkOrCreateSession(client, session.id, sessionKey, directory, log);
99566
- setCachedSession(sessionKey, newSession);
99567
- activeSessionId = newSession.id;
99568
- let modelOverride;
99569
- try {
99570
- modelOverride = await resolveLatestModel(client, sessionError.fields, directory);
99571
- if (modelOverride) {
99572
- log("info", "\u5DF2\u89E3\u6790\u964D\u7EA7\u6A21\u578B", {
99573
- sessionKey,
99574
- providerID: modelOverride.providerID,
99575
- modelID: modelOverride.modelID
99576
- });
99577
- }
99578
- } catch (modelErr) {
99579
- log("warn", "\u89E3\u6790\u964D\u7EA7\u6A21\u578B\u5931\u8D25\uFF0C\u5C06\u4F7F\u7528\u9ED8\u8BA4\u6A21\u578B", {
99498
+ const modelOverride = await resolveLatestModel(client, sessionError.fields, directory);
99499
+ if (!modelOverride) {
99500
+ log("warn", "\u65E0\u4EFB\u4F55\u5DF2\u8FDE\u63A5 provider \u6709\u53EF\u7528\u6A21\u578B\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey });
99501
+ } else {
99502
+ setRetryAttempts(sessionKey, attempts + 1);
99503
+ log("info", "\u5DF2\u89E3\u6790\u53EF\u7528\u6A21\u578B\uFF0C\u5728\u540C\u4E00 session \u4E0A\u91CD\u8BD5", {
99580
99504
  sessionKey,
99581
- error: modelErr instanceof Error ? modelErr.message : String(modelErr)
99505
+ providerID: modelOverride.providerID,
99506
+ modelID: modelOverride.modelID
99582
99507
  });
99508
+ await client.session.prompt({
99509
+ path: { id: session.id },
99510
+ query,
99511
+ body: { ...baseBody, model: modelOverride }
99512
+ });
99513
+ const finalText = await pollForResponse(client, session.id, { timeout, pollInterval, stablePolls, query });
99514
+ log("info", "\u6A21\u578B\u6062\u590D\u540E\u54CD\u5E94\u5B8C\u6210", {
99515
+ sessionKey,
99516
+ sessionId: session.id,
99517
+ output: finalText || "(empty)"
99518
+ });
99519
+ clearRetryAttempts(sessionKey);
99520
+ await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99521
+ log("info", "\u6A21\u578B\u4E0D\u517C\u5BB9\u6062\u590D\u6210\u529F", {
99522
+ sessionId: session.id,
99523
+ sessionKey,
99524
+ model: `${modelOverride.providerID}/${modelOverride.modelID}`,
99525
+ attempt: attempts + 1
99526
+ });
99527
+ await runAutoPromptLoop(session.id);
99528
+ return;
99583
99529
  }
99584
- unregisterPending(session.id);
99585
- if (placeholderId) {
99586
- registerPending(newSession.id, { chatId, placeholderId, feishuClient });
99587
- }
99588
- const retryBody = { ...baseBody, ...modelOverride ? { model: modelOverride } : {} };
99589
- await client.session.prompt({
99590
- path: { id: newSession.id },
99591
- query,
99592
- body: retryBody
99593
- });
99594
- const finalText = await pollForResponse(client, newSession.id, { timeout, pollInterval, stablePolls, query });
99595
- log("info", "\u6062\u590D\u540E\u6A21\u578B\u54CD\u5E94\u5B8C\u6210", {
99596
- sessionKey,
99597
- newSessionId: newSession.id,
99598
- output: finalText || "(empty)"
99599
- });
99600
- clearForkAttempts(sessionKey);
99601
- await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99602
- log("info", "\u6A21\u578B\u4E0D\u517C\u5BB9\u6062\u590D\u6210\u529F", {
99603
- oldSessionId: session.id,
99604
- newSessionId: newSession.id,
99605
- sessionKey,
99606
- forkAttempt: attempts + 1
99607
- });
99608
- await runAutoPromptLoop(newSession.id);
99609
- return;
99610
99530
  } catch (recoveryErr) {
99611
99531
  const recoveryErrMsg = recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr);
99612
- const newSessionError = activeSessionId !== session.id ? getSessionError(activeSessionId) : void 0;
99613
- if (newSessionError) clearSessionError(activeSessionId);
99614
- sessionError = newSessionError ?? { message: recoveryErrMsg, fields: [] };
99532
+ const retryError = getSessionError(session.id);
99533
+ if (retryError) clearSessionError(session.id);
99534
+ sessionError = retryError ?? { message: recoveryErrMsg, fields: [] };
99615
99535
  log("error", "\u6A21\u578B\u6062\u590D\u5931\u8D25", {
99616
99536
  sessionId: session.id,
99617
99537
  sessionKey,
@@ -99619,7 +99539,7 @@ async function handleChat(ctx, deps) {
99619
99539
  });
99620
99540
  }
99621
99541
  } else {
99622
- log("warn", "\u5DF2\u8FBE fork \u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", {
99542
+ log("warn", "\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", {
99623
99543
  sessionKey,
99624
99544
  attempts
99625
99545
  });
@@ -99643,23 +99563,31 @@ async function handleChat(ctx, deps) {
99643
99563
  }
99644
99564
  }
99645
99565
  async function resolveLatestModel(client, errorFields, directory) {
99646
- const pattern = /model not found:?\s*(\w[\w-]*)\//i;
99647
- const rawProviderID = errorFields.map((f) => pattern.exec(f)?.[1]).find(Boolean);
99648
- if (!rawProviderID) return void 0;
99649
- const providerID = rawProviderID.toLowerCase();
99566
+ const pattern = /model\s*not\s*found:?\s*(\w[\w-]*)\/(\S+)/i;
99567
+ const match = errorFields.map((f) => pattern.exec(f)).find(Boolean);
99568
+ const failedProviderID = match?.[1]?.toLowerCase();
99569
+ const failedModelID = match?.[2]?.replace(/\.$/, "");
99650
99570
  const query = directory ? { directory } : void 0;
99651
99571
  const { data } = await client.provider.list({ query });
99652
99572
  if (!data) return void 0;
99653
- const defaultModelID = data.default?.[providerID];
99654
- if (defaultModelID) {
99655
- return { providerID, modelID: defaultModelID };
99573
+ const connectedProviders = data.connected ?? [];
99574
+ if (connectedProviders.length === 0) return void 0;
99575
+ for (const pid of connectedProviders) {
99576
+ const defaultModelID = data.default?.[pid];
99577
+ if (defaultModelID && !(pid === failedProviderID && defaultModelID === failedModelID)) {
99578
+ return { providerID: pid, modelID: defaultModelID };
99579
+ }
99580
+ }
99581
+ for (const pid of connectedProviders) {
99582
+ const provider = data.all?.find((p) => p.id === pid);
99583
+ if (!provider?.models) continue;
99584
+ const candidates = Object.values(provider.models).filter((m) => m.status !== "deprecated" && !(pid === failedProviderID && m.id === failedModelID)).sort((a, b) => b.release_date.localeCompare(a.release_date));
99585
+ if (candidates.length > 0) {
99586
+ const best = candidates.find((m) => m.tool_call) ?? candidates[0];
99587
+ return { providerID: pid, modelID: best.id };
99588
+ }
99656
99589
  }
99657
- const provider = data.all?.find((p) => p.id === providerID);
99658
- if (!provider?.models) return void 0;
99659
- const sortedModels = Object.values(provider.models).filter((m) => m.status !== "deprecated").sort((a, b) => b.release_date.localeCompare(a.release_date));
99660
- if (sortedModels.length === 0) return void 0;
99661
- const best = sortedModels.find((m) => m.tool_call) ?? sortedModels[0];
99662
- return { providerID, modelID: best.id };
99590
+ return void 0;
99663
99591
  }
99664
99592
  async function buildPromptParts(feishuClient, messageId, messageType, rawContent, textContent, chatType, senderId, log) {
99665
99593
  if (messageType === "text") {
@@ -99932,7 +99860,7 @@ var FeishuPlugin = async (ctx) => {
99932
99860
  const hooks = {
99933
99861
  event: async ({ event }) => {
99934
99862
  if (!gateway) return;
99935
- await handleEvent(event, { client, log, directory: resolvedConfig.directory });
99863
+ await handleEvent(event, { log, directory: resolvedConfig.directory });
99936
99864
  }
99937
99865
  };
99938
99866
  return hooks;