mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-19 01:51:21 +08:00
feat(vscode): render read-tool images inline in chat view
The read tool already produces base64 data URL attachments for image files and threads them through SSE into the webview part store, but the tool renderer never received them. Thread part.state.attachments into ToolProps and render image attachments inline below the read tool card, reusing the existing user-attachment image pattern with click-to-open preview. No backend, schema, or SDK changes needed.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Render images inline in the chat view when the agent reads an image file. Images appear below the read tool card and can be clicked to open a full-size preview.
|
||||
@@ -412,6 +412,35 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
[data-slot="tool-read-images"] {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
max-width: min(100%, 64ch);
|
||||
}
|
||||
|
||||
[data-slot="tool-read-image"] {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
border-radius: var(--radius-sm, 6px);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border-weak-base);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--border-strong-base);
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="tool-read-image-img"] {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 200px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
[data-component="todos"] {
|
||||
[data-slot="message-part-todo-hidden"] {
|
||||
padding: 2px 0 2px 28px;
|
||||
|
||||
@@ -995,6 +995,7 @@ export interface ToolProps {
|
||||
callID?: string
|
||||
output?: string
|
||||
status?: string
|
||||
attachments?: FilePart[]
|
||||
hideDetails?: boolean
|
||||
defaultOpen?: boolean
|
||||
forceOpen?: boolean
|
||||
@@ -1243,6 +1244,8 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) {
|
||||
// @ts-expect-error
|
||||
output={part.state.output}
|
||||
status={part.state.status}
|
||||
// @ts-expect-error
|
||||
attachments={part.state.attachments}
|
||||
hideDetails={props.hideDetails}
|
||||
defaultOpen={props.defaultOpen}
|
||||
animate
|
||||
@@ -1746,6 +1749,7 @@ ToolRegistry.register({
|
||||
render(props) {
|
||||
const data = useData()
|
||||
const i18n = useI18n()
|
||||
const dialog = useDialog()
|
||||
const args: string[] = []
|
||||
if (props.input.offset) args.push("offset=" + props.input.offset)
|
||||
if (props.input.limit) args.push("limit=" + props.input.limit)
|
||||
@@ -1755,6 +1759,10 @@ ToolRegistry.register({
|
||||
return value.filter((p): p is string => typeof p === "string")
|
||||
})
|
||||
const pending = createMemo(() => busy(props.status))
|
||||
const images = createMemo(() =>
|
||||
(props.attachments ?? []).filter((f) => f.mime.startsWith("image/") && f.url),
|
||||
)
|
||||
const preview = (url: string, alt?: string) => dialog.show(() => <ImagePreview src={url} alt={alt} />)
|
||||
return (
|
||||
<>
|
||||
<BasicTool
|
||||
@@ -1783,6 +1791,23 @@ ToolRegistry.register({
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
<Show when={images().length > 0}>
|
||||
<div data-slot="tool-read-images">
|
||||
<For each={images()}>
|
||||
{(file) => (
|
||||
<div data-slot="tool-read-image" onClick={() => preview(file.url, file.filename)}>
|
||||
<img
|
||||
data-slot="tool-read-image-img"
|
||||
src={file.url}
|
||||
alt={file.filename ?? i18n.t("ui.message.attachment.alt")}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user