feat(fs): add a minimal read_image tool over the attachment and fs seams
The model reads a PNG/JPEG/WebP/GIF file, the bytes commit through the durable attachment lifecycle, and the tool result carries the real ImageBlock so the image enters context from the next request onward. FileSystem gains a bounded readBytes primitive (local + E2B providers); registration is conditional on the attachment store, and a strict execution gate refuses routes that do not declare image input, so a text route's durable history stays free of image blocks. llm-replay models may declare inputModalities, letting keyless ACP snapshots pin both the sha256-referenced success and the verbatim refusal. Supersedes the withdrawn route-scoped design of PR #598; the decision record is .agents/notes/implemented/feature/2026-08-10-minimal-read-image-tool.md.
This commit is contained in:
@@ -19,6 +19,7 @@ import type {
|
||||
LlmModelInfo,
|
||||
LlmProviderInfo,
|
||||
LlmResolvedModelInfo,
|
||||
ModelModality,
|
||||
ResolvedRetryPolicy,
|
||||
RetryPolicyConfig,
|
||||
StreamChunk,
|
||||
@@ -51,6 +52,8 @@ export interface ReplayModelConfig {
|
||||
description?: string
|
||||
/** Optional positive integer context capacity published by the replay adapter. */
|
||||
contextWindow?: number
|
||||
/** Optional declared input modalities, so a scenario can exercise capability gates (e.g. image-capable `read_image`). */
|
||||
inputModalities?: readonly ModelModality[]
|
||||
}
|
||||
|
||||
/** One provider route exposed by the replay adapter. */
|
||||
@@ -569,6 +572,7 @@ class ReplayAdapter extends LlmAdapter {
|
||||
id: model.id,
|
||||
name: model.name ?? model.id,
|
||||
...model.description === undefined ? {} : { description: model.description },
|
||||
...model.inputModalities === undefined ? {} : { inputModalities: [...model.inputModalities] },
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -582,6 +586,9 @@ class ReplayAdapter extends LlmAdapter {
|
||||
id: model,
|
||||
name: configuredModel?.name ?? model,
|
||||
...configuredModel?.description === undefined ? {} : { description: configuredModel.description },
|
||||
...configuredModel?.inputModalities === undefined
|
||||
? {}
|
||||
: { inputModalities: [...configuredModel.inputModalities] },
|
||||
...configuredModel?.contextWindow === undefined
|
||||
? {}
|
||||
: { context: { contextWindow: configuredModel.contextWindow } },
|
||||
|
||||
Reference in New Issue
Block a user