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 =
|
|
2065
|
-
|
|
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:
|
|
2073
|
-
text
|
|
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,
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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"]);
|