linkshell-cli 0.2.122 → 0.2.123

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.
@@ -330,6 +330,50 @@ function textFromBlocks(blocks) {
330
330
  .filter(Boolean)
331
331
  .join("\n");
332
332
  }
333
+ function contentBlocksFromValue(value) {
334
+ if (typeof value === "string") {
335
+ return value.trim() ? [{ type: "text", text: value }] : [];
336
+ }
337
+ if (Array.isArray(value)) {
338
+ return value.flatMap((entry) => contentBlocksFromValue(entry));
339
+ }
340
+ const raw = asRecord(value);
341
+ if (!raw)
342
+ return [];
343
+ const rawType = firstString(raw, ["type", "kind"]);
344
+ const normalizedType = normalizedIdentifier(rawType);
345
+ if (normalizedType === "image" || normalizedType === "inputimage" || normalizedType === "outputimage") {
346
+ const data = firstString(raw, [
347
+ "data",
348
+ "url",
349
+ "uri",
350
+ "imageUrl",
351
+ "image_url",
352
+ "base64",
353
+ ]);
354
+ const mimeType = firstString(raw, ["mimeType", "mime_type", "mediaType", "media_type"]);
355
+ const text = firstString(raw, ["text", "alt", "caption", "name"]);
356
+ return [{ type: "image", data, mimeType, text }];
357
+ }
358
+ if (normalizedType === "text" || normalizedType === "outputtext" || normalizedType === "inputtext") {
359
+ const text = firstString(raw, ["text", "content", "message"]);
360
+ return text ? [{ type: "text", text }] : [];
361
+ }
362
+ const nested = raw.content ?? raw.contentItems ?? raw.parts;
363
+ if (Array.isArray(nested))
364
+ return contentBlocksFromValue(nested);
365
+ const text = firstString(raw, ["text", "message", "content"]);
366
+ return text ? [{ type: "text", text }] : [];
367
+ }
368
+ function contentBlocksFromItem(item) {
369
+ for (const key of ["content", "contentItems", "parts", "message"]) {
370
+ const blocks = contentBlocksFromValue(item[key]);
371
+ if (blocks.length > 0)
372
+ return blocks;
373
+ }
374
+ const text = firstString(item, ["text", "message"]);
375
+ return text ? [{ type: "text", text }] : [];
376
+ }
333
377
  function protocolSupportsImages(protocol) {
334
378
  return protocol === "codex-app-server" ||
335
379
  protocol === "claude-agent-sdk" ||
@@ -2061,28 +2105,33 @@ export class AgentWorkspaceProxy {
2061
2105
  return;
2062
2106
  const itemId = firstString(item, ["id"]) ?? id("msg");
2063
2107
  const existing = this.findItem(conversationId, itemId);
2064
- const content = firstString(item, ["text", "content", "message"]) ?? existing?.text;
2065
- if (!content)
2108
+ const content = contentBlocksFromItem(item);
2109
+ const nextContent = content.length > 0
2110
+ ? content
2111
+ : existing?.content ?? (existing?.text ? [{ type: "text", text: existing.text }] : []);
2112
+ const text = textFromBlocks(nextContent);
2113
+ if (!nextContent.length && !text)
2066
2114
  return;
2067
2115
  this.upsertItem(conversationId, {
2068
2116
  id: itemId,
2069
2117
  conversationId,
2070
2118
  type: "message",
2071
2119
  role: "assistant",
2072
- content: [{ type: "text", text: content }],
2073
- text: content,
2120
+ content: nextContent,
2121
+ text,
2074
2122
  createdAt: existing?.createdAt ?? Date.now(),
2075
2123
  updatedAt: Date.now(),
2076
2124
  isStreaming: streaming,
2077
2125
  });
2078
- this.updateConversationPreview(conversationId, content, streaming ? "running" : "idle");
2126
+ this.updateConversationPreview(conversationId, text || "图片附件", streaming ? "running" : "idle");
2079
2127
  }
2080
2128
  handleSessionUpdate(params) {
2081
2129
  const raw = asRecord(params) ?? {};
2082
2130
  const nested = asRecord(raw.params) ?? {};
2083
2131
  const text = firstString(raw, ["delta", "text", "content", "message"]) ??
2084
2132
  firstString(nested, ["delta", "text", "content", "message"]);
2085
- if (!text)
2133
+ const content = contentBlocksFromItem(raw);
2134
+ if (!text && content.length === 0)
2086
2135
  return;
2087
2136
  const conversationId = this.conversationIdFromParams(raw) ?? this.fallbackConversationId();
2088
2137
  if (!conversationId)
@@ -2101,18 +2150,20 @@ export class AgentWorkspaceProxy {
2101
2150
  return;
2102
2151
  }
2103
2152
  const role = raw.role === "user" || raw.role === "system" ? raw.role : "assistant";
2153
+ const blocks = content.length > 0 ? content : [{ type: "text", text }];
2154
+ const preview = textFromBlocks(blocks);
2104
2155
  this.upsertItem(conversationId, {
2105
2156
  id: firstString(raw, ["messageId", "id"]) ?? id("msg"),
2106
2157
  conversationId,
2107
2158
  type: "message",
2108
2159
  role,
2109
- content: [{ type: "text", text }],
2110
- text,
2160
+ content: blocks,
2161
+ text: preview,
2111
2162
  createdAt: Date.now(),
2112
2163
  updatedAt: Date.now(),
2113
2164
  isStreaming: raw.done === false || raw.isStreaming === true,
2114
2165
  });
2115
- this.updateConversationPreview(conversationId, text, raw.done === true ? "idle" : "running");
2166
+ this.updateConversationPreview(conversationId, preview || "图片附件", raw.done === true ? "idle" : "running");
2116
2167
  }
2117
2168
  handleSemanticSystemItem(item, status, streaming) {
2118
2169
  const itemType = firstString(item, ["type"]);