Merge pull request #4354 from deepseek-harness/worktree/present-changes-dedup

通过提示词减少重复展示
This commit is contained in:
CreatixChu authored and GitHub committed 2026-09-18 17:33:28 +08:00
commit e651d00a9f
22 files changed
+63 -38

No files matched your search

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-09-08-present-workspace-source-files.md
2026-09-08-present-workspace-source-files.md: e1bc2bbc56d423741ca53550af2879fed3f01ecf
2026-09-08-present-workspace-source-files.zh.md: e4f21172b36a5fef50e44a79adca71011ee90a3b
2026-09-08-present-workspace-source-files.md: 52cc3e9cdbcd30d378117a327b86062523a2cb3e
2026-09-08-present-workspace-source-files.zh.md: 99b7b9df1d9ca2da2175df1ae7e9d8acbb5c5fdd
@@ -12,7 +12,7 @@ Users need to open and edit the files produced in their workspace, including she
The [present tool](../../../../packages/deliverables/tool-present/README.md) declares existing regular source files under the [Session filesystem access policy](2026-09-09-present-filesystem-access.md). It records paths and optional descriptions without reading or copying contents. The [deliverables plugin](../../../../packages/client/ui-deliverables/README.md) opens current workspace sources in the Host's default application. Edits are visible on the next open; deletion or movement makes the declaration unavailable. File-content preservation and copy-on-write storage are deferred until a persistence design owns them.
The tool description requires `present` after writing a file the user asked to receive and before the final response, including files created through Bash or code execution. A prose path reference does not replace the call. The recorded [SVG delivery scenario](../../../../snapshots/web/present-svg/snapshot.yml) uses a user request that does not name `present`, and checks the resulting file, delivery event, and card. Its UI snapshot covers the expanded Chat transcript; navigation and composer controls belong to their own scenarios, so unrelated chrome changes cannot invalidate file-delivery expectations.
The [tool description](../../../../packages/deliverables/tool-present/README.md#model-experience) guides the model's choice of files for explicit delivery. A declaration remains distinct from a prose file reference. The recorded [SVG delivery scenario](../../../../snapshots/web/present-svg/snapshot.yml) covers the resulting file, delivery event, and card. New recordings explicitly request a separate file card; replay preserves the recorded request. This scenario verifies explicit delivery, not a requirement to call `present` for every SVG. Its UI snapshot covers the expanded Chat transcript; navigation and composer controls belong to their own scenarios, so unrelated chrome changes cannot invalidate file-delivery expectations.
The tool remains an ordinary package with shared filesystem and tool error classes. Its pure type entry owns the delivery event without importing Host code into the browser. The `standard`, `ptc`, and `cordis` presets mount it; `minimal` retains its two tools. Each plugin instance correlates its executions with successful final `tools/result` notifications before appending `deliverables/presented`. Native and nested calls share this rule. A later enclosing program failure does not revoke a completed nested declaration; blocked results publish none, and same-name scoped replacements cannot publish another instance's results.
@@ -12,7 +12,7 @@ Status: implemented
[present 工具](../../../../packages/deliverables/tool-present/README.zh.md)声明交付[Session 文件系统访问策略](2026-09-09-present-filesystem-access.zh.md)允许的已有普通源文件。它记录路径和可选说明,不读取或复制内容。[交付插件](../../../../packages/client/ui-deliverables/README.zh.md)使用 Host 默认应用打开当前工作区源文件。下次打开会看到编辑后的内容;删除或移动文件会使声明不可用。文件内容保留与写时复制存储延期到有持久化设计负责时实现。
工具说明要求在写好用户要求接收的文件后、最终回复前调用 `present`,包括通过 Bash 或代码执行创建的文件。正文中的路径引用不能替代调用。录制的 [SVG 交付场景](../../../../snapshots/web/present-svg/snapshot.yml)使用未提及 `present` 的用户请求,检查生成文件、交付事件和卡片。其 UI 快照覆盖展开后的 Chat 对话内容;导航和输入框控件由各自场景负责,避免无关界面改动使文件交付预期失效。
[工具说明](../../../../packages/deliverables/tool-present/README.zh.md#model-experience)指导模型选择需要显式交付的文件。交付声明与正文中的文件引用各自独立。录制的 [SVG 交付场景](../../../../snapshots/web/present-svg/snapshot.yml)覆盖生成文件、交付事件和卡片。新录制明确请求独立文件卡片,回放保留录制时的请求。该场景验证显式交付,不要求所有 SVG 都调用 `present`。其 UI 快照覆盖展开后的 Chat 对话内容;导航和输入框控件由各自场景负责,避免无关界面改动使文件交付预期失效。
工具保持为普通包,共享文件系统和工具错误类型。其纯类型入口拥有交付事件,不向浏览器导入 Host 代码。`standard`、`ptc` 与 `cordis` preset 挂载工具;`minimal` 保持两个工具。每个插件实例将其执行与成功的最终 `tools/result` 通知关联,再追加 `deliverables/presented`。原生与嵌套调用遵循同一规则。外层程序随后失败不会撤销已完成的嵌套声明;被阻止的结果不发布声明,同名作用域替换也不能发布其他实例的结果。
@@ -1 +1 @@
When you successfully create or modify files, mention the primary outputs in your final response. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix.
Prefer showing the primary results within your final response alongside a brief explanation. Markdown file links such as [Report](path/to/report.html) open the file in the sidebar preview. For images, you can add an inline preview such as ![Preview](/absolute/path/image.png); include a file link as well so the image remains accessible in clients that cannot display it inline. Do not call present just to list edited source files, or run commands to check whether a diff view will appear. Use present when a separate file card helps the user open the complete deliverable, especially Office documents, spreadsheets, and slide decks. Each presented file adds a card below the reply, with preview and native-open actions. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. Avoid repeating results already shown inline unless the separate card adds useful access. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix.
+7 -6
View File
@@ -1,4 +1,4 @@
/** A file request elicits explicit SVG delivery without naming the present tool. */
/** An explicit file-card request exercises SVG delivery without naming the present tool. */
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
@@ -17,7 +17,7 @@ import { connectFreshWorkspaceZh, ZH_BROWSER_LOCALE } from './support.ts'
const DIR = fileURLToPath(new URL('../../../snapshots/web/present-svg', import.meta.url))
const FIXTURE = join(DIR, 'session.v3.jsonl')
const MODE = webSnapshotMode()
const PROMPT = '简单画一个 SVG 表示冯诺依曼架构, 保存为 von-neumann.svg'
const RECORD_PROMPT = '简单画一个 SVG 表示冯诺依曼架构,保存为 von-neumann.svg,并提供独立文件卡片,方便打开。'
const FILE = 'von-neumann.svg'
describe('web e2e: requested SVG is explicitly delivered', () => {
@@ -65,11 +65,12 @@ describe('web e2e: requested SVG is explicitly delivered', () => {
}
})
it('writes valid SVG and calls present before the final reply', async () => {
if (MODE !== 'record') expect(fixtureUserPrompts(await readFile(FIXTURE, 'utf8'))).toEqual([PROMPT])
it('writes valid SVG and provides the requested file card before the final reply', async () => {
const prompts = MODE === 'record' ? [RECORD_PROMPT] : fixtureUserPrompts(await readFile(FIXTURE, 'utf8'))
expect(prompts).toHaveLength(1)
const settled = scaffold.whenTurnSettled()
const input = page.locator('[data-composer-input]').first()
await input.fill(PROMPT)
await input.fill(prompts[0]!)
await input.press('Enter')
const sessionId = await settled
const session = scaffold.ctx.agents.get(sessionId)?.session
@@ -91,7 +92,7 @@ describe('web e2e: requested SVG is explicitly delivered', () => {
const events = session.snapshotEvents()
const declarations = events.filter(event => event.type === 'deliverables/presented')
const delivery = declarations.find(event => event.data.files.some(file => resolve(cwd, file.path) === join(cwd, FILE)))
expect(delivery, 'the file request must produce a successful present declaration').toBeDefined()
expect(delivery, 'explicit file-card delivery requires a successful present declaration').toBeDefined()
if (delivery === undefined) throw new Error('SVG was written but not delivered')
expect(events.some(event => (
event.type === 'tool/call' && event.data.name === 'present' && event.data.callId === delivery.data.callId
+2 -2
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/tool-catalog.md
tool-catalog.md: b133f9ba94276878b380999b3023210a5d627c6a
tool-catalog.zh.md: 3f63676e4eb379163352a6c6a590f868e53f6efb
tool-catalog.md: e737834ff79c78e514370be6548450401b5bd4ab
tool-catalog.zh.md: f15db56f7edfaa08ffdb794d57de5c4e3179a626
+1 -1
View File
@@ -627,7 +627,7 @@ The bash tool is the model-facing consumer of the bash executor seam. A `run_in_
### `present`
Declare existing files accessible through the Session filesystem as final deliverables. When a file you create or update is an output the user asked to receive, you must call present after writing it and before your final response, including files created through Bash or code execution. Mentioning its path in your reply does not replace this call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.
Declare selected existing files accessible through the Session filesystem as final deliverables. Use present when the user needs a separate file deliverable, especially Office documents, spreadsheets, and slide decks. Prefer showing results in your final response when that is sufficient; creating or editing a file does not by itself require present. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.
```json
{
+1 -1
View File
@@ -631,7 +631,7 @@ bash 工具是 bash 执行器 seam 面向模型的消费方。使用 `run_in_bac
### `present`
声明交付 Session 文件系统可访问的已有文件。如果你创建或更新的文件是用户要求接收的成果,则必须在写入完成后、最终回复前调用 present,包括通过 Bash 或代码执行创建的文件。在回复中提到文件路径不能替代这次调用。文件必须已存在。用户打开当前源文件;不复制或保存其内容。
选择 Session 文件系统可访问的已有文件,声明为最终交付物。当用户需要独立的文件交付物时使用 present,尤其是 Office 文档、电子表格和演示文稿。如果最终回复已经足够展示结果,优先在回复中展示;创建或编辑文件本身不要求调用 present。通常选择最重要的 1 至 2 项交付物,任务需要时可以更多,但一次 present 调用最多 4 个文件。文件必须已存在。用户打开当前源文件;不复制或保存其内容。
```json
{
@@ -25,6 +25,7 @@ describe('localPathMediaUrl', () => {
})
it('keeps non-HTTP transports inert', () => {
expect(localPathMediaUrl('dsh-app:', 'dsh-app://app', '/tmp/graph.png')).toBeUndefined()
expect(localPathMediaUrl('file:', 'file:///app', '/tmp/graph.png')).toBeUndefined()
expect(localPathMediaUrl('ws:', ORIGIN, '/tmp/graph.png')).toBeUndefined()
})
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-deliverables/README.md
README.md: 81b308e88ee40cfc6ff0e55bdad4620e1af06ec5
README.zh.md: 9d4b71bf4f7d81e3040ad2fdd67e49f4afde883e
README.md: 71f3545b8fb3fed3ecd678258e6c50bbfa4b580c
README.zh.md: 3e59ed2b7d4ac7e9d64b7d1f2f3c477e3ca1c50e
+4 -3
View File
@@ -38,7 +38,7 @@ The `present` tool row retains the delivery-document glyph while showing running
Developer tools must be enabled to show this card or request its summary. Turning the preference off removes the card immediately while explicit delivery cards, inline file links, and recorded workspace changes remain available.
The card renders the summary the Host serves for the turn's latest `workspace/changes` announcement, read once per announcement through the authenticated summary route; while the read is pending, once the Host answers that the summary is gone, or when it lists no file, there is no card. Its header names the complete changed-file count and summed added and deleted lines; hovering or focusing it replaces the counts with “Preview in sidebar”. Each row shows one file's display path with its own counts, “binary” for a binary file, or “too large” for a file the Host did not capture. Rows appear in the recorded display order, so repository files above the working directory and files outside it sort first. Four rows show before a fold; the control reveals every recorded file and, once expanded, collapses the list again from the bottom. Each row opens the turn's review in the right Sidebar on that file, and the header opens it on the first file. Final file deliveries still require `present`.
The card renders the summary the Host serves for the turn's latest `workspace/changes` announcement, read once per announcement through the authenticated summary route; while the read is pending, once the Host answers that the summary is gone, or when it lists no file, there is no card. Its header names the complete changed-file count and summed added and deleted lines; hovering or focusing it replaces the counts with “Preview in sidebar”. Each row shows one file's display path with its own counts, “binary” for a binary file, or “too large” for a file the Host did not capture. Rows appear in the recorded display order, so repository files above the working directory and files outside it sort first. Four rows show before a fold; the control reveals every recorded file and, once expanded, collapses the list again from the bottom. Each row opens the turn's review in the right Sidebar on that file, and the header opens it on the first file.
### The review tab
@@ -87,11 +87,11 @@ Read these pages when the deliverables surface is not enough. They move from the
#### What the model sees
The guidance asks the model to name primary outputs after successful creation or modification and link every existing-file mention outside commands, configuration expressions, and code blocks, including repeats and tables. Labels default to filenames or clear aliases, with only enough parent directories to distinguish files. Precise references display `filename:24` or `filename:24–30`; their destinations retain full relative or absolute paths with `#L24` or `#L24-L30` anchors. The display suffix contains neither `#` nor `L`.
The guidance prefers primary results in the final reply: file links open Sidebar previews, and image previews include a file link for clients without inline-image support. It recommends separate `present` cards for complete file deliverables, especially Office files, usually selecting the most important one or two, with at most four files per call when more are needed. It discourages cards solely for code edits and extra commands to inspect diff visibility. This guidance applies even with developer tools disabled: it accepts fewer file surfaces to avoid duplicate presentation and unnecessary tool calls. It asks the model to link every existing-file mention outside commands, configuration expressions, and code blocks, including repeats and tables. Labels default to filenames or clear aliases, with only enough parent directories to distinguish files. Precise references display `filename:24` or `filename:24–30`; their destinations retain full relative or absolute paths with `#L24` or `#L24-L30` anchors. The display suffix contains neither `#` nor `L`.
#### Token effect
One fixed paragraph containing an output reminder and file-reference guidance whenever this package is loaded. The [present tool](../../deliverables/tool-present/README.md#model-experience) owns the delivery schema and result text.
One fixed paragraph containing output-selection, rendering, and file-reference guidance whenever this package is loaded. The [present tool](../../deliverables/tool-present/README.md#model-experience) owns the delivery schema and result text.
#### KV Cache effect
@@ -104,6 +104,7 @@ The section is static at first-party order 9000 for the lifetime of the package
These limits define the current deliverables vocabulary. They are current package constraints, not a general file-linking comparison or a task backlog.
- **Inline local images require HTTP(S) and POSIX absolute paths**: Desktop’s `dsh-app:` pages and Windows drive-letter paths do not support inline local images. The guidance retains a Markdown file link so users can open the Sidebar preview.
- **Mention matching is exact path or unique basename only** — a suffix mention stays inert; widening the matcher is deferred until a real closing-message shape needs it.
- **Terminal-created files require explicit delivery** — the card lists them once git records the change, but delivery cards and inline-code references require `present`; explicit Markdown links can reference existing files directly.
- **Declarations do not preserve file contents** — reopening or transferring a Session requires source files accessible through the viewed Session’s filesystem. Missing files, directories, and final symbolic links return 404.
+4 -3
View File
@@ -38,7 +38,7 @@ Web 的 `standard`、`ptc` 与 `cordis` preset 提供 `present` 用于声明交
只有开启开发者工具才展示此卡片并请求其摘要。关闭该偏好会立即隐藏卡片,同时保留显式交付卡片、行内文件链接和已记录的工作区改动。
卡片渲染 Host 为本轮最新一条 `workspace/changes` 宣告提供的摘要,每条宣告通过经过认证的摘要路由读取一次;读取尚未完成、Host 答复摘要已不存在,或摘要没有列出任何文件时,没有卡片。标题给出改动文件总数与增删行数合计;鼠标悬停或键盘聚焦时,统计信息替换为“在侧边栏预览”。每一行显示一个文件的展示路径及其增删行数,二进制文件显示“二进制”,Host 没有捕获的文件显示“过大”。行按记录的展示顺序排列,因此仓库内位于工作目录之上的文件与工作区外的文件排在最前。折叠前显示四行;控件展开全部记录文件,展开后从底部收起列表。每一行在右侧 Sidebar 中打开本轮的 review 并选中该文件,标题则在第一个文件上打开它。最终文件交付仍需调用 `present`。
卡片渲染 Host 为本轮最新一条 `workspace/changes` 宣告提供的摘要,每条宣告通过经过认证的摘要路由读取一次;读取尚未完成、Host 答复摘要已不存在,或摘要没有列出任何文件时,没有卡片。标题给出改动文件总数与增删行数合计;鼠标悬停或键盘聚焦时,统计信息替换为“在侧边栏预览”。每一行显示一个文件的展示路径及其增删行数,二进制文件显示“二进制”,Host 没有捕获的文件显示“过大”。行按记录的展示顺序排列,因此仓库内位于工作目录之上的文件与工作区外的文件排在最前。折叠前显示四行;控件展开全部记录文件,展开后从底部收起列表。每一行在右侧 Sidebar 中打开本轮的 review 并选中该文件,标题则在第一个文件上打开它。
### review tab
@@ -87,11 +87,11 @@ Node 半部注册[模型体验](#model-experience)所述的静态 `ui:deliverabl
#### 模型看到的内容
提示词要求模型在成功创建或修改文件后点名主要产出,并链接命令、配置表达式和代码块以外的每次现有文件提及,包括重复提及和表格。标签默认使用文件名或清楚的别名,仅添加足以区分文件的父目录。精确引用显示为 `filename:24` 或 `filename:24–30`;目标保留完整相对路径或绝对路径,以及 `#L24` 或 `#L24-L30` 锚点。显示后缀不含 `#` 或 `L`。
提示词建议在最终回复中展示主要结果:文件链接打开 Sidebar 预览,图片预览同时保留文件链接,供不支持行内图片的客户端使用。对于需要完整文件的交付,尤其是 Office 文件,建议使用独立的 `present` 卡片,通常选最重要的一两项,需要时可以更多,但每次调用最多四项。提示词建议避免仅为列出代码改动生成卡片,也不为确认 diff 是否显示额外运行命令。开发者工具关闭时仍采用这条建议,接受较少的文件展示入口,以减少重复展示和不必要的工具调用。文件引用要求链接命令、配置表达式和代码块以外的每次现有文件提及,包括重复提及和表格。标签默认使用文件名或清楚的别名,仅添加足以区分文件的父目录。精确引用显示为 `filename:24` 或 `filename:24–30`;目标保留完整相对路径或绝对路径,以及 `#L24` 或 `#L24-L30` 锚点。显示后缀不含 `#` 或 `L`。
#### Token 影响
加载本包时增加一段包含产出提醒和文件引用指导的固定提示词。[present 工具](../../deliverables/tool-present/README.zh.md#model-experience)拥有交付 schema 和结果文本。
加载本包时增加一段包含产出选择、渲染效果和文件引用指导的固定提示词。[present 工具](../../deliverables/tool-present/README.zh.md#model-experience)拥有交付 schema 和结果文本。
#### KV Cache 影响
@@ -104,6 +104,7 @@ Node 半部注册[模型体验](#model-experience)所述的静态 `ui:deliverabl
这些限制界定了当前产出物词表。它们是当前包约束,不是通用文件链接对比或任务积压。
- **本地行内图片要求 HTTP(S) 页面和 POSIX 绝对路径**:Desktop 的 `dsh-app:` 页面和 Windows 盘符路径不支持本地行内图片。提示词要求保留 Markdown 文件链接,让用户仍可打开 Sidebar 预览。
- **提及匹配只认精确路径或唯一 basename**——后缀式提及保持惰性;等真实的收尾消息形态产生需求后再放宽匹配规则。
- **终端创建的文件需要显式交付**——git 记录到改动后卡片会列出它们,但交付卡片和行内代码引用需要调用 `present`;显式 Markdown 链接可以直接引用现有文件。
- **声明不保存文件内容**:重新打开或转移 Session 后,源文件仍需能被当前查看的 Session 文件系统访问。文件缺失、为目录或最终路径为符号链接时返回 404。
+5 -1
View File
@@ -14,7 +14,11 @@ import { registerPresentOpen } from './present-open.ts'
export const inject = ['systemPrompt', 'connection', 'sessionQuery', 'sessionController', 'workspaceFiles', 'fs', 'sandboxPolicy', 'workspaceChanges']
/** Static Web guidance for primary outputs and existing-file references. */
const FILE_REFERENCE_PROMPT = 'When you successfully create or modify files, mention the primary outputs in your final response. '
const FILE_REFERENCE_PROMPT = 'Prefer showing the primary results within your final response alongside a brief explanation. '
+ 'Markdown file links such as [Report](path/to/report.html) open the file in the sidebar preview. For images, you can add an inline preview such as ![Preview](/absolute/path/image.png); include a file link as well so the image remains accessible in clients that cannot display it inline. '
+ 'Do not call present just to list edited source files, or run commands to check whether a diff view will appear. '
+ 'Use present when a separate file card helps the user open the complete deliverable, especially Office documents, spreadsheets, and slide decks. Each presented file adds a card below the reply, with preview and native-open actions. '
+ 'Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. Avoid repeating results already shown inline unless the separate card adds useful access. '
+ 'Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. '
+ 'Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix.'
@@ -29,9 +29,10 @@ describe('ui-deliverables node plugin', () => {
const section = (await ctx.systemPrompt.assemble()).sections
.find(entry => entry.name === 'ui:deliverable-file-references')
expect(section?.text).toMatchInlineSnapshot('"When you successfully create or modify files, mention the primary outputs in your final response. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix."')
expect(section?.text).toMatchInlineSnapshot('"Prefer showing the primary results within your final response alongside a brief explanation. Markdown file links such as [Report](path/to/report.html) open the file in the sidebar preview. For images, you can add an inline preview such as ![Preview](/absolute/path/image.png); include a file link as well so the image remains accessible in clients that cannot display it inline. Do not call present just to list edited source files, or run commands to check whether a diff view will appear. Use present when a separate file card helps the user open the complete deliverable, especially Office documents, spreadsheets, and slide decks. Each presented file adds a card below the reply, with preview and native-open actions. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. Avoid repeating results already shown inline unless the separate card adds useful access. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix."')
for (const scenario of ['cordis-tool-round', 'fresh-round-trip', 'ptc-round', 'schedule-catalog']) {
// Only live request pins track current guidance; seeded sessions retain their recorded prompt.
for (const scenario of ['fresh-round-trip', 'ptc-round']) {
const sidecar = await readFile(new URL(`../../../../snapshots/web/${scenario}/system-prompt.expected.md`, import.meta.url), 'utf8')
expect(sidecar, scenario).toContain(section!.text)
}
@@ -29,6 +29,21 @@ describe('Markdown file links', () => {
expect(view.container.querySelector('a')).toBeNull()
})
it.each(['/workspace/chart.png', 'C:/work/chart.png'])('keeps %s accessible when inline images are unavailable', (path) => {
const openFile = vi.fn()
const view = render(
<MarkdownDelegateProvider openFile={openFile}>
<MarkdownText
text={`![Preview](${path}) [Open image](${path})`}
pathImages={{ resolve: () => undefined }}
/>
</MarkdownDelegateProvider>,
)
expect(view.container.querySelector('img')).toBeNull()
fireEvent.click(view.getByRole('button', { name: 'Open image' }))
expect(openFile).toHaveBeenCalledExactlyOnceWith(path, undefined)
})
it.each(['', '![](https://example.com/image.png)'])('names an empty label %s with the decoded path', (label) => {
const view = render(
<MarkdownDelegateProvider openFile={vi.fn()}>
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/deliverables/tool-present/README.md
README.md: 93003711545f678336a02c9bf8589176f844af65
README.zh.md: 161efcc3931fbf57175064ccf1179b195320d4b9
README.md: a7eb9e7cf9060472258666de186a7ecefe7aa407
README.zh.md: 5ba4ab5f100517708d80e4860d9e5eed0f43a801
+1 -1
View File
@@ -73,7 +73,7 @@ The pure `./types` entry declares `PresentedFile` and the Session event without
#### What the model sees
The [present schema](../../../docs/tool-catalog.md#present) asks for existing accessible files: “Declare existing files accessible through the Session filesystem as final deliverables. When a file you create or update is an output the user asked to receive, you must call present after writing it and before your final response, including files created through Bash or code execution. Mentioning its path in your reply does not replace this call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.” Results report `Presented <path>` for each file; the program result and durable event contain paths and optional descriptions.
The [present schema](../../../docs/tool-catalog.md#present) asks for existing accessible files: “Declare selected existing files accessible through the Session filesystem as final deliverables. Use present when the user needs a separate file deliverable, especially Office documents, spreadsheets, and slide decks. Prefer showing results in your final response when that is sufficient; creating or editing a file does not by itself require present. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.” Results report `Presented <path>` for each file; the program result and durable event contain paths and optional descriptions.
#### Token effect
@@ -73,7 +73,7 @@ kind: "package-reference"
#### 模型看到的内容
[present schema](../../../docs/tool-catalog.zh.md#present)要求已有且可访问的文件:“Declare existing files accessible through the Session filesystem as final deliverables. When a file you create or update is an output the user asked to receive, you must call present after writing it and before your final response, including files created through Bash or code execution. Mentioning its path in your reply does not replace this call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.” 每个文件的结果为 `Presented <path>`;程序结果和持久事件包含路径及可选说明。
[present schema](../../../docs/tool-catalog.zh.md#present)要求已有且可访问的文件:“Declare selected existing files accessible through the Session filesystem as final deliverables. Use present when the user needs a separate file deliverable, especially Office documents, spreadsheets, and slide decks. Prefer showing results in your final response when that is sufficient; creating or editing a file does not by itself require present. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.” 每个文件的结果为 `Presented <path>`;程序结果和持久事件包含路径及可选说明。
#### Token 影响
@@ -37,10 +37,11 @@ export function apply(ctx: Context, config: Config): void {
const pending = new WeakMap<ToolExecution, { session: Session; turn: number; files: PresentedFile[] }>()
ctx.tools.register(defineTool({
name: 'present',
description: 'Declare existing files accessible through the Session filesystem as final deliverables. '
+ 'When a file you create or update is an output the user asked to receive, you must call present after writing it and before your final response, including files created through Bash or code execution. '
+ 'Mentioning its path in your reply does not replace this call. The files must already exist. '
+ 'The user opens the current source files; their contents are not copied or preserved.',
description: 'Declare selected existing files accessible through the Session filesystem as final deliverables. '
+ 'Use present when the user needs a separate file deliverable, especially Office documents, spreadsheets, and slide decks. '
+ 'Prefer showing results in your final response when that is sufficient; creating or editing a file does not by itself require present. '
+ 'Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. '
+ 'The files must already exist. The user opens the current source files; their contents are not copied or preserved.',
parameters: {
files: {
type: 'array', required: true,
@@ -30,7 +30,7 @@ Use subagent in the background by default. Start independent delegations togethe
Use subagent_fork in the background by default. Start independent delegations together in one assistant message and continue useful work while they run. Set `run_in_background: false` only when your next action depends on that subagent's result. When a background run settles, the runtime sends you a notice containing its outcome and any final assistant message.
When you successfully create or modify files, mention the primary outputs in your final response. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix.
Prefer showing the primary results within your final response alongside a brief explanation. Markdown file links such as [Report](path/to/report.html) open the file in the sidebar preview. For images, you can add an inline preview such as ![Preview](/absolute/path/image.png); include a file link as well so the image remains accessible in clients that cannot display it inline. Do not call present just to list edited source files, or run commands to check whether a diff view will appear. Use present when a separate file card helps the user open the complete deliverable, especially Office documents, spreadsheets, and slide decks. Each presented file adds a card below the reply, with preview and native-open actions. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. Avoid repeating results already shown inline unless the separate card adds useful access. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix.
The DeepSeek Harness implementation checkout is at {{sourceRoot}}. The checkout location and current working directory are separate values and may differ; never infer the working directory from this path. Use pwd to determine the current working directory. Use this checkout only to inspect or extend DSH itself.
@@ -325,7 +325,7 @@
},
{
"name": "present",
"description": "Declare existing files accessible through the Session filesystem as final deliverables. When a file you create or update is an output the user asked to receive, you must call present after writing it and before your final response, including files created through Bash or code execution. Mentioning its path in your reply does not replace this call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.",
"description": "Declare selected existing files accessible through the Session filesystem as final deliverables. Use present when the user needs a separate file deliverable, especially Office documents, spreadsheets, and slide decks. Prefer showing results in your final response when that is sufficient; creating or editing a file does not by itself require present. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. The files must already exist. The user opens the current source files; their contents are not copied or preserved.",
"parameters": {
"type": "object",
"properties": {
@@ -160,7 +160,7 @@ interface ToolArgsMap {
/** children (default) lists direct children only; descendants walks the complete tree below you. */
scope?: "children" | "descendants";
} & Record<string, JsonValue>;
/** Declare existing files accessible through the Session filesystem as final deliverables. When a file you create or update is an output the user asked to receive, you must call present after writing it and before your final response, including files created through Bash or code execution. Mentioning its path in your reply does not replace this call. The files must already exist. The user opens the current source files; their contents are not copied or preserved. */
/** Declare selected existing files accessible through the Session filesystem as final deliverables. Use present when the user needs a separate file deliverable, especially Office documents, spreadsheets, and slide decks. Prefer showing results in your final response when that is sufficient; creating or editing a file does not by itself require present. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. The files must already exist. The user opens the current source files; their contents are not copied or preserved. */
present: {
files: {
/** Path of an existing regular file. Relative paths use the Session working directory. */
@@ -540,7 +540,7 @@ declare const tools: {
}
```
When you successfully create or modify files, mention the primary outputs in your final response. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix.
Prefer showing the primary results within your final response alongside a brief explanation. Markdown file links such as [Report](path/to/report.html) open the file in the sidebar preview. For images, you can add an inline preview such as ![Preview](/absolute/path/image.png); include a file link as well so the image remains accessible in clients that cannot display it inline. Do not call present just to list edited source files, or run commands to check whether a diff view will appear. Use present when a separate file card helps the user open the complete deliverable, especially Office documents, spreadsheets, and slide decks. Each presented file adds a card below the reply, with preview and native-open actions. Usually select the 1-2 most important deliverables; include more when needed, but at most 4 files in a single present call. Avoid repeating results already shown inline unless the separate card adds useful access. Outside commands, configuration expressions, and code blocks, link every mention of an existing file, including repeats and tables, to its full path relative to the working directory or absolute; append #L24 or #L24-L30 to the target for known lines. Use the filename or a clear alias as the label, adding only enough parent directories to distinguish files; keep full paths out of labels. Default to the name alone; when precise locations matter, append :24 or :24–30, with no # or L in the line suffix.
The DeepSeek Harness implementation checkout is at {{sourceRoot}}. The checkout location and current working directory are separate values and may differ; never infer the working directory from this path. Use pwd to determine the current working directory. Use this checkout only to inspect or extend DSH itself.