opencode-feishu 0.7.10 → 0.7.12

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
@@ -99239,21 +99239,23 @@ function extractErrorFields(error) {
99239
99239
  if (typeof error === "string") return [error];
99240
99240
  if (error && typeof error === "object") {
99241
99241
  const e = error;
99242
- const fields = [e.type, e.name, e.message].filter(Boolean).map(String);
99242
+ const explicit = [e.message, e.type, e.name];
99243
+ const enumerable = Object.values(e);
99244
+ const fields = [...explicit, ...enumerable].filter((v) => typeof v === "string" && v.length > 0);
99243
99245
  if (e.data && typeof e.data === "object" && "message" in e.data) {
99244
99246
  const dataMsg = e.data.message;
99245
- if (dataMsg) fields.push(String(dataMsg));
99247
+ if (typeof dataMsg === "string" && dataMsg.length > 0) fields.push(dataMsg);
99246
99248
  }
99247
- return fields;
99249
+ return [...new Set(fields)];
99248
99250
  }
99249
99251
  return [String(error)];
99250
99252
  }
99251
99253
  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);
99254
+ const patterns = ["model not found", "modelnotfound", "model not supported", "model_not_supported"];
99255
+ return fields.some((f) => {
99256
+ const l = f.toLowerCase();
99257
+ return patterns.some((p) => l.includes(p));
99258
+ });
99257
99259
  }
