






















@@ -239,7 +239,7 @@ export function filterToolResultMediaUrls(
239239 *
240240 * Strategy (first match wins):
241241 * 1. Read structured `details.media` attachments from tool details.
242- * 2. Parse legacy `MEDIA:` tokens from text content blocks.
242+ * 2. Parse `MEDIA:` directive tokens from text content blocks.
243243 * 3. Fall back to `details.path` when image content exists (legacy imageResult).
244244 *
245245 * Returns an empty array when no media is found (e.g. Pi SDK `read` tool
@@ -279,6 +279,44 @@ function collectStructuredMediaUrls(media: Record<string, unknown>): string[] {
279279return Array.from(new Set(urls));
280280}
281281282+function extractTextContentMediaArtifact(content: unknown[]): {
283+mediaUrls: string[];
284+audioAsVoice?: boolean;
285+hasImageContent: boolean;
286+} {
287+const mediaUrls: string[] = [];
288+let audioAsVoice = false;
289+let hasImageContent = false;
290+291+for (const item of content) {
292+if (!item || typeof item !== "object") {
293+continue;
294+}
295+const entry = item as Record<string, unknown>;
296+if (entry.type === "image") {
297+hasImageContent = true;
298+continue;
299+}
300+if (entry.type !== "text" || typeof entry.text !== "string") {
301+continue;
302+}
303+304+const parsed = splitMediaFromOutput(entry.text);
305+if (parsed.audioAsVoice) {
306+audioAsVoice = true;
307+}
308+if (parsed.mediaUrls?.length) {
309+mediaUrls.push(...parsed.mediaUrls);
310+}
311+}
312+313+return {
314+ mediaUrls,
315+ ...(audioAsVoice ? { audioAsVoice: true } : {}),
316+ hasImageContent,
317+};
318+}
319+282320export function extractToolResultMediaArtifact(
283321result: unknown,
284322): ToolResultMediaArtifact | undefined {
@@ -303,42 +341,18 @@ export function extractToolResultMediaArtifact(
303341return undefined;
304342}
305343306-// Extract legacy MEDIA: paths from text content blocks using the shared
307-// parser so directive matching and validation stay in sync with outbound
308-// reply parsing.
309-const paths: string[] = [];
310-let audioAsVoice = false;
311-let hasImageContent = false;
312-for (const item of content) {
313-if (!item || typeof item !== "object") {
314-continue;
315-}
316-const entry = item as Record<string, unknown>;
317-if (entry.type === "image") {
318-hasImageContent = true;
319-continue;
320-}
321-if (entry.type === "text" && typeof entry.text === "string") {
322-const parsed = splitMediaFromOutput(entry.text);
323-if (parsed.audioAsVoice) {
324-audioAsVoice = true;
325-}
326-if (parsed.mediaUrls?.length) {
327-paths.push(...parsed.mediaUrls);
328-}
329-}
330-}
344+const textMedia = extractTextContentMediaArtifact(content);
331345332-if (paths.length > 0) {
346+if (textMedia.mediaUrls.length > 0) {
333347return {
334-mediaUrls: paths,
335- ...(audioAsVoice ? { audioAsVoice: true } : {}),
348+mediaUrls: textMedia.mediaUrls,
349+ ...(textMedia.audioAsVoice ? { audioAsVoice: true } : {}),
336350};
337351}
338352339353// Fall back to legacy details.path when image content exists but no
340354// structured media details or MEDIA: text.
341-if (hasImageContent) {
355+if (textMedia.hasImageContent) {
342356const details = record.details as Record<string, unknown> | undefined;
343357const p = normalizeOptionalString(details?.path) ?? "";
344358if (p) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。