@vibe-lark/larkpal 0.1.60 → 0.1.62

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.
Files changed (2) hide show
  1. package/dist/main.mjs +91 -79
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -2785,7 +2785,85 @@ async function createLarkpalAgentAdapter() {
2785
2785
  });
2786
2786
  }
2787
2787
  else log$30.warn("未配置 LARKPAL_AGENT_MCP_SERVER_URL,Agent 无远程工具可用");
2788
- return adapter;
2788
+ return wrapLarkpalAgentAdapter(adapter);
2789
+ }
2790
+ function wrapLarkpalAgentAdapter(adapter) {
2791
+ return {
2792
+ get name() {
2793
+ return adapter.name;
2794
+ },
2795
+ executePrompt(config, callbacks) {
2796
+ return adapter.executePrompt(normalizeLarkpalAgentConfig(config), callbacks);
2797
+ },
2798
+ stopProcess(sessionId) {
2799
+ return adapter.stopProcess(sessionId);
2800
+ },
2801
+ stopAll() {
2802
+ return adapter.stopAll();
2803
+ },
2804
+ getProcessInfo(sessionId) {
2805
+ return adapter.getProcessInfo(sessionId);
2806
+ },
2807
+ getAllProcessInfo() {
2808
+ return adapter.getAllProcessInfo();
2809
+ },
2810
+ isSessionBusy(sessionId) {
2811
+ return adapter.isSessionBusy?.(sessionId) ?? false;
2812
+ }
2813
+ };
2814
+ }
2815
+ function normalizeLarkpalAgentConfig(config) {
2816
+ if (!Array.isArray(config.prompt)) return config;
2817
+ const textParts = [];
2818
+ const imageArtifacts = [];
2819
+ const imageLines = [];
2820
+ config.prompt.forEach((block, index) => {
2821
+ if (block.type === "text") {
2822
+ if (block.text.trim()) textParts.push(block.text);
2823
+ return;
2824
+ }
2825
+ if (block.type !== "image") return;
2826
+ const artifact = toAgentImageArtifact(block, index);
2827
+ const label = artifact?.assetId ?? block.fileKey ?? `image_${index + 1}`;
2828
+ if (artifact) imageArtifacts.push(artifact);
2829
+ imageLines.push(artifact ? `- ${label}: ${artifact.path} (${artifact.mimeType})` : `- ${label}: inline image omitted from text prompt (${block.source.media_type})`);
2830
+ });
2831
+ if (imageLines.length === 0) return config;
2832
+ const prompt = [
2833
+ textParts.join("\n\n").trim(),
2834
+ "[Images]",
2835
+ ...imageLines,
2836
+ "The user is asking about these image attachments. Use visual or file tools to inspect the image pixels when needed; do not infer image content from the file name alone."
2837
+ ].filter(Boolean).join("\n");
2838
+ return {
2839
+ ...config,
2840
+ prompt,
2841
+ sourceArtifacts: mergeSourceArtifacts(config.sourceArtifacts, imageArtifacts),
2842
+ metadata: {
2843
+ ...config.metadata,
2844
+ inboundImageCount: imageLines.length,
2845
+ visualAllowedDirs: [config.cwd]
2846
+ }
2847
+ };
2848
+ }
2849
+ function toAgentImageArtifact(block, index) {
2850
+ if (!block.filePath) return null;
2851
+ return {
2852
+ type: "image_asset",
2853
+ assetId: block.fileKey ?? `inbound_image_${index + 1}`,
2854
+ path: block.filePath,
2855
+ mimeType: block.source.media_type.split(";", 1)[0] || "image/png",
2856
+ metadata: {
2857
+ source: "feishu-message",
2858
+ fileKey: block.fileKey
2859
+ }
2860
+ };
2861
+ }
2862
+ function mergeSourceArtifacts(existing, imageArtifacts) {
2863
+ if (imageArtifacts.length === 0) return existing;
2864
+ if (existing === void 0) return imageArtifacts;
2865
+ if (Array.isArray(existing)) return [...existing, ...imageArtifacts];
2866
+ return [existing, ...imageArtifacts];
2789
2867
  }
2790
2868
  //#endregion
2791
2869
  //#region src/routing/session-router.ts
@@ -3463,7 +3541,7 @@ function serializeChatRun(run) {
3463
3541
  lastEventType: run.lastEventType,
3464
3542
  lastToolName: run.lastToolName,
3465
3543
  idleSeconds,
3466
- adapterBusy: run.adapterBusy,
3544
+ adapterBusy: run.status === "running" ? run.adapterBusy : false,
3467
3545
  staleReason: run.staleReason
3468
3546
  };
3469
3547
  }