99258
99260
  async function handleEvent(event, deps) {
99259
99261
  switch (event.type) {
@@ -99436,6 +99438,7 @@ async function handleChat(ctx, deps) {
99436
99438
  for (let i = 0; i < autoPrompt.maxIterations; i++) {
99437
99439
  await abortableSleep(autoPrompt.intervalSeconds * 1e3, ac.signal);
99438
99440
  log("info", "\u53D1\u9001\u81EA\u52A8\u63D0\u793A", { sessionKey, iteration: i + 1 });
99441
+ clearSessionError(activeId);
99439
99442
  await client.session.prompt({
99440
99443
  path: { id: activeId },
99441
99444
  query,
@@ -99466,6 +99469,7 @@ async function handleChat(ctx, deps) {
99466
99469
  }
99467
99470
  }
99468
99471
  try {
99472
+ clearSessionError(session.id);
99469
99473
  await client.session.prompt({
99470
99474
  path: { id: session.id },
99471
99475
  query,
@@ -99481,30 +99485,52 @@ async function handleChat(ctx, deps) {
99481
99485
  await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99482
99486
  await runAutoPromptLoop(session.id);
99483
99487
  } catch (err) {
99484
- await new Promise((r) => setTimeout(r, SSE_RACE_WAIT_MS));
99485
- let sessionError = getSessionError(session.id);
99486
- clearSessionError(session.id);
99487
- if (!sessionError) {
99488
- const thrownFields = extractErrorFields(err);
99489
- if (isModelError(thrownFields)) {
99490
- const thrownMsg = err instanceof Error ? err.message : String(err);
99491
- sessionError = { message: thrownMsg, fields: thrownFields };
99488
+ let sessionError;
99489
+ if (err instanceof SessionErrorDetected) {
99490
+ sessionError = err.sessionError;
99491
+ clearSessionError(session.id);
99492
+ } else {
99493
+ await new Promise((r) => setTimeout(r, SSE_RACE_WAIT_MS));
99494
+ sessionError = getSessionError(session.id);
99495
+ clearSessionError(session.id);
99496
+ if (!sessionError) {
99497
+ const thrownFields = extractErrorFields(err);
99498
+ if (isModelError(thrownFields)) {
99499
+ const thrownMsg = err instanceof Error ? err.message : String(err);
99500
+ sessionError = { message: thrownMsg, fields: thrownFields };
99501
+ }
99492
99502
  }
99493
99503
  }
99504
+ if (sessionError) {
99505
+ log("info", "\u9519\u8BEF\u5B57\u6BB5\u68C0\u67E5", {
99506
+ sessionKey,
99507
+ fields: sessionError.fields,
99508
+ isModel: isModelError(sessionError.fields)
99509
+ });
99510
+ }
99494
99511
  if (sessionError && isModelError(sessionError.fields)) {
99495
99512
  const attempts = getRetryAttempts(sessionKey);
99496
99513
  if (attempts < MAX_RETRY_ATTEMPTS) {
99497
99514
  try {
99498
- const modelOverride = await resolveLatestModel(client, sessionError.fields, directory);
99515
+ let modelOverride;
99516
+ try {
99517
+ modelOverride = await getGlobalDefaultModel(client, directory);
99518
+ } catch (configErr) {
99519
+ log("warn", "\u8BFB\u53D6\u5168\u5C40\u6A21\u578B\u914D\u7F6E\u5931\u8D25", {
99520
+ sessionKey,
99521
+ error: configErr instanceof Error ? configErr.message : String(configErr)
99522
+ });
99523
+ }
99499
99524
  if (!modelOverride) {
99500
- log("warn", "\u65E0\u4EFB\u4F55\u5DF2\u8FDE\u63A5 provider \u6709\u53EF\u7528\u6A21\u578B\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey });
99525
+ log("warn", "\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u672A\u914D\u7F6E\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey });
99501
99526
  } else {
99502
99527
  setRetryAttempts(sessionKey, attempts + 1);
99503
- log("info", "\u5DF2\u89E3\u6790\u53EF\u7528\u6A21\u578B\uFF0C\u5728\u540C\u4E00 session \u4E0A\u91CD\u8BD5", {
99528
+ log("info", "\u4F7F\u7528\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u6062\u590D", {
99504
99529
  sessionKey,
99505
99530
  providerID: modelOverride.providerID,
99506
99531
  modelID: modelOverride.modelID
99507
99532
  });
99533
+ clearSessionError(session.id);
99508
99534
  await client.session.prompt({
99509
99535
  path: { id: session.id },
99510
99536
  query,
@@ -99528,14 +99554,25 @@ async function handleChat(ctx, deps) {
99528
99554
  return;
99529
99555
  }
99530
99556
  } catch (recoveryErr) {
99531
- const recoveryErrMsg = recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr);
99532
- const retryError = getSessionError(session.id);
99533
- if (retryError) clearSessionError(session.id);
99534
- sessionError = retryError ?? { message: recoveryErrMsg, fields: [] };
99557
+ const errMsg = recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr);
99558
+ if (recoveryErr instanceof SessionErrorDetected) {
99559
+ sessionError = recoveryErr.sessionError;
99560
+ clearSessionError(session.id);
99561
+ } else {
99562
+ await new Promise((r) => setTimeout(r, SSE_RACE_WAIT_MS));
99563
+ const sseError = getSessionError(session.id);
99564
+ if (sseError) {
99565
+ sessionError = sseError;
99566
+ clearSessionError(session.id);
99567
+ } else {
99568
+ const thrownFields = extractErrorFields(recoveryErr);
99569
+ sessionError = { message: errMsg, fields: thrownFields };
99570
+ }
99571
+ }
99535
99572
  log("error", "\u6A21\u578B\u6062\u590D\u5931\u8D25", {
99536
99573
  sessionId: session.id,
99537
99574
  sessionKey,
99538
- error: recoveryErrMsg
99575
+ error: errMsg
99539
99576
  });
99540
99577
  }
99541
99578
  } else {
@@ -99562,32 +99599,16 @@ async function handleChat(ctx, deps) {
99562
99599
  unregisterPending(activeSessionId);
99563
99600
  }
99564
99601
  }
99565
- async function resolveLatestModel(client, errorFields, directory) {
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(/\.$/, "");
99602
+ async function getGlobalDefaultModel(client, directory) {
99570
99603
  const query = directory ? { directory } : void 0;
99571
- const { data } = await client.provider.list({ query });
99572
- if (!data) return void 0;
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
- }
99589
- }
99590
- return void 0;
99604
+ const { data: config } = await client.config.get({ query });
99605
+ const model = config?.model;
99606
+ if (!model || !model.includes("/")) return void 0;
99607
+ const slash = model.indexOf("/");
99608
+ const providerID = model.slice(0, slash).trim();
99609
+ const modelID = model.slice(slash + 1).trim();
99610
+ if (!providerID || !modelID) return void 0;
99611
+ return { providerID, modelID };
99591
99612
  }
99592
99613
  async function buildPromptParts(feishuClient, messageId, messageType, rawContent, textContent, chatType, senderId, log) {
99593
99614
  if (messageType === "text") {
@@ -99603,6 +99624,13 @@ async function buildPromptParts(feishuClient, messageId, messageType, rawContent
99603
99624
  }
99604
99625
  return parts;
99605
99626
  }
99627
+ var SessionErrorDetected = class extends Error {
99628
+ constructor(sessionError) {
99629
+ super(sessionError.message);
99630
+ this.sessionError = sessionError;
99631
+ this.name = "SessionErrorDetected";
99632
+ }
99633
+ };
99606
99634
  async function pollForResponse(client, sessionId, opts) {
99607
99635
  const { timeout, pollInterval, stablePolls, query, signal } = opts;
99608
99636
  const start = Date.now();
@@ -99614,6 +99642,10 @@ async function pollForResponse(client, sessionId, opts) {
99614
99642
  } else {
99615
99643
  await new Promise((r) => setTimeout(r, pollInterval));
99616
99644
  }
99645
+ const sseError = getSessionError(sessionId);
99646
+ if (sseError) {
99647
+ throw new SessionErrorDetected(sseError);
99648
+ }
99617
99649
  const { data: messages } = await client.session.messages({ path: { id: sessionId }, query });
99618
99650
  const text2 = extractLastAssistantText(messages ?? []);
99619
99651
  if (text2 && text2 !== lastText) {
@@ -99624,6 +99656,10 @@ async function pollForResponse(client, sessionId, opts) {
99624
99656
  if (sameCount >= stablePolls) break;
99625
99657
  }
99626
99658
  }
99659
+ const finalSseError = getSessionError(sessionId);
99660
+ if (finalSseError) {
99661
+ throw new SessionErrorDetected(finalSseError);
99662
+ }
99627
99663
  const { data: finalMessages } = await client.session.messages({ path: { id: sessionId }, query });
99628
99664
  return extractLastAssistantText(finalMessages ?? []) || lastText;
99629
99665
  }