@deepseek-ai/dsh-client-ui-tool 0.1.2-alpha.5 → 0.1.3-alpha.2
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/README.i18n.yaml +2 -2
- package/README.md +5 -3
- package/README.zh.md +5 -3
- package/lib/client.js +344 -21
- package/lib/types/client/contract/slots.d.ts +36 -0
- package/lib/types/client/tool/ToolCallTree.d.ts +1 -1
- package/lib/types/client/tool/ToolDetails.d.ts +1 -1
- package/lib/types/client/tool/components/ToolRow.d.ts +19 -2
- package/lib/types/client/tool/models/image-card-model.d.ts +45 -0
- package/lib/types/client/tool/models/terminal-card-model.d.ts +10 -4
- package/lib/types/client/tool/toolviews/read-family-row.d.ts +25 -0
- package/lib/types/client/tool/toolviews/read-image-row.d.ts +24 -0
- package/lib/types/client/tool/toolviews/read-row.d.ts +1 -1
- package/package.json +22 -13
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-tool/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: e0b49a3b582f5f1e6e9aa19e0b026dedb9ba2a18
|
|
6
|
+
README.zh.md: 032f048f2501923c4c9f010b76afe27d98fe7889
|
package/README.md
CHANGED
|
@@ -39,11 +39,11 @@ ctx.slots.inject('tool.call.toolview', () =>
|
|
|
39
39
|
}, BusinessToolRow))
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
The owner payload is `ToolCallOwnerProps`: `callId`, `toolName`, the frozen `block`, optional `cwd` and `home`, and plain `openFile`/`inspect` callbacks. A Code Dispatch block retains its event's `parentCallId`; a root Session call has no such field, so descendants keep the generic flattened form
|
|
42
|
+
The owner payload is `ToolCallOwnerProps`: `callId`, `toolName`, the frozen `block`, optional `cwd` and `home`, the session-authorized `loadImage` loader (for a view whose result carries durable images), and plain `openFile`/`inspect` callbacks. A Code Dispatch block retains its event's `parentCallId`; a root Session call has no such field, so descendants route through the same keyed dispatch — a registered view such as `read_image` renders its card there, and unregistered descendants keep the generic flattened form. Path summaries relativize to the Session cwd first, then replace a leftover POSIX Host home with `~`; `filePath` and Host open keep the authored filesystem path. The registration receives the normal Session slot runtime share but no React node or Runtime service.
|
|
43
43
|
|
|
44
44
|
### Built-in views
|
|
45
45
|
|
|
46
|
-
This package owns the generic fallback and the built-in shell/pwsh, read, write/edit, running `str_replace_editor` `create`/`str_replace`, grep/glob, web, todo, question, and Code Dispatch presentations. Structured cards derive directly from first-party raw event fields; Host `presentCall` and `presentResult` values never enter the Client.
|
|
46
|
+
This package owns the generic fallback and the built-in shell/pwsh, read, read_image, write/edit, running `str_replace_editor` `create`/`str_replace`, grep/glob, web, todo, question, and Code Dispatch presentations. Structured cards derive directly from first-party raw event fields; Host `presentCall` and `presentResult` values never enter the Client. Running and settled foreground standard `bash`/`pwsh` and `terminal_send` calls use terminal cards at the root and in Code Dispatch children, subject to the same argument, result, and error checks. Persistent `bash`/`pwsh` calls use terminal cards only while running. Shell output ending in a recognized spill-policy notice uses expandable generic output in shell rows and generic output in Details; a displaced or omitted exit marker cannot establish success. Settled persistent-shell results stay generic because reset and partial-output diagnostics do not always describe one process exit status; root persistent results are expandable, while background acknowledgements remain collapsed. A successful question row pairs call questions with result answers by their stable ids and shows readable question/answer lines when expanded. A cancelled or interrupted row shows its verdict and original questions without inventing answers. Unsupported, malformed, or ambiguous inputs fall back to flattened Tool input/result text. `ui-skill` demonstrates a business-owned registration for `skill`.
|
|
47
47
|
|
|
48
48
|
-----
|
|
49
49
|
|
|
@@ -61,8 +61,10 @@ The package realizes one dispatch rule: atomic Tool views are keyed by wire Tool
|
|
|
61
61
|
|
|
62
62
|
### Details and cards
|
|
63
63
|
|
|
64
|
-
The package fills `conversation.details.tool` with `ToolDetails`. Row and Details renderers share one pure card model for each terminal, read, diff, search, and web card. These models validate raw call arguments, result content, failure state, persisted metadata, Code Dispatch `parentCallId`, and Session path facts. Generic rows retain the original `argsRaw` reference and format their input body only while it is expanded; structured cards skip generic-body formatting. Unsupported or malformed inputs use flattened Tool result text. Card-specific limits and fallback rules remain in the owning [terminal](../../../.agents/notes/implemented/feature/2026-07-28-web-terminal-card.md), [diff](../../../.agents/notes/implemented/feature/2026-07-30-web-diff-card.md), [read](../../../.agents/notes/implemented/feature/2026-07-30-web-read-card-frontend.md), [search](../../../.agents/notes/implemented/feature/2026-07-30-web-search-card.md), [web](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card-frontend.md), and [question](../../../.agents/notes/implemented/feature/2026-07-29-ask-question-web-presentation.md) notes.
|
|
65
64
|
|
|
65
|
+
The package fills `conversation.details.tool` with `ToolDetails`. Row and Details renderers share one pure card model for each terminal, read, diff, search, and web card; the image card is row-only because its gallery renders through the tool-owned `tool.call.images` slot the details panel does not declare. These models validate raw call arguments, result content, failure state, persisted metadata, and Session path facts. Diff, read, search, and web models also reject Code Dispatch children; terminal eligibility does not depend on `parentCallId`. Unsupported or malformed inputs use flattened Tool result text. Card-specific limits and fallback rules for the terminal, diff, read, search, and web cards remain in [the ui-primitives README](../ui-primitives/README.md); the image card's model in this package carries its own fallback rules.
|
|
66
|
+
|
|
67
|
+
The terminal model uses `hasSpillNotice` from the browser-safe `@deepseek-ai/dsh-spill-policy/notice` entry, not an independent UI pattern. The [spill-policy README](../../spill/spill-policy/README.md#shared-notice-ownership) owns notice formatting and recognition. This check conservatively selects generic output; matching text cannot authenticate its source, and replay leaves recorded result bytes untouched.
|
|
66
68
|
</details>
|
|
67
69
|
|
|
68
70
|
-----
|
package/README.zh.md
CHANGED
|
@@ -39,11 +39,11 @@ ctx.slots.inject('tool.call.toolview', () =>
|
|
|
39
39
|
}, BusinessToolRow))
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、冻结的 `block`、可选 `cwd` 与 `home
|
|
42
|
+
owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、冻结的 `block`、可选 `cwd` 与 `home`、会话授权的 `loadImage` loader(供结果携带持久图像的视图使用),以及普通的 `openFile`/`inspect` 回调。Code Dispatch block 保留事件的 `parentCallId`;root Session call 没有该字段,因此 descendant 走同一条按 key 分发——注册过视图的调用(如 `read_image`)在嵌套处也渲染其卡片,未注册的 descendant 保持 generic 压平形式。路径摘要先相对 Session cwd 缩短,再把剩余的 POSIX Host home 写成 `~`;`filePath` 与 Host 打开仍使用作者给出的文件系统路径。注册项会收到常规 Session slot runtime share,但不会收到 React node 或 runtime service。
|
|
43
43
|
|
|
44
44
|
### 内置视图
|
|
45
45
|
|
|
46
|
-
本包拥有 generic fallback,以及 shell/pwsh、read、write/edit、running `str_replace_editor` `create`/`str_replace`、grep/glob、web、todo、question 与 Code Dispatch 的内置展示。结构化卡片直接从第一方原始 event 字段派生;Host `presentCall` 与 `presentResult` 值不会进入 Client
|
|
46
|
+
本包拥有 generic fallback,以及 shell/pwsh、read、read_image、write/edit、running `str_replace_editor` `create`/`str_replace`、grep/glob、web、todo、question 与 Code Dispatch 的内置展示。结构化卡片直接从第一方原始 event 字段派生;Host `presentCall` 与 `presentResult` 值不会进入 Client。运行中与已完成的前台标准 `bash`/`pwsh` 和 `terminal_send` 调用,无论位于根还是 Code Dispatch 子调用中,都在通过相同的参数、结果和错误检查后使用 terminal 卡片。持久 `bash`/`pwsh` 调用仅在运行中使用 terminal 卡片。以已识别的 spill 策略提示结尾的 shell 输出,在 shell 行中使用可展开的 generic 输出,在 Details 中使用 generic 输出;位置被改变或被省略的退出标记无法证明成功。已完成的持久 shell 结果保持 generic 展示,因为 reset 与部分输出诊断不一定描述单个进程的退出状态;根调用的持久 shell 结果可展开,后台启动回执则保持折叠。成功的问题行按稳定 id 配对调用中的问题与结果中的回答,展开后显示可读的问答行。已取消或已中断的问题行显示其裁决与原始问题,不虚构回答。不受支持、格式错误或含糊的输入回退为压平的工具输入/结果文本。`ui-skill` 展示了业务包自行拥有的 `skill` 注册项。
|
|
47
47
|
|
|
48
48
|
-----
|
|
49
49
|
|
|
@@ -61,8 +61,10 @@ owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、冻结的 `block`
|
|
|
61
61
|
|
|
62
62
|
### 详情与卡片
|
|
63
63
|
|
|
64
|
-
本包通过 `ToolDetails` 填充 `conversation.details.tool`。行 renderer 与 Details renderer 分别为 terminal、read、diff、search 和 web 卡片复用同一个纯 card model。这些 model 校验原始调用参数、结果内容、失败状态、持久 metadata、Code Dispatch `parentCallId` 与 Session 路径事实。Generic row 保留原始 `argsRaw` 引用,只在展开期间格式化 input body;结构化卡片跳过 generic body 格式化。不受支持或格式错误的输入使用压平的工具结果文本。各类卡片的上限与 fallback 规则仍由对应的 [terminal](../../../.agents/notes/implemented/feature/2026-07-28-web-terminal-card.zh.md)、[diff](../../../.agents/notes/implemented/feature/2026-07-30-web-diff-card.zh.md)、[read](../../../.agents/notes/implemented/feature/2026-07-30-web-read-card-frontend.zh.md)、[search](../../../.agents/notes/implemented/feature/2026-07-30-web-search-card.zh.md)、[web](../../../.agents/notes/implemented/feature/2026-07-30-web-result-card-frontend.zh.md) 与 [question](../../../.agents/notes/implemented/feature/2026-07-29-ask-question-web-presentation.zh.md) 笔记负责。
|
|
65
64
|
|
|
65
|
+
本包通过 `ToolDetails` 填充 `conversation.details.tool`。行 renderer 与 Details renderer 分别为 terminal、read、diff、search 和 web 卡片复用同一个纯 card model;image 卡片仅属于行,因为其图库经由工具自有 `tool.call.images` 槽位渲染,而 details 面板不声明该槽位。这些 model 校验原始调用参数、结果内容、失败状态、持久 metadata 与 Session 路径事实。diff、read、search 和 web model 还会拒绝 Code Dispatch 子调用;terminal 适用性不依赖 `parentCallId`。不受支持或格式错误的输入使用压平的工具结果文本。terminal、diff、read、search 与 web 卡片的上限与 fallback 规则仍由 [ui-primitives README](../ui-primitives/README.zh.md) 负责;image 卡片的 fallback 规则由本包内的 card model 自行承载。
|
|
66
|
+
|
|
67
|
+
terminal model 使用浏览器安全入口 `@deepseek-ai/dsh-spill-policy/notice` 的 `hasSpillNotice`,而非独立的 UI 匹配规则。[spill-policy README](../../spill/spill-policy/README.zh.md#shared-notice-ownership) 负责通知的格式化与识别。该检查保守地选择通用输出;匹配文本不能认证其来源,回放也不改变已记录的结果字节。
|
|
66
68
|
</details>
|
|
67
69
|
|
|
68
70
|
-----
|
package/lib/client.js
CHANGED
|
@@ -25,7 +25,8 @@ window.__ModuleLoader__.load({
|
|
|
25
25
|
function resolveWorkspacePath(cwd, path) {
|
|
26
26
|
if (path.startsWith("/") || isWindowsStylePath(path)) return path;
|
|
27
27
|
if (cwd === void 0 || cwd === "") return path;
|
|
28
|
-
|
|
28
|
+
const separator = isWindowsStylePath(cwd) && cwd.includes("\\") ? "\\" : "/";
|
|
29
|
+
return `${cwd.replace(/[/\\]+$/, "")}${separator}${path.replace(/^[/\\]+/, "")}`;
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* Abbreviate a POSIX home directory for display.
|
|
@@ -67,6 +68,7 @@ window.__ModuleLoader__.load({
|
|
|
67
68
|
bash: "bash",
|
|
68
69
|
pwsh: "bash",
|
|
69
70
|
read: "read",
|
|
71
|
+
read_image: "read",
|
|
70
72
|
web_fetch: "read",
|
|
71
73
|
web_search: "search",
|
|
72
74
|
grep: "search",
|
|
@@ -87,7 +89,8 @@ window.__ModuleLoader__.load({
|
|
|
87
89
|
cordis_run: "tool.title.runCordis",
|
|
88
90
|
cordis_stop: "tool.title.stopCordis",
|
|
89
91
|
cordis_undefine: "tool.title.removeCordis",
|
|
90
|
-
pwsh: "tool.title.pwsh"
|
|
92
|
+
pwsh: "tool.title.pwsh",
|
|
93
|
+
read_image: "tool.title.readImage"
|
|
91
94
|
};
|
|
92
95
|
/**
|
|
93
96
|
* Classify a tool name into its row variant.
|
|
@@ -555,6 +558,65 @@ window.__ModuleLoader__.load({
|
|
|
555
558
|
}
|
|
556
559
|
};
|
|
557
560
|
}
|
|
561
|
+
new TextEncoder();
|
|
562
|
+
new TextDecoder();
|
|
563
|
+
/**
|
|
564
|
+
* Standardized, false-precision-safe wording for one {@link Omitted} value —
|
|
565
|
+
* the "may standardize omission wording" half the library owns. `exact` prints
|
|
566
|
+
* the count (`Omitted 3 items`); `unknown` prints NO count because the caller
|
|
567
|
+
* did not provide one. `none` is the empty string.
|
|
568
|
+
*
|
|
569
|
+
* @param omitted The omission metadata from a retainer result.
|
|
570
|
+
* @param unit The noun for the omitted quantity (`items`, `bytes`, `chars`, `lines`).
|
|
571
|
+
* @returns A neutral clause (no trailing space), or `''` when nothing was omitted.
|
|
572
|
+
*/
|
|
573
|
+
function describeOmitted(omitted, unit) {
|
|
574
|
+
switch (omitted.kind) {
|
|
575
|
+
case "none": return "";
|
|
576
|
+
case "exact": return `Omitted ${omitted.count} ${unit}.`;
|
|
577
|
+
case "unknown": return `More ${unit} were omitted.`;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
//#endregion
|
|
581
|
+
//#region ../../spill/spill-policy/src/notice.ts
|
|
582
|
+
/** Browser-safe formatting and recognition of persisted spill-policy notices. */
|
|
583
|
+
const OPEN = "(";
|
|
584
|
+
const CLOSE = ")";
|
|
585
|
+
const LOCATION = " Full formatted result stored at: ";
|
|
586
|
+
const GUIDANCE_SEPARATOR = ". ";
|
|
587
|
+
const SEPARATOR = "\n\n";
|
|
588
|
+
const EXACT_OMISSION = describeOmitted({
|
|
589
|
+
kind: "exact",
|
|
590
|
+
count: 0
|
|
591
|
+
}, "bytes");
|
|
592
|
+
const COUNT_OFFSET = EXACT_OMISSION.indexOf("0");
|
|
593
|
+
const COUNT_SUFFIX = EXACT_OMISSION.slice(COUNT_OFFSET + 1);
|
|
594
|
+
function isOmission(text) {
|
|
595
|
+
if (text === describeOmitted({ kind: "none" }, "bytes") || text === describeOmitted({ kind: "unknown" }, "bytes")) return true;
|
|
596
|
+
const count = Number(text.slice(COUNT_OFFSET, text.length - COUNT_SUFFIX.length));
|
|
597
|
+
return Number.isSafeInteger(count) && count >= 0 && text === describeOmitted({
|
|
598
|
+
kind: "exact",
|
|
599
|
+
count
|
|
600
|
+
}, "bytes");
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Recognize a final spill-policy notice in persisted text, including notice-only output.
|
|
604
|
+
* This identifies the text convention, not authenticated provenance of tool output.
|
|
605
|
+
* @param text - complete recorded text result.
|
|
606
|
+
* @returns whether a complete notice occupies the end of the result.
|
|
607
|
+
*/
|
|
608
|
+
function hasSpillNotice(text) {
|
|
609
|
+
if (!text.endsWith(CLOSE)) return false;
|
|
610
|
+
let start = 0;
|
|
611
|
+
while (true) {
|
|
612
|
+
const next = text.indexOf(`${SEPARATOR}${OPEN}`, start);
|
|
613
|
+
const candidate = text.slice(start, next < 0 ? -1 : next);
|
|
614
|
+
const location = candidate.indexOf(LOCATION, 1);
|
|
615
|
+
if (candidate.startsWith(OPEN) && location >= 0 && isOmission(candidate.slice(1, location))) return text.indexOf(GUIDANCE_SEPARATOR, start + location + 34) >= 0;
|
|
616
|
+
if (next < 0) return false;
|
|
617
|
+
start = next + 2;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
558
620
|
//#endregion
|
|
559
621
|
//#region lib/types/client/tool/models/terminal-card-model.js
|
|
560
622
|
/**
|
|
@@ -720,6 +782,20 @@ window.__ModuleLoader__.load({
|
|
|
720
782
|
if (parsed === null) return false;
|
|
721
783
|
return shellCall(parsed.name, parsed.args)?.persistent === true;
|
|
722
784
|
}
|
|
785
|
+
/**
|
|
786
|
+
* Identify a settled foreground shell preview whose spill footer can hide the exit marker.
|
|
787
|
+
* @param block - running or settled Tool block.
|
|
788
|
+
* @returns whether the shell output must remain generic without an inferred exit status.
|
|
789
|
+
*/
|
|
790
|
+
function isSpilledShellCall(block) {
|
|
791
|
+
if (!("kind" in block)) return false;
|
|
792
|
+
const parsed = parsedToolCall(block);
|
|
793
|
+
if (parsed === null) return false;
|
|
794
|
+
const call = shellCall(parsed.name, parsed.args);
|
|
795
|
+
if (call === null || call.background) return false;
|
|
796
|
+
const output = singleResultText(block);
|
|
797
|
+
return output !== void 0 && hasSpillNotice(output);
|
|
798
|
+
}
|
|
723
799
|
function terminalSendCall(name, args) {
|
|
724
800
|
if (name !== "terminal_send") return null;
|
|
725
801
|
const { sessionId, text, submit, run_in_background: background } = args;
|
|
@@ -756,17 +832,16 @@ window.__ModuleLoader__.load({
|
|
|
756
832
|
};
|
|
757
833
|
}
|
|
758
834
|
/**
|
|
759
|
-
* Derive terminal props for supported
|
|
760
|
-
* Standard shell results parse their final status
|
|
761
|
-
* results, background calls, errors,
|
|
762
|
-
* the generic path. {@link isSettledPersistentShellCall} lets that generic
|
|
835
|
+
* Derive terminal props for supported shell and terminal-send calls, including
|
|
836
|
+
* nested Code Dispatch calls. Standard shell results parse their final status
|
|
837
|
+
* marker; persistent shell results, spill previews, background calls, errors,
|
|
838
|
+
* and malformed input use the generic path. {@link isSettledPersistentShellCall} lets that generic
|
|
763
839
|
* persistent result remain expandable without inventing one process status.
|
|
764
840
|
* @param block - running or settled Tool block.
|
|
765
841
|
* @param sessionCwd - session workspace root used to resolve workdir.
|
|
766
842
|
* @returns locale-neutral terminal-card data, or null for the generic path.
|
|
767
843
|
*/
|
|
768
844
|
function terminalCardModel(block, sessionCwd) {
|
|
769
|
-
if (block.parentCallId !== void 0) return null;
|
|
770
845
|
const parsed = parsedToolCall(block);
|
|
771
846
|
if (parsed === null) return null;
|
|
772
847
|
const call = shellCall(parsed.name, parsed.args) ?? terminalSendCall(parsed.name, parsed.args);
|
|
@@ -791,7 +866,7 @@ window.__ModuleLoader__.load({
|
|
|
791
866
|
running: true
|
|
792
867
|
}
|
|
793
868
|
};
|
|
794
|
-
if (block.isError || call.kind === "shell" && call.persistent) return null;
|
|
869
|
+
if (block.isError || call.kind === "shell" && call.persistent || isSpilledShellCall(block)) return null;
|
|
795
870
|
const output = singleResultText(block);
|
|
796
871
|
if (output === void 0) return null;
|
|
797
872
|
const status = call.kind === "terminal-send" ? { output } : parseExitStatus(output);
|
|
@@ -1042,7 +1117,7 @@ window.__ModuleLoader__.load({
|
|
|
1042
1117
|
}
|
|
1043
1118
|
//#endregion
|
|
1044
1119
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-tool/src/client/tool/components/ToolRow.module.css.mjs
|
|
1045
|
-
const css$3 = ".o3BgMG_root{flex-direction:column;display:flex}.o3BgMG_row{position:relative;overflow:hidden}.o3BgMG_root[data-state=running] .o3BgMG_row:after{content:\"\";background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite o3BgMG_dsh-tool-row-sweep;position:absolute;top:0;bottom:0;left:0}@keyframes o3BgMG_dsh-tool-row-sweep{0%{left:-300px}90%,to{left:100%}}.o3BgMG_leading{flex-shrink:0}.o3BgMG_root[data-tool^=cordis_] .o3BgMG_leading,.o3BgMG_root[data-tool^=cordis_] .o3BgMG_title{color:var(--dsw-alias-state-business-primary)}.o3BgMG_root[data-tool^=cordis_] .o3BgMG_title{font-weight:500}.o3BgMG_root[data-tool^=cordis_] .o3BgMG_sep{background:var(--dsw-alias-state-business-primary)}.o3BgMG_chevron{color:var(--dsw-alias-label-secondary)}.o3BgMG_title{font-weight:400}.o3BgMG_sep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.o3BgMG_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:auto;overflow:hidden}.o3BgMG_summarySuffix{white-space:nowrap;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:none;margin-left:4px}.o3BgMG_diffStat{font-family:var(--ds-font-family-code);font-size:calc(var(--dsh-content-font-size-secondary,13px) - 2px);color:var(--dsw-alias-label-caption);margin-left:10px;transform:translateY(.5px)}.o3BgMG_fileLink{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:inherit;text-align:left;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);text-decoration:underline dotted;text-decoration-color:var(--dsw-alias-label-tertiary);text-underline-offset:3px;cursor:pointer;background:0 0;border:none;flex:0 auto;margin:0;padding:0;text-decoration-thickness:1px;overflow:hidden}.o3BgMG_fileLink:hover{color:var(--dsw-alias-label-primary);text-decoration-color:currentColor}.o3BgMG_errorSummary{color:var(--dsw-alias-state-error-primary)}.o3BgMG_bodyWrap{flex-direction:column;display:flex}.o3BgMG_inspectButton{border:.5px solid var(--dsw-alias-border-l3);corner-shape:round;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.o3BgMG_root:hover .o3BgMG_inspectButton,.o3BgMG_inspectButton:focus-visible{opacity:1}.o3BgMG_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.o3BgMG_bodyScroll{max-height:260px;overflow-y:auto}.o3BgMG_ioCard{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);font:var(--dsw-font-markdown-code-block-small);border-radius:12px;flex-direction:column;margin:4px 0 4px 4px;display:flex}.o3BgMG_ioSection{grid-template-columns:max-content 1fr;align-items:baseline;column-gap:14px;max-height:150px;padding:12px 16px;display:grid;overflow-y:auto}.o3BgMG_ioSection::-webkit-scrollbar-thumb{background-clip:padding-box;border:2px solid #0000;border-radius:6px}.o3BgMG_ioSection::-webkit-scrollbar-track{margin:6px 0}.o3BgMG_ioLabel{color:var(--dsw-alias-label-caption);align-self:start;position:sticky;top:0}.o3BgMG_ioDivider{background:var(--dsw-alias-border-l2);flex:none;height:.5px}.o3BgMG_ioText{white-space:pre-wrap;word-break:break-word;min-width:0;color:var(--dsw-alias-label-secondary)}.o3BgMG_ioText[data-error]{color:var(--dsw-alias-state-error-primary)}.o3BgMG_codeBody,.o3BgMG_terminalBody,.o3BgMG_diffBody,.o3BgMG_readBody,.o3BgMG_searchBody,.o3BgMG_webBody{margin:4px 0 4px 4px}.o3BgMG_searchRecovery{white-space:pre-wrap;overflow-wrap:anywhere;font:var(--dsw-font-xs-13);color:var(--dsw-alias-label-tertiary);margin:4px 0 4px 4px}.o3BgMG_codeBody{--dsl-code-block-content-font:var(--dsw-font-markdown-code-block-small)}.o3BgMG_terminalBody{--dsl-terminal-font:var(--dsw-font-markdown-code-block-small);--dsl-terminal-line-height:18px;--dsl-terminal-output-max-height:224px;border:.5px solid var(--dsw-alias-border-l1)}.o3BgMG_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
|
|
1120
|
+
const css$3 = ".o3BgMG_root{flex-direction:column;display:flex}.o3BgMG_row{position:relative;overflow:hidden}.o3BgMG_root[data-state=running] .o3BgMG_row:after{content:\"\";background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite o3BgMG_dsh-tool-row-sweep;position:absolute;top:0;bottom:0;left:0}@keyframes o3BgMG_dsh-tool-row-sweep{0%{left:-300px}90%,to{left:100%}}.o3BgMG_leading{flex-shrink:0}.o3BgMG_root[data-tool^=cordis_] .o3BgMG_leading,.o3BgMG_root[data-tool^=cordis_] .o3BgMG_title{color:var(--dsw-alias-state-business-primary)}.o3BgMG_root[data-tool^=cordis_] .o3BgMG_title{font-weight:500}.o3BgMG_root[data-tool^=cordis_] .o3BgMG_sep{background:var(--dsw-alias-state-business-primary)}.o3BgMG_chevron{color:var(--dsw-alias-label-secondary)}.o3BgMG_title{font-weight:400}.o3BgMG_sep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.o3BgMG_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:auto;overflow:hidden}.o3BgMG_summarySuffix{white-space:nowrap;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:none;margin-left:4px}.o3BgMG_diffStat{font-family:var(--ds-font-family-code);font-size:calc(var(--dsh-content-font-size-secondary,13px) - 2px);color:var(--dsw-alias-label-caption);margin-left:10px;transform:translateY(.5px)}.o3BgMG_fileLink{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:inherit;text-align:left;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);text-decoration:underline dotted;text-decoration-color:var(--dsw-alias-label-tertiary);text-underline-offset:3px;cursor:pointer;background:0 0;border:none;flex:0 auto;margin:0;padding:0;text-decoration-thickness:1px;overflow:hidden}.o3BgMG_fileLink:hover{color:var(--dsw-alias-label-primary);text-decoration-color:currentColor}.o3BgMG_errorSummary{color:var(--dsw-alias-state-error-primary)}.o3BgMG_bodyWrap{flex-direction:column;display:flex}.o3BgMG_inspectButton{border:.5px solid var(--dsw-alias-border-l3);corner-shape:round;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.o3BgMG_root:hover .o3BgMG_inspectButton,.o3BgMG_inspectButton:focus-visible{opacity:1}.o3BgMG_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.o3BgMG_bodyScroll{max-height:260px;overflow-y:auto}.o3BgMG_ioCard{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);font:var(--dsw-font-markdown-code-block-small);border-radius:12px;flex-direction:column;margin:4px 0 4px 4px;display:flex}.o3BgMG_ioSection{grid-template-columns:max-content 1fr;align-items:baseline;column-gap:14px;max-height:150px;padding:12px 16px;display:grid;overflow-y:auto}.o3BgMG_ioSection::-webkit-scrollbar-thumb{background-clip:padding-box;border:2px solid #0000;border-radius:6px}.o3BgMG_ioSection::-webkit-scrollbar-track{margin:6px 0}.o3BgMG_ioLabel{color:var(--dsw-alias-label-caption);align-self:start;position:sticky;top:0}.o3BgMG_ioDivider{background:var(--dsw-alias-border-l2);flex:none;height:.5px}.o3BgMG_ioText{white-space:pre-wrap;word-break:break-word;min-width:0;color:var(--dsw-alias-label-secondary)}.o3BgMG_ioText[data-error]{color:var(--dsw-alias-state-error-primary)}.o3BgMG_codeBody,.o3BgMG_terminalBody,.o3BgMG_diffBody,.o3BgMG_readBody,.o3BgMG_imageBody,.o3BgMG_searchBody,.o3BgMG_webBody{margin:4px 0 4px 4px}.o3BgMG_searchRecovery{white-space:pre-wrap;overflow-wrap:anywhere;font:var(--dsw-font-xs-13);color:var(--dsw-alias-label-tertiary);margin:4px 0 4px 4px}.o3BgMG_imageLabel{overflow-wrap:anywhere;font:var(--dsw-font-sm-13);color:var(--dsw-alias-label-secondary);margin-bottom:4px}.o3BgMG_imageMeta{white-space:pre-wrap;overflow-wrap:anywhere;font:var(--dsw-font-xs-13);color:var(--dsw-alias-label-tertiary)}.o3BgMG_codeBody{--dsl-code-block-content-font:var(--dsw-font-markdown-code-block-small)}.o3BgMG_terminalBody{--dsl-terminal-font:var(--dsw-font-markdown-code-block-small);--dsl-terminal-line-height:18px;--dsl-terminal-output-max-height:224px;border:.5px solid var(--dsw-alias-border-l1)}.o3BgMG_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
|
|
1046
1121
|
const tagId$3 = "@deepseek-ai/dsh-client-ui-tool/ToolRow.module.css";
|
|
1047
1122
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
1048
1123
|
const tag = document.createElement("style");
|
|
@@ -1061,6 +1136,9 @@ window.__ModuleLoader__.load({
|
|
|
1061
1136
|
"dsh-tool-row-sweep": "o3BgMG_dsh-tool-row-sweep",
|
|
1062
1137
|
"errorSummary": "o3BgMG_errorSummary",
|
|
1063
1138
|
"fileLink": "o3BgMG_fileLink",
|
|
1139
|
+
"imageBody": "o3BgMG_imageBody",
|
|
1140
|
+
"imageLabel": "o3BgMG_imageLabel",
|
|
1141
|
+
"imageMeta": "o3BgMG_imageMeta",
|
|
1064
1142
|
"inspectButton": "o3BgMG_inspectButton",
|
|
1065
1143
|
"ioCard": "o3BgMG_ioCard",
|
|
1066
1144
|
"ioDivider": "o3BgMG_ioDivider",
|
|
@@ -1102,7 +1180,7 @@ window.__ModuleLoader__.load({
|
|
|
1102
1180
|
default: return null;
|
|
1103
1181
|
}
|
|
1104
1182
|
}
|
|
1105
|
-
function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, bodyRaw, output, askQuestion, errorSummary, terminal, diff, read, search, web, state, filePath, onOpenFile, inspect }) {
|
|
1183
|
+
function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, bodyRaw, output, askQuestion, errorSummary, terminal, diff, read, image, renderSlot, loadImage, search, web, state, filePath, onOpenFile, inspect }) {
|
|
1106
1184
|
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
1107
1185
|
const terminalLabels = (0, react.useMemo)(() => terminalBlockLabels(t), [t]);
|
|
1108
1186
|
const diffLabels = (0, react.useMemo)(() => diffBlockLabels(t), [t]);
|
|
@@ -1112,11 +1190,12 @@ window.__ModuleLoader__.load({
|
|
|
1112
1190
|
const terminalBody = terminal === void 0 || terminal === null ? null : localizeTerminalCardModel(terminal, t);
|
|
1113
1191
|
const diffBody = diff ?? null;
|
|
1114
1192
|
const readBody = read ?? null;
|
|
1193
|
+
const imageBody = image !== void 0 && image !== null && renderSlot !== void 0 && loadImage !== void 0 ? image : null;
|
|
1115
1194
|
const searchBody = search ?? null;
|
|
1116
1195
|
const webBody = web ?? null;
|
|
1117
1196
|
const askQuestionBody = askQuestion ?? null;
|
|
1118
1197
|
const outputText = output ?? null;
|
|
1119
|
-
const card = askQuestionBody ?? terminalBody ?? diffBody ?? readBody ?? searchBody ?? webBody;
|
|
1198
|
+
const card = askQuestionBody ?? terminalBody ?? diffBody ?? readBody ?? imageBody ?? searchBody ?? webBody;
|
|
1120
1199
|
const expandable = bodyRaw != null || outputText !== null || card !== null;
|
|
1121
1200
|
const open = expanded && expandable;
|
|
1122
1201
|
const bodyText = (0, react.useMemo)(() => open && card === null && bodyRaw != null ? formatToolBody(variant, bodyRaw) : null, [
|
|
@@ -1203,6 +1282,23 @@ window.__ModuleLoader__.load({
|
|
|
1203
1282
|
labels: readLabels,
|
|
1204
1283
|
maxLines: 8,
|
|
1205
1284
|
className: ToolRow_module_css_default.readBody
|
|
1285
|
+
}) : imageBody !== null ? (0, react_jsx_runtime.jsxs)("div", {
|
|
1286
|
+
className: ToolRow_module_css_default.imageBody,
|
|
1287
|
+
children: [
|
|
1288
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
1289
|
+
className: ToolRow_module_css_default.imageLabel,
|
|
1290
|
+
children: imageBody.label
|
|
1291
|
+
}),
|
|
1292
|
+
renderSlot !== void 0 && loadImage !== void 0 && renderSlot("tool.call.images", {
|
|
1293
|
+
images: imageBody.images,
|
|
1294
|
+
loadImage,
|
|
1295
|
+
align: "start"
|
|
1296
|
+
}),
|
|
1297
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
1298
|
+
className: ToolRow_module_css_default.imageMeta,
|
|
1299
|
+
children: imageBody.text
|
|
1300
|
+
})
|
|
1301
|
+
]
|
|
1206
1302
|
}) : searchBody !== null ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SearchBlock, {
|
|
1207
1303
|
...searchBody.card,
|
|
1208
1304
|
labels: searchLabels,
|
|
@@ -1328,7 +1424,7 @@ window.__ModuleLoader__.load({
|
|
|
1328
1424
|
return "kind" in node ? node.call?.name ?? "" : node.name;
|
|
1329
1425
|
}
|
|
1330
1426
|
/** One atomic call dispatched through the Tool-owned keyed slot. */
|
|
1331
|
-
const ToolCall = (0, react.memo)(function ToolCall({ renderSlot, callId, toolName, block, openFile, selected, cwd, home, inspectCall, t, children }) {
|
|
1427
|
+
const ToolCall = (0, react.memo)(function ToolCall({ renderSlot, callId, toolName, block, openFile, selected, cwd, home, inspectCall, loadImage, t, children }) {
|
|
1332
1428
|
const owner = (0, react.useMemo)(() => ({
|
|
1333
1429
|
callId,
|
|
1334
1430
|
toolName,
|
|
@@ -1336,6 +1432,7 @@ window.__ModuleLoader__.load({
|
|
|
1336
1432
|
openFile,
|
|
1337
1433
|
cwd,
|
|
1338
1434
|
home,
|
|
1435
|
+
loadImage,
|
|
1339
1436
|
inspect: () => {
|
|
1340
1437
|
inspectCall(callId);
|
|
1341
1438
|
}
|
|
@@ -1346,6 +1443,7 @@ window.__ModuleLoader__.load({
|
|
|
1346
1443
|
openFile,
|
|
1347
1444
|
cwd,
|
|
1348
1445
|
home,
|
|
1446
|
+
loadImage,
|
|
1349
1447
|
inspectCall
|
|
1350
1448
|
]);
|
|
1351
1449
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1362,7 +1460,7 @@ window.__ModuleLoader__.load({
|
|
|
1362
1460
|
}), children]
|
|
1363
1461
|
});
|
|
1364
1462
|
});
|
|
1365
|
-
const ToolCallBranch = (0, react.memo)(function ToolCallBranch({ renderSlot, block, selectedCallId, cwd, home, openFile, inspectCall, t }) {
|
|
1463
|
+
const ToolCallBranch = (0, react.memo)(function ToolCallBranch({ renderSlot, block, selectedCallId, cwd, home, openFile, inspectCall, loadImage, t }) {
|
|
1366
1464
|
return (0, react_jsx_runtime.jsx)(ToolCall, {
|
|
1367
1465
|
renderSlot,
|
|
1368
1466
|
callId: block.callId,
|
|
@@ -1373,6 +1471,7 @@ window.__ModuleLoader__.load({
|
|
|
1373
1471
|
cwd,
|
|
1374
1472
|
home,
|
|
1375
1473
|
inspectCall,
|
|
1474
|
+
loadImage,
|
|
1376
1475
|
t,
|
|
1377
1476
|
children: block.subCalls.length > 0 ? (0, react_jsx_runtime.jsx)("div", {
|
|
1378
1477
|
className: ToolCallTree_module_css_default.subCalls,
|
|
@@ -1385,6 +1484,7 @@ window.__ModuleLoader__.load({
|
|
|
1385
1484
|
home,
|
|
1386
1485
|
openFile,
|
|
1387
1486
|
inspectCall,
|
|
1487
|
+
loadImage,
|
|
1388
1488
|
t
|
|
1389
1489
|
}, child.callId))
|
|
1390
1490
|
}) : null
|
|
@@ -1396,7 +1496,7 @@ window.__ModuleLoader__.load({
|
|
|
1396
1496
|
* @param props - whole-Tool owner data and the Tool-owned child-slot share.
|
|
1397
1497
|
* @returns the Tool call tree.
|
|
1398
1498
|
*/
|
|
1399
|
-
function ToolCallTree({ renderSlot, node, selectedCallId, cwd, openFile, inspectCall, useHostInfo, t }) {
|
|
1499
|
+
function ToolCallTree({ renderSlot, node, selectedCallId, cwd, openFile, inspectCall, loadImage, useHostInfo, t }) {
|
|
1400
1500
|
const home = useHostInfo((info) => info.home);
|
|
1401
1501
|
const block = node.data.root;
|
|
1402
1502
|
return (0, react_jsx_runtime.jsx)(ToolCallBranch, {
|
|
@@ -1407,6 +1507,7 @@ window.__ModuleLoader__.load({
|
|
|
1407
1507
|
home,
|
|
1408
1508
|
openFile,
|
|
1409
1509
|
inspectCall,
|
|
1510
|
+
loadImage,
|
|
1410
1511
|
t
|
|
1411
1512
|
});
|
|
1412
1513
|
}
|
|
@@ -1435,7 +1536,7 @@ window.__ModuleLoader__.load({
|
|
|
1435
1536
|
/** Card-aware output body for the selected Tool call in details. */
|
|
1436
1537
|
/**
|
|
1437
1538
|
* Render the selected Tool call's structured output when its raw fields form a
|
|
1438
|
-
* supported
|
|
1539
|
+
* supported card, otherwise preserve the flattened result text.
|
|
1439
1540
|
* @param props - selected call slice, workspace root, host home, and locale seat.
|
|
1440
1541
|
* @returns the details output body.
|
|
1441
1542
|
*/
|
|
@@ -1714,7 +1815,7 @@ window.__ModuleLoader__.load({
|
|
|
1714
1815
|
const state = model.state === "ok" && terminalModel !== null && terminalFailed(terminalModel) ? "error" : model.state;
|
|
1715
1816
|
const status = stateStatus(state, t);
|
|
1716
1817
|
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
1717
|
-
const genericBody = terminal === null && (model.state === "error" || isSettledPersistentShellCall(block)) && (model.bodyRaw !== null || model.output !== null);
|
|
1818
|
+
const genericBody = terminal === null && (model.state === "error" || isSettledPersistentShellCall(block) || isSpilledShellCall(block)) && (model.bodyRaw !== null || model.output !== null);
|
|
1718
1819
|
const expandable = terminal !== null || genericBody;
|
|
1719
1820
|
const open = expanded && expandable;
|
|
1720
1821
|
const body = (0, react.useMemo)(() => open && genericBody && model.bodyRaw !== null ? formatToolBody(model.variant, model.bodyRaw) : null, [
|
|
@@ -1872,13 +1973,16 @@ window.__ModuleLoader__.load({
|
|
|
1872
1973
|
}
|
|
1873
1974
|
};
|
|
1874
1975
|
//#endregion
|
|
1875
|
-
//#region lib/types/client/tool/toolviews/read-row.js
|
|
1976
|
+
//#region lib/types/client/tool/toolviews/read-family-row.js
|
|
1876
1977
|
/**
|
|
1877
|
-
*
|
|
1978
|
+
* Compose a read-family row: the shared chrome and model-derived fields, plus the
|
|
1979
|
+
* caller's card material.
|
|
1980
|
+
* @param props - the toolview runtime share and locale seat.
|
|
1981
|
+
* @param card - the card props this row owns.
|
|
1982
|
+
* @returns the assembled ToolRow.
|
|
1878
1983
|
*/
|
|
1879
|
-
function
|
|
1984
|
+
function readFamilyRow({ toolName, block, cwd, home, openFile, inspect, t }, card) {
|
|
1880
1985
|
const model = toolRowModel(toolName, block, cwd, home);
|
|
1881
|
-
const read = readCardModel(block, cwd, home);
|
|
1882
1986
|
return (0, react_jsx_runtime.jsx)(ToolRow, {
|
|
1883
1987
|
t,
|
|
1884
1988
|
variant: model.variant,
|
|
@@ -1886,15 +1990,25 @@ window.__ModuleLoader__.load({
|
|
|
1886
1990
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 }),
|
|
1887
1991
|
title: t(model.titleKey),
|
|
1888
1992
|
summary: model.summary,
|
|
1993
|
+
bodyRaw: null,
|
|
1889
1994
|
output: model.output,
|
|
1890
1995
|
errorSummary: model.errorSummary,
|
|
1891
|
-
|
|
1996
|
+
...card,
|
|
1892
1997
|
state: model.state,
|
|
1893
1998
|
filePath: model.filePath,
|
|
1894
1999
|
onOpenFile: openFile,
|
|
1895
2000
|
inspect
|
|
1896
2001
|
});
|
|
1897
2002
|
}
|
|
2003
|
+
//#endregion
|
|
2004
|
+
//#region lib/types/client/tool/toolviews/read-row.js
|
|
2005
|
+
/**
|
|
2006
|
+
* Lets users expand a completed read result and open its reported path.
|
|
2007
|
+
*/
|
|
2008
|
+
function ReadRow(props) {
|
|
2009
|
+
const { block, cwd, home } = props;
|
|
2010
|
+
return readFamilyRow(props, { read: readCardModel(block, cwd, home) });
|
|
2011
|
+
}
|
|
1898
2012
|
/** Registers the read tool's conversation row. */
|
|
1899
2013
|
const readToolview = {
|
|
1900
2014
|
name: "read-toolview",
|
|
@@ -1908,6 +2022,214 @@ window.__ModuleLoader__.load({
|
|
|
1908
2022
|
}
|
|
1909
2023
|
};
|
|
1910
2024
|
//#endregion
|
|
2025
|
+
//#region lib/types/client/tool/models/image-card-model.js
|
|
2026
|
+
/**
|
|
2027
|
+
* Whether a wire value is a usable pixel or byte measure.
|
|
2028
|
+
* @param value - unvalidated wire value.
|
|
2029
|
+
* @returns true when it is a positive integer.
|
|
2030
|
+
*/
|
|
2031
|
+
function positiveInteger(value) {
|
|
2032
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
2033
|
+
}
|
|
2034
|
+
/** The envelope `formatImageReadOutput` writes, matched by shape. */
|
|
2035
|
+
const IMAGE_ENVELOPE = /^<path>[^\n]*<\/path>\n<type>image<\/type>\n<content>\n[\s\S]*\n<\/content>$/u;
|
|
2036
|
+
/** The media types a durable image block may claim; anything else declines.
|
|
2037
|
+
* Hand-written mirror of `ImageMediaType` from dsh-attachment — the wire
|
|
2038
|
+
* boundary needs a runtime check and feature plugins must not import values
|
|
2039
|
+
* from each other; a new member added there must be added here too, or the
|
|
2040
|
+
* decline point below silently degrades that image to the generic card. */
|
|
2041
|
+
const IMAGE_MEDIA_TYPES = new Set([
|
|
2042
|
+
"image/png",
|
|
2043
|
+
"image/jpeg",
|
|
2044
|
+
"image/webp",
|
|
2045
|
+
"image/gif"
|
|
2046
|
+
]);
|
|
2047
|
+
/** Runtime membership check; the cast is safe because the set holds exactly the four members. */
|
|
2048
|
+
function isImageMediaType(value) {
|
|
2049
|
+
return IMAGE_MEDIA_TYPES.has(value);
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* Narrow the persisted metadata, defensively. Every field arrives unvalidated on
|
|
2053
|
+
* replay (an obsolete or hand-edited log reaches here), so any mismatch declines
|
|
2054
|
+
* to the generic card rather than throwing. An absent `meta` (a nested call
|
|
2055
|
+
* persists none) leaves the path to the call's own `file_path` argument.
|
|
2056
|
+
*
|
|
2057
|
+
* The attachment id is checked for existence only: it is opaque and
|
|
2058
|
+
* provider-owned, and consumers must not parse that representation, so
|
|
2059
|
+
* pattern-matching the local content-address form would reject a legitimate id
|
|
2060
|
+
* minted by an alternative store.
|
|
2061
|
+
* @param meta - persisted presentation metadata of unknown shape.
|
|
2062
|
+
* @returns the narrowed path, or null when it does not match.
|
|
2063
|
+
*/
|
|
2064
|
+
function imageMeta(meta) {
|
|
2065
|
+
if (typeof meta !== "object" || meta === null || Array.isArray(meta)) return null;
|
|
2066
|
+
const { path } = meta;
|
|
2067
|
+
if (typeof path !== "string" || path === "") return null;
|
|
2068
|
+
return { path };
|
|
2069
|
+
}
|
|
2070
|
+
/**
|
|
2071
|
+
* Narrow every attachment reference carried by the result's image blocks, in
|
|
2072
|
+
* order.
|
|
2073
|
+
*
|
|
2074
|
+
* The content is the single source of truth for the references: it is what the
|
|
2075
|
+
* tool actually returned and what a post-execute hook would replace together
|
|
2076
|
+
* with the rest of the content. Every field arrives unvalidated over the wire,
|
|
2077
|
+
* so any malformed image block declines to the generic card rather than
|
|
2078
|
+
* rendering a partial gallery.
|
|
2079
|
+
*
|
|
2080
|
+
* The attachment id is checked for existence only — it is opaque and
|
|
2081
|
+
* provider-owned, so pattern-matching the local content-address form would reject
|
|
2082
|
+
* a legitimate id minted by an alternative store.
|
|
2083
|
+
* @param content - the settled result's content blocks.
|
|
2084
|
+
* @returns the narrowed references, or null when no valid image block is present.
|
|
2085
|
+
*/
|
|
2086
|
+
function imageReferences(content) {
|
|
2087
|
+
const refs = [];
|
|
2088
|
+
for (const part of content) {
|
|
2089
|
+
if (typeof part !== "object" || part === null) continue;
|
|
2090
|
+
const { type, attachment } = part;
|
|
2091
|
+
if (type !== "image") continue;
|
|
2092
|
+
if (typeof attachment !== "object" || attachment === null || Array.isArray(attachment)) return null;
|
|
2093
|
+
const { attachmentId, mediaType, bytes, width, height, name, originalDimensions } = attachment;
|
|
2094
|
+
if (typeof attachmentId !== "string" || attachmentId === "") return null;
|
|
2095
|
+
if (typeof mediaType !== "string" || !isImageMediaType(mediaType)) return null;
|
|
2096
|
+
if (!positiveInteger(bytes) || !positiveInteger(width) || !positiveInteger(height)) return null;
|
|
2097
|
+
if (name !== void 0 && typeof name !== "string") return null;
|
|
2098
|
+
let inputDimensions;
|
|
2099
|
+
if (originalDimensions !== void 0) {
|
|
2100
|
+
if (typeof originalDimensions !== "object" || originalDimensions === null || Array.isArray(originalDimensions)) return null;
|
|
2101
|
+
const { width: inputWidth, height: inputHeight } = originalDimensions;
|
|
2102
|
+
if (!positiveInteger(inputWidth) || !positiveInteger(inputHeight)) return null;
|
|
2103
|
+
inputDimensions = {
|
|
2104
|
+
width: inputWidth,
|
|
2105
|
+
height: inputHeight
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
refs.push({
|
|
2109
|
+
attachmentId,
|
|
2110
|
+
mediaType,
|
|
2111
|
+
bytes,
|
|
2112
|
+
width,
|
|
2113
|
+
height,
|
|
2114
|
+
...name === void 0 ? {} : { name },
|
|
2115
|
+
...inputDimensions === void 0 ? {} : { originalDimensions: inputDimensions }
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
return refs.length > 0 ? refs : null;
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* Read the text of every text block of a settled image result, joined in order.
|
|
2122
|
+
*
|
|
2123
|
+
* The envelope is one of them; a post-execute hook that appends further text
|
|
2124
|
+
* blocks keeps them visible under the gallery instead of being dropped. The
|
|
2125
|
+
* envelope shape is still the recognition gate: a result without it is not a
|
|
2126
|
+
* well-formed image read and declines.
|
|
2127
|
+
* @param content - the settled result's content blocks.
|
|
2128
|
+
* @returns the joined text, or null when no envelope-shaped block is present.
|
|
2129
|
+
*/
|
|
2130
|
+
function imageTexts(content) {
|
|
2131
|
+
const parts = [];
|
|
2132
|
+
let sawEnvelope = false;
|
|
2133
|
+
for (const part of content) {
|
|
2134
|
+
if (part.type !== "text" || typeof part.text !== "string") continue;
|
|
2135
|
+
if (IMAGE_ENVELOPE.test(part.text)) sawEnvelope = true;
|
|
2136
|
+
parts.push(part.text);
|
|
2137
|
+
}
|
|
2138
|
+
return sawEnvelope && parts.length > 0 ? parts.join("\n") : null;
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Whether the content carries only blocks the card consumes.
|
|
2142
|
+
*
|
|
2143
|
+
* `ContentBlock` is a merge-extensible union, so a post-execute hook could
|
|
2144
|
+
* append a block of a type this card does not render (reasoning, an extension
|
|
2145
|
+
* type, or a non-object). Rendering the card anyway would silently hide that
|
|
2146
|
+
* block, so anything beyond a well-formed text or image object declines to the
|
|
2147
|
+
* generic card, which shows the flattened content.
|
|
2148
|
+
* @param content - the settled result's content blocks.
|
|
2149
|
+
* @returns true when every block is a text or image object with usable fields.
|
|
2150
|
+
*/
|
|
2151
|
+
function fullyRendered(content) {
|
|
2152
|
+
return content.every((part) => {
|
|
2153
|
+
if (typeof part !== "object" || part === null) return false;
|
|
2154
|
+
const { type, text } = part;
|
|
2155
|
+
return type === "image" || type === "text" && typeof text === "string";
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
/**
|
|
2159
|
+
* Derive a settled image card after validating the call head, persisted
|
|
2160
|
+
* metadata (or its argument fallback), and the model-facing image envelope.
|
|
2161
|
+
*
|
|
2162
|
+
* The card is result-side only: a call carries no content until `execute`
|
|
2163
|
+
* returns, so a running `read_image` has none and this returns null for it.
|
|
2164
|
+
* Both root and nested calls settle as ToolResultNode; the nested one (a
|
|
2165
|
+
* read_image dispatched from inside run_code) persists no presentationMeta, so
|
|
2166
|
+
* its label falls back to the call's own `file_path` argument.
|
|
2167
|
+
* @param block - running or settled Tool block.
|
|
2168
|
+
* @param sessionCwd - the session workspace root; a workspace-rooted absolute
|
|
2169
|
+
* path label displays relative to it. Absent leaves the path as authored.
|
|
2170
|
+
* @param home - host account home; a leftover POSIX home path displays as `~`.
|
|
2171
|
+
* @returns the image-card props, or null for the generic path.
|
|
2172
|
+
*/
|
|
2173
|
+
function imageCardModel(block, sessionCwd, home) {
|
|
2174
|
+
if (!("kind" in block) || block.isError) return null;
|
|
2175
|
+
const call = parsedToolCall(block);
|
|
2176
|
+
if (call?.name !== "read_image") return null;
|
|
2177
|
+
const { file_path: filePath } = call.args;
|
|
2178
|
+
if (typeof filePath !== "string" || filePath.trim() === "") return null;
|
|
2179
|
+
const path = imageMeta(block.meta)?.path ?? (block.parentCallId !== void 0 ? filePath : null);
|
|
2180
|
+
if (path === null) return null;
|
|
2181
|
+
if (!fullyRendered(block.content)) return null;
|
|
2182
|
+
const refs = imageReferences(block.content);
|
|
2183
|
+
if (refs === null) return null;
|
|
2184
|
+
const text = imageTexts(block.content);
|
|
2185
|
+
if (text === null) return null;
|
|
2186
|
+
return {
|
|
2187
|
+
label: abbreviateHomePath(relativizeToCwd(path, sessionCwd), home),
|
|
2188
|
+
images: refs.map((ref) => ({ attachment: ref })),
|
|
2189
|
+
text
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
2192
|
+
//#endregion
|
|
2193
|
+
//#region lib/types/client/tool/toolviews/read-image-row.js
|
|
2194
|
+
/**
|
|
2195
|
+
* read_image row: the read-family chrome with the durably committed image as the
|
|
2196
|
+
* row's collapsed-by-default card body, rendered through the `tool.call.images`
|
|
2197
|
+
* slot this entry declares.
|
|
2198
|
+
*/
|
|
2199
|
+
function ReadImageRow(props) {
|
|
2200
|
+
const { block, cwd, home, renderSlot, loadImage } = props;
|
|
2201
|
+
return readFamilyRow(props, {
|
|
2202
|
+
image: imageCardModel(block, cwd, home),
|
|
2203
|
+
renderSlot,
|
|
2204
|
+
loadImage
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* The read_image row as a plain registrant plugin following the atomic Tool-view
|
|
2209
|
+
* declaration across independent activation and reload lifetimes. Declaring
|
|
2210
|
+
* `tool.call.images` as a child slot authorizes this entry's `renderSlot` to
|
|
2211
|
+
* dispatch the gallery.
|
|
2212
|
+
*/
|
|
2213
|
+
const readImageToolview = {
|
|
2214
|
+
name: "read-image-toolview",
|
|
2215
|
+
inject: ["slots"],
|
|
2216
|
+
/**
|
|
2217
|
+
* Register the read_image row into the Tool-owned keyed view slot.
|
|
2218
|
+
* @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
|
|
2219
|
+
*/
|
|
2220
|
+
apply(ctx) {
|
|
2221
|
+
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
2222
|
+
name: "tool.call.toolview",
|
|
2223
|
+
key: "read_image",
|
|
2224
|
+
locale: CONVERSATION_NS,
|
|
2225
|
+
children: { "tool.call.images": {
|
|
2226
|
+
kind: "single",
|
|
2227
|
+
scope: "session"
|
|
2228
|
+
} }
|
|
2229
|
+
}, ReadImageRow));
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
//#endregion
|
|
1911
2233
|
//#region lib/types/client/tool/toolviews/search-row.js
|
|
1912
2234
|
const SEARCH_TITLE_KEYS = {
|
|
1913
2235
|
grep: "tool.title.grep",
|
|
@@ -2120,6 +2442,7 @@ window.__ModuleLoader__.load({
|
|
|
2120
2442
|
}, ToolDetails));
|
|
2121
2443
|
ctx.plugin(bashToolviewSample);
|
|
2122
2444
|
ctx.plugin(readToolview);
|
|
2445
|
+
ctx.plugin(readImageToolview);
|
|
2123
2446
|
ctx.plugin(fileMutationToolview);
|
|
2124
2447
|
ctx.plugin(searchToolview);
|
|
2125
2448
|
ctx.plugin(webToolview);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { HostObservable, InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
3
|
import type { RemoteHostFacts } from '@deepseek-ai/dsh-api-remotes/client';
|
|
4
4
|
import type { ToolCallBlock } from '@deepseek-ai/dsh-client-ui-chat/client';
|
|
5
|
+
import type { MessageImageLoader, MessageImageSource } from '@deepseek-ai/dsh-client-ui-conversation/client';
|
|
5
6
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
6
7
|
interface SlotMap {
|
|
7
8
|
/**
|
|
@@ -23,8 +24,35 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
23
24
|
scope: 'session';
|
|
24
25
|
owner: ToolCallOwnerProps;
|
|
25
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* Durable images of a settled image-bearing Tool call, rendered through
|
|
29
|
+
* the attachment presentation plugin. The Tool layer never imports an
|
|
30
|
+
* attachment implementation: a toolview declares this slot as a child and
|
|
31
|
+
* renders it with the image card's references plus the session-authorized
|
|
32
|
+
* loader it received in its owner, and the attachment plugin fills the
|
|
33
|
+
* gallery. Composing no attachment presentation plugin renders nothing,
|
|
34
|
+
* which is why the image card keeps its own envelope text beside the
|
|
35
|
+
* gallery. A child slot is declared by exactly one entry: registering a
|
|
36
|
+
* second toolview that declares the same child throws at load, so a
|
|
37
|
+
* future image-bearing tool must reuse this entry or own a distinct
|
|
38
|
+
* slot.
|
|
39
|
+
*/
|
|
40
|
+
'tool.call.images': {
|
|
41
|
+
kind: 'single';
|
|
42
|
+
scope: 'session';
|
|
43
|
+
owner: ToolImagesOwnerProps;
|
|
44
|
+
};
|
|
26
45
|
}
|
|
27
46
|
}
|
|
47
|
+
/** Owner currency of the Tool image gallery slot: references plus the loader. */
|
|
48
|
+
export interface ToolImagesOwnerProps {
|
|
49
|
+
/** Durable references or submission-echo previews in result order. */
|
|
50
|
+
images: readonly MessageImageSource[];
|
|
51
|
+
/** Session-authorized image URL loader for the durable arm. */
|
|
52
|
+
loadImage: MessageImageLoader;
|
|
53
|
+
/** Horizontal placement inside the owning record. */
|
|
54
|
+
align: 'start' | 'end';
|
|
55
|
+
}
|
|
28
56
|
/** Standard owner currency supplied to every atomic Tool view. */
|
|
29
57
|
export interface ToolCallOwnerProps {
|
|
30
58
|
/** Tool call identity, stable across running and settled forms. */
|
|
@@ -39,6 +67,14 @@ export interface ToolCallOwnerProps {
|
|
|
39
67
|
home?: string | undefined;
|
|
40
68
|
/** Open a Tool argument path through the Host. */
|
|
41
69
|
openFile: (path: string) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Session-authorized image loader for the `tool.call.images` slot, supplied
|
|
72
|
+
* by the chat node that owns this call. A composed chat node always
|
|
73
|
+
* supplies it (`ChatNodeOwnerProps.loadImage` is required), so the tool
|
|
74
|
+
* layer never imports an attachment implementation nor handles URL
|
|
75
|
+
* authorization.
|
|
76
|
+
*/
|
|
77
|
+
loadImage: MessageImageLoader;
|
|
42
78
|
/** Inspect this call in the trajectory view when available. */
|
|
43
79
|
inspect?: (() => void) | undefined;
|
|
44
80
|
}
|
|
@@ -5,5 +5,5 @@ import type { ToolTreeProps } from '../contract/slots.ts';
|
|
|
5
5
|
* @param props - whole-Tool owner data and the Tool-owned child-slot share.
|
|
6
6
|
* @returns the Tool call tree.
|
|
7
7
|
*/
|
|
8
|
-
export declare function ToolCallTree({ renderSlot, node, selectedCallId, cwd, openFile, inspectCall, useHostInfo, t, }: ToolTreeProps): import("react").JSX.Element;
|
|
8
|
+
export declare function ToolCallTree({ renderSlot, node, selectedCallId, cwd, openFile, inspectCall, loadImage, useHostInfo, t, }: ToolTreeProps): import("react").JSX.Element;
|
|
9
9
|
//# sourceMappingURL=ToolCallTree.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ToolDetailsProps } from '../contract/slots.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Render the selected Tool call's structured output when its raw fields form a
|
|
4
|
-
* supported
|
|
4
|
+
* supported card, otherwise preserve the flattened result text.
|
|
5
5
|
* @param props - selected call slice, workspace root, host home, and locale seat.
|
|
6
6
|
* @returns the details output body.
|
|
7
7
|
*/
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
+
import type { PropsRenderSlots, TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
+
import type { MessageImageLoader } from '@deepseek-ai/dsh-client-ui-conversation/client';
|
|
3
4
|
import { type DiffCardModel } from '../models/diff-card-model.ts';
|
|
4
5
|
import { type ReadCardModel } from '../models/read-card-model.ts';
|
|
6
|
+
import type { ImageCardModel } from '../models/image-card-model.ts';
|
|
5
7
|
import { type SearchCardModel } from '../models/search-card-model.ts';
|
|
6
8
|
import { type TerminalCardModel } from '../models/terminal-card-model.ts';
|
|
7
9
|
import type { AskQuestionCardModel } from '../models/ask-question-card-model.ts';
|
|
@@ -35,6 +37,21 @@ export interface ToolRowProps {
|
|
|
35
37
|
terminal?: TerminalCardModel | null | undefined;
|
|
36
38
|
diff?: DiffCardModel | null | undefined;
|
|
37
39
|
read?: ReadCardModel | null | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Image-card material for a call whose result is an image (derived by
|
|
42
|
+
* `imageCardModel`). Rendered through the `tool.call.images` slot, so the
|
|
43
|
+
* tool layer never imports an attachment implementation nor handles URL
|
|
44
|
+
* authorization.
|
|
45
|
+
*/
|
|
46
|
+
image?: ImageCardModel | null | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Dispatch the image gallery through the tool-owned `tool.call.images`
|
|
49
|
+
* slot, supplied by the toolview that owns this row together with the
|
|
50
|
+
* session-authorized loader.
|
|
51
|
+
*/
|
|
52
|
+
renderSlot?: PropsRenderSlots<'tool.call.images'>['renderSlot'] | undefined;
|
|
53
|
+
/** Session-authorized image URL loader for the gallery slot. */
|
|
54
|
+
loadImage?: MessageImageLoader | undefined;
|
|
38
55
|
search?: SearchCardModel | null | undefined;
|
|
39
56
|
web?: WebCardModelProps | null | undefined;
|
|
40
57
|
state: ToolRowState;
|
|
@@ -51,5 +68,5 @@ export interface ToolRowProps {
|
|
|
51
68
|
*/
|
|
52
69
|
inspect?: (() => void) | undefined;
|
|
53
70
|
}
|
|
54
|
-
export declare function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, bodyRaw, output, askQuestion, errorSummary, terminal, diff, read, search, web, state, filePath, onOpenFile, inspect, }: ToolRowProps): import("react").JSX.Element;
|
|
71
|
+
export declare function ToolRow({ t, variant, toolName, icon, title, summary, summarySuffix, bodyRaw, output, askQuestion, errorSummary, terminal, diff, read, image, renderSlot, loadImage, search, web, state, filePath, onOpenFile, inspect, }: ToolRowProps): import("react").JSX.Element;
|
|
55
72
|
//# sourceMappingURL=ToolRow.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Pure image-card derivation from raw result content and metadata. @module */
|
|
2
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
3
|
+
import { type ToolCallBlock } from './tool-call-model.ts';
|
|
4
|
+
/**
|
|
5
|
+
* The image-card material one settled call contributes: the display label plus
|
|
6
|
+
* the durable references the attachment slot renders as a gallery.
|
|
7
|
+
*
|
|
8
|
+
* The bytes are not here. `attachmentId` is opaque and provider-owned, so a UI
|
|
9
|
+
* resolves it to a session-authorized URL at render time; this model never parses
|
|
10
|
+
* it nor derives a path from it.
|
|
11
|
+
*/
|
|
12
|
+
export interface ImageCardModel {
|
|
13
|
+
/** Card label: the read path, shortened the way every other card's is. */
|
|
14
|
+
label: string;
|
|
15
|
+
/** The durable images this result returned, in result order. */
|
|
16
|
+
images: readonly {
|
|
17
|
+
readonly attachment: ImageAttachmentRef;
|
|
18
|
+
}[];
|
|
19
|
+
/**
|
|
20
|
+
* The model-facing envelope text, for the line under the gallery.
|
|
21
|
+
*
|
|
22
|
+
* Taken from the result's own text block rather than the row's flattened
|
|
23
|
+
* result text: an image read's content is `[text envelope, image block]`, and
|
|
24
|
+
* flattening JSON.stringifies the image block, which would print the raw
|
|
25
|
+
* attachment object under the picture — the symptom this card exists to remove.
|
|
26
|
+
*/
|
|
27
|
+
text: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Derive a settled image card after validating the call head, persisted
|
|
31
|
+
* metadata (or its argument fallback), and the model-facing image envelope.
|
|
32
|
+
*
|
|
33
|
+
* The card is result-side only: a call carries no content until `execute`
|
|
34
|
+
* returns, so a running `read_image` has none and this returns null for it.
|
|
35
|
+
* Both root and nested calls settle as ToolResultNode; the nested one (a
|
|
36
|
+
* read_image dispatched from inside run_code) persists no presentationMeta, so
|
|
37
|
+
* its label falls back to the call's own `file_path` argument.
|
|
38
|
+
* @param block - running or settled Tool block.
|
|
39
|
+
* @param sessionCwd - the session workspace root; a workspace-rooted absolute
|
|
40
|
+
* path label displays relative to it. Absent leaves the path as authored.
|
|
41
|
+
* @param home - host account home; a leftover POSIX home path displays as `~`.
|
|
42
|
+
* @returns the image-card props, or null for the generic path.
|
|
43
|
+
*/
|
|
44
|
+
export declare function imageCardModel(block: ToolCallBlock, sessionCwd?: string, home?: string): ImageCardModel | null;
|
|
45
|
+
//# sourceMappingURL=image-card-model.d.ts.map
|
|
@@ -67,10 +67,16 @@ export declare function terminalFailed(model: TerminalCardModel): boolean;
|
|
|
67
67
|
*/
|
|
68
68
|
export declare function isSettledPersistentShellCall(block: ToolCallBlock): boolean;
|
|
69
69
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
|
|
70
|
+
* Identify a settled foreground shell preview whose spill footer can hide the exit marker.
|
|
71
|
+
* @param block - running or settled Tool block.
|
|
72
|
+
* @returns whether the shell output must remain generic without an inferred exit status.
|
|
73
|
+
*/
|
|
74
|
+
export declare function isSpilledShellCall(block: ToolCallBlock): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Derive terminal props for supported shell and terminal-send calls, including
|
|
77
|
+
* nested Code Dispatch calls. Standard shell results parse their final status
|
|
78
|
+
* marker; persistent shell results, spill previews, background calls, errors,
|
|
79
|
+
* and malformed input use the generic path. {@link isSettledPersistentShellCall} lets that generic
|
|
74
80
|
* persistent result remain expandable without inventing one process status.
|
|
75
81
|
* @param block - running or settled Tool block.
|
|
76
82
|
* @param sessionCwd - session workspace root used to resolve workdir.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
+
import type { ToolCallViewProps } from '../../contract/slots.ts';
|
|
4
|
+
import { type ToolRowProps } from '../components/ToolRow.tsx';
|
|
5
|
+
/** Full row props of a read-family toolview: the runtime share plus its locale seat. */
|
|
6
|
+
export type ReadFamilyRowProps = ToolCallViewProps & {
|
|
7
|
+
t: ToolRowProps['t'];
|
|
8
|
+
};
|
|
9
|
+
/** read_image row props: the runtime share, the declared image child slot, and the locale seat. */
|
|
10
|
+
export type ReadImageRowProps = ReadFamilyRowProps & PropsRenderSlots<'tool.call.images'>;
|
|
11
|
+
/**
|
|
12
|
+
* The card material one read-family row contributes: exactly the ToolRow card
|
|
13
|
+
* props that row owns. `read` supplies `read`; `read_image` supplies `image`
|
|
14
|
+
* together with the slot dispatcher and loader that draw it.
|
|
15
|
+
*/
|
|
16
|
+
export type ReadFamilyCard = Pick<ToolRowProps, 'read' | 'image' | 'renderSlot' | 'loadImage'>;
|
|
17
|
+
/**
|
|
18
|
+
* Compose a read-family row: the shared chrome and model-derived fields, plus the
|
|
19
|
+
* caller's card material.
|
|
20
|
+
* @param props - the toolview runtime share and locale seat.
|
|
21
|
+
* @param card - the card props this row owns.
|
|
22
|
+
* @returns the assembled ToolRow.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readFamilyRow({ toolName, block, cwd, home, openFile, inspect, t }: ReadFamilyRowProps, card: ReadFamilyCard): ReactNode;
|
|
25
|
+
//# sourceMappingURL=read-family-row.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type ReadImageRowProps } from './read-family-row.tsx';
|
|
3
|
+
/**
|
|
4
|
+
* read_image row: the read-family chrome with the durably committed image as the
|
|
5
|
+
* row's collapsed-by-default card body, rendered through the `tool.call.images`
|
|
6
|
+
* slot this entry declares.
|
|
7
|
+
*/
|
|
8
|
+
export declare function ReadImageRow(props: ReadImageRowProps): import("react").ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* The read_image row as a plain registrant plugin following the atomic Tool-view
|
|
11
|
+
* declaration across independent activation and reload lifetimes. Declaring
|
|
12
|
+
* `tool.call.images` as a child slot authorizes this entry's `renderSlot` to
|
|
13
|
+
* dispatch the gallery.
|
|
14
|
+
*/
|
|
15
|
+
export declare const readImageToolview: {
|
|
16
|
+
name: string;
|
|
17
|
+
inject: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Register the read_image row into the Tool-owned keyed view slot.
|
|
20
|
+
* @param ctx - registrant context (disposal rides ctx.effect inside slots.register).
|
|
21
|
+
*/
|
|
22
|
+
apply(ctx: Context): void;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=read-image-row.d.ts.map
|
|
@@ -5,7 +5,7 @@ type ReadRowProps = ToolCallViewProps & PropsLocale<'conversation'>;
|
|
|
5
5
|
/**
|
|
6
6
|
* Lets users expand a completed read result and open its reported path.
|
|
7
7
|
*/
|
|
8
|
-
export declare function ReadRow(
|
|
8
|
+
export declare function ReadRow(props: ReadRowProps): import("react").ReactNode;
|
|
9
9
|
/** Registers the read tool's conversation row. */
|
|
10
10
|
export declare const readToolview: {
|
|
11
11
|
name: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-tool",
|
|
3
3
|
"description": "Client Tool call-tree renderer and keyed per-tool presentation slot",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -48,19 +48,28 @@
|
|
|
48
48
|
"@types/react": "~18.3.1",
|
|
49
49
|
"react": "^18.2.0",
|
|
50
50
|
"react-dom": "^18.2.0",
|
|
51
|
-
"@deepseek-ai/dsh-
|
|
52
|
-
"@deepseek-ai/dsh-
|
|
51
|
+
"@deepseek-ai/dsh-spill-policy": "^0.1.3-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-agent": "^0.1.3-alpha.2",
|
|
53
|
+
"@deepseek-ai/dsh-llm": "^0.1.3-alpha.2",
|
|
54
|
+
"@deepseek-ai/dsh-session": "^0.1.3-alpha.2",
|
|
55
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.3-alpha.2",
|
|
56
|
+
"@deepseek-ai/dsh-tools": "^0.1.3-alpha.2",
|
|
57
|
+
"@deepseek-ai/dsh-spill": "^0.1.3-alpha.2",
|
|
58
|
+
"@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.3-alpha.2",
|
|
53
59
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
54
|
-
"@deepseek-ai/dsh-
|
|
55
|
-
"@deepseek-ai/dsh-client-
|
|
56
|
-
"@deepseek-ai/dsh-client-
|
|
57
|
-
"@deepseek-ai/dsh-client-
|
|
58
|
-
"@deepseek-ai/dsh-
|
|
59
|
-
"@deepseek-ai/dsh-client-ui-
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-client-ui-
|
|
63
|
-
"@deepseek-ai/dsh-util-workspace-path": "^0.1.
|
|
60
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.3-alpha.2",
|
|
61
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.3-alpha.2",
|
|
62
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.3-alpha.2",
|
|
63
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.3-alpha.2",
|
|
64
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.3-alpha.2",
|
|
65
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.3-alpha.2",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.3-alpha.2",
|
|
67
|
+
"@deepseek-ai/dsh-api-workspace-controller": "^0.1.3-alpha.2",
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.3-alpha.2",
|
|
69
|
+
"@deepseek-ai/dsh-util-workspace-path": "^0.1.3-alpha.2",
|
|
70
|
+
"@deepseek-ai/dsh-attachment": "^0.1.3-alpha.2",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-session": "^0.1.3-alpha.2",
|
|
72
|
+
"@deepseek-ai/dsh-client-ui-chat": "^0.1.3-alpha.2"
|
|
64
73
|
},
|
|
65
74
|
"files": [
|
|
66
75
|
"lib/index.js",
|