@agimon-ai/doompi-read 0.0.1-alpha.14 → 0.0.1-alpha.15

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-read",
3
- "version": "0.0.1-alpha.14",
3
+ "version": "0.0.1-alpha.15",
4
4
  "description": "Snapshot-bound hashline read tool for Pi and DoomPi.",
5
5
  "keywords": [
6
6
  "ai",
@@ -51,11 +51,11 @@
51
51
  "dependencies": {
52
52
  "@deepseek-ai/cordis": "4.0.1",
53
53
  "typebox": "1.3.16",
54
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.42",
55
- "@agimon-ai/doompi-hashline": "0.0.1-alpha.14",
56
- "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.5",
57
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.3",
58
- "@agimon-ai/doompi-ui": "0.0.1-alpha.42"
54
+ "@agimon-ai/doompi-hashline": "0.0.1-alpha.15",
55
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.43",
56
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.43",
57
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.4",
58
+ "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.6"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@earendil-works/pi-coding-agent": "0.84.4",
@@ -10,6 +10,20 @@ import { readCallView } from './readToolView.ts';
10
10
  import { HashlineLines } from './HashlineLines.tsx';
11
11
  import { hashlineBody, resultTextLines } from './hashlineView.ts';
12
12
 
13
+ const IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
14
+
15
+ function resultImages(content: readonly unknown[]): Array<{ data: string; mimeType: string }> {
16
+ return content.flatMap((block) => {
17
+ if (typeof block !== 'object' || block === null || Array.isArray(block)) return [];
18
+ const value = block as Record<string, unknown>;
19
+ return value.type === 'image' &&
20
+ typeof value.data === 'string' &&
21
+ typeof value.mimeType === 'string' &&
22
+ IMAGE_MIME_TYPES.has(value.mimeType)
23
+ ? [{ data: value.data, mimeType: value.mimeType }]
24
+ : [];
25
+ });
26
+ }
13
27
  /**
14
28
  * The read tool's timeline item, the web half of its renderCall and
15
29
  * renderResult: the call summary in the header and the anchored lines with
@@ -18,6 +32,7 @@ import { hashlineBody, resultTextLines } from './hashlineView.ts';
18
32
  */
19
33
  export function ReadToolMessage({ args, result, output, running, isError }: ToolMessageRenderProps) {
20
34
  const view = readCallView(args);
35
+ const images = resultImages(result?.content ?? []);
21
36
  const collapsed = result === null || isError ? null : hashlineBody(result, output, 'read', false);
22
37
  return (
23
38
  <MessageItem tone={toolTone({ running, isError })} expandable={collapsed !== null && collapsed.hidden > 0}>
@@ -49,9 +64,28 @@ export function ReadToolMessage({ args, result, output, running, isError }: Tool
49
64
  <MessageItemStatus tone="running">running</MessageItemStatus>
50
65
  </MessageItemBody>
51
66
  ) : null
52
- ) : body.shown.length === 0 && body.notice === undefined ? null : (
67
+ ) : body.shown.length === 0 && body.notice === undefined && images.length === 0 ? null : (
53
68
  <MessageItemBody data-testid="tool-result-read" className="flex flex-col gap-1">
54
69
  <HashlineLines lines={body.shown} gutter={body.gutter} />
70
+ {images.map((image, index) => {
71
+ const url = `data:${image.mimeType};base64,${image.data}`;
72
+ return (
73
+ <a
74
+ key={`${image.mimeType}:${String(index)}`}
75
+ href={url}
76
+ target="_blank"
77
+ rel="noreferrer"
78
+ className="self-start"
79
+ >
80
+ <img
81
+ src={url}
82
+ alt={`Read result ${String(index + 1)}`}
83
+ data-testid="tool-result-read-image"
84
+ className="h-auto max-h-96 max-w-full rounded-md border border-doom-border-soft object-contain"
85
+ />
86
+ </a>
87
+ );
88
+ })}
55
89
  {body.hidden > 0 ? <MessageItemStatus expands>{body.hidden} more lines</MessageItemStatus> : null}
56
90
  {body.notice !== undefined ? <span className="text-doom-faint">{body.notice}</span> : null}
57
91
  </MessageItemBody>