opencode-feishu 0.5.1 → 0.6.1

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
@@ -99178,6 +99178,17 @@ async function updateMessage(client, messageId, text2) {
99178
99178
 
99179
99179
  // src/handler/event.ts
99180
99180
  var pendingBySession = /* @__PURE__ */ new Map();
99181
+ var sessionErrors = /* @__PURE__ */ new Map();
99182
+ function trackSessionError(sessionId, error) {
99183
+ if (error.includes("ModelNotFound") || error.includes("ProviderModelNotFound")) {
99184
+ sessionErrors.set(sessionId, error);
99185
+ }
99186
+ }
99187
+ function consumeSessionError(sessionId) {
99188
+ const err = sessionErrors.get(sessionId);
99189
+ if (err) sessionErrors.delete(sessionId);
99190
+ return err;
99191
+ }
99181
99192
  function registerPending(sessionId, payload) {
99182
99193
  pendingBySession.set(sessionId, { ...payload, textBuffer: "" });
99183
99194
  }
@@ -99212,9 +99223,10 @@ async function handleEvent(event) {
99212
99223
  const props = event.properties;
99213
99224
  const sessionId = props.sessionID;
99214
99225
  if (!sessionId) break;
99226
+ const errMsg = props.error?.message ?? String(props.error);
99227
+ trackSessionError(sessionId, errMsg);
99215
99228
  const payload = pendingBySession.get(sessionId);
99216
99229
  if (!payload) break;
99217
- const errMsg = props.error?.message ?? String(props.error);
99218
99230
  const updateRes = await updateMessage(payload.feishuClient, payload.placeholderId, `\u274C \u4F1A\u8BDD\u9519\u8BEF: ${errMsg}`);
99219
99231
  if (!updateRes.ok) {
99220
99232
  await sendTextMessage(payload.feishuClient, payload.chatId, `\u274C \u4F1A\u8BDD\u9519\u8BEF: ${errMsg}`);
@@ -99237,6 +99249,9 @@ var TITLE_PREFIX = "Feishu";
99237
99249
  function buildSessionKey(chatType, id) {
99238
99250
  return `${SESSION_KEY_PREFIX}-${chatType}-${id}`;
99239
99251
  }
99252
+ function generateSessionTitle(sessionKey) {
99253
+ return `${TITLE_PREFIX}-${sessionKey}-${Date.now()}`;
99254
+ }
99240
99255
  async function getOrCreateSession(client, sessionKey, directory) {
99241
99256
  const titlePrefix = `${TITLE_PREFIX}-${sessionKey}-`;
99242
99257
  const query = directory ? { directory } : void 0;
@@ -99255,7 +99270,7 @@ async function getOrCreateSession(client, sessionKey, directory) {
99255
99270
  if (best?.id) return { id: best.id, title: best.title };
99256
99271
  }
99257
99272
  }
99258
- const title = `${titlePrefix}${Date.now()}`;
99273
+ const title = generateSessionTitle(sessionKey);
99259
99274
  const createResp = await client.session.create({ query, body: { title } });
99260
99275
  if (!createResp?.data?.id) {
99261
99276
  const err = createResp?.error;
@@ -99265,6 +99280,33 @@ async function getOrCreateSession(client, sessionKey, directory) {
99265
99280
  }
99266
99281
  return { id: createResp.data.id, title: createResp.data.title };
99267
99282
  }
99283
+ async function forkSession(client, oldSessionId, sessionKey, directory) {
99284
+ const query = directory ? { directory } : void 0;
99285
+ const resp = await client.session.fork({
99286
+ path: { id: oldSessionId },
99287
+ query,
99288
+ body: {}
99289
+ });
99290
+ if (!resp?.data?.id) {
99291
+ const err = resp?.error;
99292
+ throw new Error(
99293
+ `Fork \u4F1A\u8BDD\u5931\u8D25: ${err ? JSON.stringify(err) : "unknown"}`
99294
+ );
99295
+ }
99296
+ const title = generateSessionTitle(sessionKey);
99297
+ const updateResp = await client.session.update({
99298
+ path: { id: resp.data.id },
99299
+ query,
99300
+ body: { title }
99301
+ });
99302
+ if (!updateResp?.data?.id) {
99303
+ const err = updateResp?.error;
99304
+ throw new Error(
99305
+ `\u66F4\u65B0 forked session \u6807\u9898\u5931\u8D25: ${err ? JSON.stringify(err) : "unknown"}`
99306
+ );
99307
+ }
99308
+ return { id: resp.data.id, title };
99309
+ }
99268
99310
 
99269
99311
  // src/handler/chat.ts
99270
99312
  var activeAutoPrompts = /* @__PURE__ */ new Map();
@@ -99280,18 +99322,19 @@ async function handleChat(ctx, deps) {
99280
99322
  activeAutoPrompts.delete(sessionKey);
99281
99323
  log("info", "\u7528\u6237\u4ECB\u5165\uFF0C\u81EA\u52A8\u63D0\u793A\u5DF2\u4E2D\u65AD", { sessionKey });
99282
99324
  }
99283
- const session = await getOrCreateSession(client, sessionKey, directory);
99325
+ let session = await getOrCreateSession(client, sessionKey, directory);
99284
99326
  const parts = await buildPromptParts(feishuClient, messageId, messageType, rawContent, content, chatType, senderId, log);
99285
99327
  if (!parts.length) return;
99286
99328
  if (!shouldReply) {
99287
99329
  try {
99288
- await client.session.prompt({
99289
- path: { id: session.id },
99330
+ session = await promptWithForkRecovery({
99331
+ client,
99332
+ session,
99333
+ sessionKey,
99334
+ directory,
99290
99335
  query,
99291
- body: {
99292
- parts,
99293
- noReply: true
99294
- }
99336
+ log,
99337
+ body: { parts, noReply: true }
99295
99338
  });
99296
99339
  } catch (err) {
99297
99340
  log("warn", "\u9759\u9ED8\u8F6C\u53D1\u5931\u8D25", {
@@ -99306,6 +99349,7 @@ async function handleChat(ctx, deps) {
99306
99349
  const stablePolls = config.stablePolls;
99307
99350
  let placeholderId = "";
99308
99351
  let done = false;
99352
+ let oldSessionId = session.id;
99309
99353
  const timer = thinkingDelay > 0 ? setTimeout(async () => {
99310
99354
  if (done) return;
99311
99355
  try {
@@ -99323,13 +99367,21 @@ async function handleChat(ctx, deps) {
99323
99367
  }
99324
99368
  }, thinkingDelay) : null;
99325
99369
  try {
99326
- await client.session.prompt({
99327
- path: { id: session.id },
99370
+ session = await promptWithForkRecovery({
99371
+ client,
99372
+ session,
99373
+ sessionKey,
99374
+ directory,
99328
99375
  query,
99329
- body: {
99330
- parts
99331
- }
99376
+ log,
99377
+ body: { parts }
99332
99378
  });
99379
+ if (session.id !== oldSessionId) {
99380
+ unregisterPending(oldSessionId);
99381
+ if (placeholderId) {
99382
+ registerPending(session.id, { chatId, placeholderId, feishuClient });
99383
+ }
99384
+ }
99333
99385
  const finalText = await pollForResponse(client, session.id, { timeout, pollInterval, stablePolls, query });
99334
99386
  await replyOrUpdate(feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
99335
99387
  const { autoPrompt } = config;
@@ -99375,6 +99427,7 @@ async function handleChat(ctx, deps) {
99375
99427
  done = true;
99376
99428
  if (timer) clearTimeout(timer);
99377
99429
  unregisterPending(session.id);
99430
+ if (session.id !== oldSessionId) unregisterPending(oldSessionId);
99378
99431
  }
99379
99432
  }
99380
99433
  async function buildPromptParts(feishuClient, messageId, messageType, rawContent, textContent, chatType, senderId, log) {
@@ -99446,6 +99499,26 @@ function abortableSleep(ms, signal) {
99446
99499
  signal.addEventListener("abort", onAbort, { once: true });
99447
99500
  });
99448
99501
  }
99502
+ function isModelNotFoundError(err, sessionId) {
99503
+ const msg = err instanceof Error ? err.message : String(err);
99504
+ const tracked = consumeSessionError(sessionId);
99505
+ if (msg.includes("ProviderModelNotFound") || msg.includes("ModelNotFound")) return true;
99506
+ return !!tracked;
99507
+ }
99508
+ async function promptWithForkRecovery(opts) {
99509
+ const { client, sessionKey, directory, query, log, body } = opts;
99510
+ let { session } = opts;
99511
+ const doPrompt = (s) => client.session.prompt({ path: { id: s.id }, query, body });
99512
+ try {
99513
+ await doPrompt(session);
99514
+ } catch (err) {
99515
+ if (!isModelNotFoundError(err, session.id)) throw err;
99516
+ log("warn", "\u4F1A\u8BDD\u6A21\u578B\u4E0D\u517C\u5BB9\uFF0Cfork \u65E7\u4F1A\u8BDD\u91CD\u8BD5", { oldSessionId: session.id });
99517
+ session = await forkSession(client, session.id, sessionKey, directory);
99518
+ await doPrompt(session);
99519
+ }
99520
+ return session;
99521
+ }
99449
99522
  function extractLastAssistantText(messages) {
99450
99523
  const assistant = messages.filter((m) => m.info?.role === "assistant").pop();
99451
99524
  const parts = assistant?.parts ?? [];