@@ -3577,6 +3655,7 @@ async function markRunTerminal(run, messageStore, status, params) {
3577
3655
  run.finalStatus = params.finalStatus;
3578
3656
  run.error = params.error;
3579
3657
  run.staleReason = params.staleReason;
3658
+ run.adapterBusy = false;
3580
3659
  recordRunEvent(run, `run-${status}`);
3581
3660
  broadcastRunStatus(run);
3582
3661
  await appendRunStatusMessage(run, messageStore);
@@ -10876,26 +10955,6 @@ async function sendCardByCardId(params) {
10876
10955
  chatId: response?.data?.chat_id ?? ""
10877
10956
  };
10878
10957
  }
10879
- /**
10880
- * Close (or open) the streaming mode on a CardKit card.
10881
- *
10882
- * Must be called after streaming is complete to restore normal card
10883
- * behaviour (forwarding, interaction callbacks, etc.).
10884
- */
10885
- async function setCardStreamingMode(params) {
10886
- const { cfg, cardId, streamingMode, sequence, accountId } = params;
10887
- logCardKitResponse({
10888
- resp: await resolveLarkSdk(cfg, accountId).cardkit.v1.card.settings({
10889
- data: {
10890
- settings: JSON.stringify({ streaming_mode: streamingMode }),
10891
- sequence
10892
- },
10893
- path: { card_id: cardId }
10894
- }),
10895
- api: "card.settings",
10896
- context: `seq=${sequence}, streaming_mode=${streamingMode}`
10897
- });
10898
- }
10899
10958
  //#endregion
10900
10959
  //#region src/card/reply-dispatcher-types.ts
