openclaw-lark-multi-agent 1.0.11 → 1.0.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.
@@ -59,6 +59,7 @@ export declare class OpenClawClient {
59
59
  * 30-minute safety net only for catastrophic WS disconnection.
60
60
  */
61
61
  private collectReply;
62
+ private pickBestCollectedText;
62
63
  createSession(params: {
63
64
  key: string;
64
65
  model: string;
@@ -192,7 +192,7 @@ export class OpenClawClient {
192
192
  this.agentEvents.get(rawKey).push({
193
193
  runId: frame.payload.runId,
194
194
  sessionKey: rawKey,
195
- stream: "assistant",
195
+ stream: "transcriptAssistant",
196
196
  data: { deltaText: visibleAssistantText, delta: visibleAssistantText, replace: true },
197
197
  });
198
198
  }
@@ -336,6 +336,7 @@ export class OpenClawClient {
336
336
  let text = "";
337
337
  let chatDeltaText = "";
338
338
  let chatFinalText = "";
339
+ let transcriptAssistantText = "";
339
340
  let sessionKey = targetSessionKey ? `agent:main:${targetSessionKey.replace(/^agent:[^:]+:/, "")}` : "";
340
341
  let shortSessionKey = targetSessionKey ? targetSessionKey.replace(/^agent:[^:]+:/, "") : "";
341
342
  let chatFinalTimer = null;
@@ -374,7 +375,7 @@ export class OpenClawClient {
374
375
  this.abortChat(targetSessionKey || sessionKey, runId).catch((err) => {
375
376
  console.warn(`[OpenClaw] abort after collectReply idle timeout failed:`, err.message);
376
377
  });
377
- const visibleText = text || chatDeltaText || chatFinalText;
378
+ const visibleText = this.pickBestCollectedText(chatFinalText, text, chatDeltaText, transcriptAssistantText);
378
379
  if (visibleText) {
379
380
  resolve(visibleText);
380
381
  }
@@ -399,7 +400,7 @@ export class OpenClawClient {
399
400
  }
400
401
  return `运行事件 item${data.kind ? `/${data.kind}` : ""}`;
401
402
  }
402
- if (ev.stream === "assistant" || ev.stream === "chatDelta") {
403
+ if (ev.stream === "assistant" || ev.stream === "chatDelta" || ev.stream === "transcriptAssistant") {
403
404
  const chunk = String(ev.data?.deltaText || ev.data?.delta || "").trim();
404
405
  return chunk ? `模型输出片段: ${chunk.slice(0, 300)}` : "模型输出片段";
405
406
  }
@@ -550,7 +551,7 @@ export class OpenClawClient {
550
551
  lifecycleStartedLogged = true;
551
552
  console.log(`[OpenClaw] lifecycle start for runId=${runId} after ${Date.now() - collectStartedAt}ms`);
552
553
  }
553
- if ((ev.stream === "assistant" || ev.stream === "chatDelta") && (ev.data?.deltaText || ev.data?.delta)) {
554
+ if ((ev.stream === "assistant" || ev.stream === "chatDelta" || ev.stream === "transcriptAssistant") && (ev.data?.deltaText || ev.data?.delta)) {
554
555
  const chunk = ev.data.deltaText || ev.data.delta;
555
556
  if (ev.stream === "assistant") {
556
557
  if (ev.data?.replace) {
@@ -560,7 +561,7 @@ export class OpenClawClient {
560
561
  text += chunk;
561
562
  }
562
563
  }
563
- else {
564
+ else if (ev.stream === "chatDelta") {
564
565
  if (ev.data?.replace) {
565
566
  chatDeltaText = chunk;
566
567
  }
@@ -568,6 +569,14 @@ export class OpenClawClient {
568
569
  chatDeltaText += chunk;
569
570
  }
570
571
  }
572
+ else {
573
+ if (ev.data?.replace) {
574
+ transcriptAssistantText = chunk;
575
+ }
576
+ else {
577
+ transcriptAssistantText += chunk;
578
+ }
579
+ }
571
580
  }
572
581
  if (ev.stream === "chatFinal") {
573
582
  chatFinalText = ev.data?.text || "";
@@ -580,7 +589,7 @@ export class OpenClawClient {
580
589
  });
581
590
  // Prefer final chat message over accumulated deltas: some providers may
582
591
  // emit only partial deltas (e.g. "N") while final contains "NO_REPLY".
583
- const latestFinalText = chatFinalText || text || chatDeltaText;
592
+ const latestFinalText = this.pickBestCollectedText(chatFinalText, text, chatDeltaText, transcriptAssistantText);
584
593
  if (latestFinalText) {
585
594
  finish(latestFinalText);
586
595
  }
@@ -597,9 +606,9 @@ export class OpenClawClient {
597
606
  if (ev.stream === "lifecycle" && ev.data?.phase === "end") {
598
607
  // Prefer final chat message over accumulated deltas: some providers may
599
608
  // emit only partial deltas (e.g. "N") while final contains "NO_REPLY".
600
- const finalText = chatFinalText || text || chatDeltaText;
609
+ const finalText = this.pickBestCollectedText(chatFinalText, text, chatDeltaText, transcriptAssistantText);
601
610
  const finishFromLifecycle = () => {
602
- const latestFinalText = chatFinalText || text || chatDeltaText;
611
+ const latestFinalText = this.pickBestCollectedText(chatFinalText, text, chatDeltaText, transcriptAssistantText);
603
612
  if (!chatFinalText && latestFinalText.trim() === "N") {
604
613
  // Some providers stream the first character of NO_REPLY ("N") but
605
614
  // never deliver a final chat message in time. Never surface a lone
@@ -662,6 +671,17 @@ export class OpenClawClient {
662
671
  }, 50);
663
672
  });
664
673
  }
674
+ pickBestCollectedText(chatFinalText, assistantText, chatDeltaText, transcriptAssistantText) {
675
+ if (chatFinalText)
676
+ return chatFinalText;
677
+ const candidates = [assistantText, chatDeltaText, transcriptAssistantText].filter((value) => value && value.trim());
678
+ if (candidates.length === 0)
679
+ return "";
680
+ // transcriptAssistant is a full transcript mirror. Keep it separate from
681
+ // streaming deltas to avoid concatenating the same response twice; choose
682
+ // the richest available non-final text as fallback.
683
+ return candidates.sort((a, b) => b.length - a.length)[0];
684
+ }
665
685
  // --- Session management ---
666
686
  async createSession(params) {
667
687
  return this.rpc("sessions.create", params);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-lark-multi-agent",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Multi-bot Lark/Feishu bridge for OpenClaw, with per-bot model routing and isolated sessions",
5
5
  "type": "module",
6
6
  "scripts": {