opencode-feishu 0.7.8 → 0.7.11

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);
@@ -99249,11 +99249,11 @@ function extractErrorFields(error) {
99249
99249
  return [String(error)];
99250
99250
  }
99251
99251
  function isModelError(fields) {
99252
- const check = (s) => {
99253
- const l = s.toLowerCase();
99254
- return l.includes("model not found") || l.includes("modelnotfound");
99255
- };
99256
- return fields.some(check);
99252
+ const patterns = ["model not found", "modelnotfound", "model not supported", "model_not_supported"];
99253
+ return fields.some((f) => {
99254
+ const l = f.toLowerCase();
99255
+ return patterns.some((p) => l.includes(p));
99256
+ });
99257
99257
  }
99258
99258
  async function handleEvent(event, deps) {
99259
99259
  switch (event.type) {
@@ -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;
@@ -99501,6 +99436,7 @@ async function handleChat(ctx, deps) {
99501
99436
  for (let i = 0; i < autoPrompt.maxIterations; i++) {
99502
99437
  await abortableSleep(autoPrompt.intervalSeconds * 1e3, ac.signal);
99503
99438
  log("info", "\u53D1\u9001\u81EA\u52A8\u63D0\u793A", { sessionKey, iteration: i + 1 });
99439
+ clearSessionError(activeId);
99504
99440
  await client.session.prompt({
99505
99441
  path: { id: activeId },
99506
99442
  query,
@@ -99531,6 +99467,7 @@ async function handleChat(ctx, deps) {
99531
99467
  }
99532
99468
  }
99533
99469
  try {
99470
+ clearSessionError(session.id);
99534
99471
  await client.session.prompt({
99535
99472
  path: { id: session.id },
99536
99473
  query,
@@ -99542,84 +99479,95 @@ async function handleChat(ctx, deps) {
99542
99479
  sessionId: session.id,
99543
99480
  output: finalText || "(empty)"
99544
99481
  });
99545
- clearForkAttempts(sessionKey);
99482
+ clearRetryAttempts(sessionKey);
99546
99483
  await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99547
99484
  await runAutoPromptLoop(session.id);
99548
99485
  } catch (err) {
99549
- await new Promise((r) => setTimeout(r, SSE_RACE_WAIT_MS));
99550
- let sessionError = getSessionError(session.id);
99551
- clearSessionError(session.id);
99552
- if (!sessionError) {
99553
- const thrownFields = extractErrorFields(err);
99554
- if (isModelError(thrownFields)) {
99555
- const thrownMsg = err instanceof Error ? err.message : String(err);
99556
- sessionError = { message: thrownMsg, fields: thrownFields };
99486
+ let sessionError;
99487
+ if (err instanceof SessionErrorDetected) {
99488
+ sessionError = err.sessionError;
99489
+ clearSessionError(session.id);
99490
+ } else {
99491
+ await new Promise((r) => setTimeout(r, SSE_RACE_WAIT_MS));
99492
+ sessionError = getSessionError(session.id);
99493
+ clearSessionError(session.id);
99494
+ if (!sessionError) {
99495
+ const thrownFields = extractErrorFields(err);
99496
+ if (isModelError(thrownFields)) {
99497
+ const thrownMsg = err instanceof Error ? err.message : String(err);
99498
+ sessionError = { message: thrownMsg, fields: thrownFields };
99499
+ }
99557
99500
  }
99558
99501
  }
99559
99502
  if (sessionError && isModelError(sessionError.fields)) {
99560
- const attempts = getForkAttempts(sessionKey);
99561
- if (attempts < MAX_FORK_ATTEMPTS) {
99562
- setForkAttempts(sessionKey, attempts + 1);
99503
+ const attempts = getRetryAttempts(sessionKey);
99504
+ if (attempts < MAX_RETRY_ATTEMPTS) {
99563
99505
  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
99506
  let modelOverride;
99569
99507
  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", {
99508
+ modelOverride = await getGlobalDefaultModel(client, directory);
99509
+ } catch (configErr) {
99510
+ log("warn", "\u8BFB\u53D6\u5168\u5C40\u6A21\u578B\u914D\u7F6E\u5931\u8D25", {
99580
99511
  sessionKey,
99581
- error: modelErr instanceof Error ? modelErr.message : String(modelErr)
99512
+ error: configErr instanceof Error ? configErr.message : String(configErr)
99582
99513
  });
99583
99514
  }
99584
- unregisterPending(session.id);
99585
- if (placeholderId) {
99586
- registerPending(newSession.id, { chatId, placeholderId, feishuClient });
99515
+ if (!modelOverride) {
99516
+ log("warn", "\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u672A\u914D\u7F6E\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey });
99517
+ } else {
99518
+ setRetryAttempts(sessionKey, attempts + 1);
99519
+ log("info", "\u4F7F\u7528\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u6062\u590D", {
99520
+ sessionKey,
99521
+ providerID: modelOverride.providerID,
99522
+ modelID: modelOverride.modelID
99523
+ });
99524
+ clearSessionError(session.id);
99525
+ await client.session.prompt({
99526
+ path: { id: session.id },
99527
+ query,
99528
+ body: { ...baseBody, model: modelOverride }
99529
+ });
99530
+ const finalText = await pollForResponse(client, session.id, { timeout, pollInterval, stablePolls, query });
99531
+ log("info", "\u6A21\u578B\u6062\u590D\u540E\u54CD\u5E94\u5B8C\u6210", {
99532
+ sessionKey,
99533
+ sessionId: session.id,
99534
+ output: finalText || "(empty)"
99535
+ });
99536
+ clearRetryAttempts(sessionKey);
99537
+ await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99538
+ log("info", "\u6A21\u578B\u4E0D\u517C\u5BB9\u6062\u590D\u6210\u529F", {
99539
+ sessionId: session.id,
99540
+ sessionKey,
99541
+ model: `${modelOverride.providerID}/${modelOverride.modelID}`,
99542
+ attempt: attempts + 1
99543
+ });
99544
+ await runAutoPromptLoop(session.id);
99545
+ return;
99587
99546
  }
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
99547
  } catch (recoveryErr) {
99611
- 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: [] };
99548
+ const errMsg = recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr);
99549
+ if (recoveryErr instanceof SessionErrorDetected) {
99550
+ sessionError = recoveryErr.sessionError;
99551
+ clearSessionError(session.id);
99552
+ } else {
99553
+ await new Promise((r) => setTimeout(r, SSE_RACE_WAIT_MS));
99554
+ const sseError = getSessionError(session.id);
99555
+ if (sseError) {
99556
+ sessionError = sseError;
99557
+ clearSessionError(session.id);
99558
+ } else {
99559
+ const thrownFields = extractErrorFields(recoveryErr);
99560
+ sessionError = { message: errMsg, fields: thrownFields };
99561
+ }
99562
+ }
99615
99563
  log("error", "\u6A21\u578B\u6062\u590D\u5931\u8D25", {
99616
99564
  sessionId: session.id,
99617
99565
  sessionKey,
99618
- error: recoveryErrMsg
99566
+ error: errMsg
99619
99567
  });
99620
99568
  }
99621
99569
  } else {
99622
- log("warn", "\u5DF2\u8FBE fork \u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", {
99570
+ log("warn", "\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", {
99623
99571
  sessionKey,
99624
99572
  attempts
99625
99573
  });
@@ -99642,24 +99590,16 @@ async function handleChat(ctx, deps) {
99642
99590
  unregisterPending(activeSessionId);
99643
99591
  }
99644
99592
  }
99645
- 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();
99593
+ async function getGlobalDefaultModel(client, directory) {
99650
99594
  const query = directory ? { directory } : void 0;
99651
- const { data } = await client.provider.list({ query });
99652
- if (!data) return void 0;
99653
- const defaultModelID = data.default?.[providerID];
99654
- if (defaultModelID) {
99655
- return { providerID, modelID: defaultModelID };
99656
- }
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 };
99595
+ const { data: config } = await client.config.get({ query });
99596
+ const model = config?.model;
99597
+ if (!model || !model.includes("/")) return void 0;
99598
+ const slash = model.indexOf("/");
99599
+ const providerID = model.slice(0, slash).trim();
99600
+ const modelID = model.slice(slash + 1).trim();
99601
+ if (!providerID || !modelID) return void 0;
99602
+ return { providerID, modelID };
99663
99603
  }
99664
99604
  async function buildPromptParts(feishuClient, messageId, messageType, rawContent, textContent, chatType, senderId, log) {
99665
99605
  if (messageType === "text") {
@@ -99675,6 +99615,13 @@ async function buildPromptParts(feishuClient, messageId, messageType, rawContent
99675
99615
  }
99676
99616
  return parts;
99677
99617
  }
99618
+ var SessionErrorDetected = class extends Error {
99619
+ constructor(sessionError) {
99620
+ super(sessionError.message);
99621
+ this.sessionError = sessionError;
99622
+ this.name = "SessionErrorDetected";
99623
+ }
99624
+ };
99678
99625
  async function pollForResponse(client, sessionId, opts) {
99679
99626
  const { timeout, pollInterval, stablePolls, query, signal } = opts;
99680
99627
  const start = Date.now();
@@ -99686,6 +99633,10 @@ async function pollForResponse(client, sessionId, opts) {
99686
99633
  } else {
99687
99634
  await new Promise((r) => setTimeout(r, pollInterval));
99688
99635
  }
99636
+ const sseError = getSessionError(sessionId);
99637
+ if (sseError) {
99638
+ throw new SessionErrorDetected(sseError);
99639
+ }
99689
99640
  const { data: messages } = await client.session.messages({ path: { id: sessionId }, query });
99690
99641
  const text2 = extractLastAssistantText(messages ?? []);
99691
99642
  if (text2 && text2 !== lastText) {
@@ -99696,6 +99647,10 @@ async function pollForResponse(client, sessionId, opts) {
99696
99647
  if (sameCount >= stablePolls) break;
99697
99648
  }
99698
99649
  }
99650
+ const finalSseError = getSessionError(sessionId);
99651
+ if (finalSseError) {
99652
+ throw new SessionErrorDetected(finalSseError);
99653
+ }
99699
99654
  const { data: finalMessages } = await client.session.messages({ path: { id: sessionId }, query });
99700
99655
  return extractLastAssistantText(finalMessages ?? []) || lastText;
99701
99656
  }
@@ -99932,7 +99887,7 @@ var FeishuPlugin = async (ctx) => {
99932
99887
  const hooks = {
99933
99888
  event: async ({ event }) => {
99934
99889
  if (!gateway) return;
99935
- await handleEvent(event, { client, log, directory: resolvedConfig.directory });
99890
+ await handleEvent(event, { log, directory: resolvedConfig.directory });
99936
99891
  }
99937
99892
  };
99938
99893
  return hooks;