10901
10960
  const TERMINAL_PHASES = new Set([
@@ -11881,7 +11940,7 @@ var StreamingCardController = class StreamingCardController {
11881
11940
  footer: this.deps.resolvedFooter,
11882
11941
  footerMetrics
11883
11942
  });
11884
- if (errorEffectiveCardId) await this.closeStreamingAndUpdate(errorEffectiveCardId, errorCard, "onError");
11943
+ if (errorEffectiveCardId) await this.updateStreamingCard(errorEffectiveCardId, errorCard, "onError");
11885
11944
  else await updateCardFeishu({
11886
11945
  cfg: this.deps.cfg,
11887
11946
  messageId: this.cardKit.cardMessageId,
@@ -11949,20 +12008,6 @@ var StreamingCardController = class StreamingCardController {
11949
12008
  const FINAL_UPDATE_RETRY_DELAY_MS = 2e3;
11950
12009
  for (let attempt = 1; attempt <= MAX_FINAL_UPDATE_RETRIES; attempt++) try {
11951
12010
  if (idleEffectiveCardId) {
11952
- const seqBeforeClose = this.cardKit.cardKitSequence;
11953
- this.cardKit.cardKitSequence += 1;
11954
- log$16.info("onIdle: closing streaming mode", {
11955
- attempt,
11956
- seqBefore: seqBeforeClose,
11957
- seqAfter: this.cardKit.cardKitSequence
11958
- });
11959
- await setCardStreamingMode({
11960
- cfg: this.deps.cfg,
11961
- cardId: idleEffectiveCardId,
11962
- streamingMode: false,
11963
- sequence: this.cardKit.cardKitSequence,
11964
- accountId: this.deps.accountId
11965
- });
11966
12011
  const seqBeforeUpdate = this.cardKit.cardKitSequence;
11967
12012
  this.cardKit.cardKitSequence += 1;
11968
12013
  log$16.info("onIdle: updating final card", {
@@ -12047,7 +12092,7 @@ var StreamingCardController = class StreamingCardController {
12047
12092
  footer: this.deps.resolvedFooter,
12048
12093
  footerMetrics
12049
12094
  });
12050
- await this.closeStreamingAndUpdate(effectiveCardId, abortCardContent, "abortCard");
12095
+ await this.updateStreamingCard(effectiveCardId, abortCardContent, "abortCard");
12051
12096
  log$16.info("abortCard completed", { effectiveCardId });
12052
12097
  } else if (this.cardKit.cardMessageId) {
12053
12098
  const abortCard = buildCardContent("complete", {
@@ -12085,20 +12130,6 @@ var StreamingCardController = class StreamingCardController {
12085
12130
  if (this.cardCreationPromise) await this.cardCreationPromise;
12086
12131
  const effectiveCardId = this.cardKit.cardKitCardId ?? this.cardKit.originalCardKitCardId;
12087
12132
  if (effectiveCardId) {
12088
- const seqBeforeClose = this.cardKit.cardKitSequence;
12089
- this.cardKit.cardKitSequence += 1;
12090
- log$16.info("replaceWithClarificationCard: closing streaming mode", {
12091
- cardId: effectiveCardId,
12092
- seqBefore: seqBeforeClose,
12093
- seqAfter: this.cardKit.cardKitSequence
12094
- });
12095
- await setCardStreamingMode({
12096
- cfg: this.deps.cfg,
12097
- cardId: effectiveCardId,
12098
- streamingMode: false,
12099
- sequence: this.cardKit.cardKitSequence,
12100
- accountId: this.deps.accountId
12101
- });
12102
12133
  const seqBeforeUpdate = this.cardKit.cardKitSequence;
12103
12134
  this.cardKit.cardKitSequence += 1;
12104
12135
  await updateCardKitCard({
@@ -12145,10 +12176,10 @@ var StreamingCardController = class StreamingCardController {
12145
12176
  }
12146
12177
  }
12147
12178
  /**
12148
- * 强制关闭 streaming 状态(兜底方法)。
12179
+ * 强制终态化 streaming 卡片(兜底方法)。
12149
12180
  *
12150
- * 当进程已退出且卡片可能因 API 调用失败仍停留在 streaming 状态时,
12151
- * 由 session-control-handler 调用,强制调用 closeStreaming + updateCard
12181
+ * 当进程已退出且卡片可能因 API 调用失败仍停留在中间态时,
12182
+ * 由 session-control-handler 调用,直接更新卡片内容并保留 streaming mode
12152
12183
  * 即使已经是 terminal phase 也会尝试执行 API 调用。
12153
12184
  */
12154
12185
  async forceCloseStreaming() {
@@ -12157,7 +12188,7 @@ var StreamingCardController = class StreamingCardController {
12157
12188
  log$16.warn("forceCloseStreaming: no card to close");
12158
12189
  return;
12159
12190
  }
12160
- log$16.info("forceCloseStreaming: 强制终态化卡片", {
12191
+ log$16.info("forceCloseStreaming: 强制终态化 streaming 卡片", {
12161
12192
  cardId: effectiveCardId,
12162
12193
  messageId: this.cardKit.cardMessageId,
12163
12194
  phase: this.phase
@@ -12185,14 +12216,6 @@ var StreamingCardController = class StreamingCardController {
12185
12216
  showUndoButton: false
12186
12217
  });
12187
12218
  if (effectiveCardId) {
12188
- this.cardKit.cardKitSequence += 1;
12189
- await setCardStreamingMode({
12190
- cfg: this.deps.cfg,
12191
- cardId: effectiveCardId,
12192
- streamingMode: false,
12193
- sequence: this.cardKit.cardKitSequence,
12194
- accountId: this.deps.accountId
12195
- });
12196
12219
  this.cardKit.cardKitSequence += 1;
12197
12220
  await updateCardKitCard({
12198
12221
  cfg: this.deps.cfg,
@@ -12506,22 +12529,9 @@ var StreamingCardController = class StreamingCardController {
12506
12529
  this.onEnterTerminalPhase();
12507
12530
  }
12508
12531
  /**
12509
- * Close streaming mode then update card content (shared by onError and abortCard).
12532
+ * Update terminal card content while keeping CardKit streaming mode enabled.
12510
12533
  */
12511
- async closeStreamingAndUpdate(cardId, card, label) {
12512
- const seqBeforeClose = this.cardKit.cardKitSequence;
12513
- this.cardKit.cardKitSequence += 1;
12514
- log$16.info(`${label}: closing streaming mode`, {
12515
- seqBefore: seqBeforeClose,
12516
- seqAfter: this.cardKit.cardKitSequence
12517
- });
12518
- await setCardStreamingMode({
12519
- cfg: this.deps.cfg,
12520
- cardId,
12521
- streamingMode: false,
12522
- sequence: this.cardKit.cardKitSequence,
12523
- accountId: this.deps.accountId
12524
- });
12534
+ async updateStreamingCard(cardId, card, label) {
12525
12535
  const seqBeforeUpdate = this.cardKit.cardKitSequence;
12526
12536
  this.cardKit.cardKitSequence += 1;
12527
12537
  log$16.info(`${label}: updating card`, {
@@ -13478,6 +13488,8 @@ async function dispatchToCC(params) {
13478
13488
  const base64Data = buffer.toString("base64");
13479
13489
  imageBlocks.push({
13480
13490
  type: "image",
13491
+ filePath: imgFilePath,
13492
+ fileKey: imgRes.fileKey,
13481
13493
  source: {
13482
13494
  type: "base64",
13483
13495
  media_type: mediaType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-lark/larkpal",
3
- "version": "0.1.60",
3
+ "version": "0.1.62",
4
4
  "description": "LarkPal - Lark/Feishu bot service",
5
5
  "type": "module",
6
6
  "main": "./dist/main.mjs",