Add filesystem capability seam and tools

This commit is contained in:
Dudu-0223
2026-06-22 10:48:41 +08:00
parent 6b4dc48fbd
commit 5e01564afb
36 changed files with 3515 additions and 1 deletions

View File

@@ -0,0 +1,82 @@
/**
* The model-facing `edit` tool: update an existing UTF-8 text file by replacing
* literal text, requiring a unique match by default. Execution goes through
* `ctx.fs`, which enforces prior observation and the stale-version guard and
* owns the literal-match semantics.
*
* @module @deepseek-ai/dsh-tool-fs/edit
*/
import type { Context } from 'cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
import type { FsEditOutcome } from '@deepseek-ai/dsh-fs'
import type {} from '@deepseek-ai/dsh-system-prompt'
/** Validated `edit` arguments after defaulting. */
interface EditInput {
filePath: string
oldString: string
newString: string
replaceAll: boolean
}
/** Validate value constraints the schema DSL can't express. */
export function parseEditArgs(args: { file_path: string; old_string: string; new_string: string; replace_all?: boolean }): EditInput {
if (args.file_path.trim().length === 0) throw new Error('file_path must be a non-empty string')
if (args.old_string.length === 0) throw new Error('old_string must be a non-empty string')
if (args.old_string === args.new_string) throw new Error('old_string and new_string must differ')
return {
filePath: args.file_path,
oldString: args.old_string,
newString: args.new_string,
replaceAll: args.replace_all ?? false,
}
}
/** Format an edit outcome as a Claude-style model-facing success message. */
export function formatEditOutput(displayPath: string, outcome: FsEditOutcome): string {
return outcome.replaceAll
? `The file ${displayPath} has been updated. All occurrences were successfully replaced.`
: `The file ${displayPath} has been updated successfully.`
}
/** Register the `edit` tool and its system-prompt guidance. */
export function apply(ctx: Context): void {
ctx.systemPrompt.section({
name: 'tool:edit',
order: 102,
text: 'Use the edit tool for targeted changes to existing UTF-8 text files. It replaces literal old_string with new_string; by default old_string must appear exactly once. If old_string appears multiple times, provide a more specific old_string or set replace_all to true.',
})
ctx.tools.register(defineTool({
name: 'edit',
description: 'Edit an existing UTF-8 text file by replacing literal text.',
parameters: {
file_path: { type: 'string', required: true, description: 'Path to edit, resolved by the filesystem backend.' },
old_string: { type: 'string', required: true, description: 'Literal text to replace. Must match exactly.' },
new_string: { type: 'string', required: true, description: 'Literal replacement text. Use an empty string to delete the match.' },
replace_all: { type: 'boolean', description: 'Replace all matches. Defaults to false; when false, old_string must appear exactly once.' },
},
async execute(args, exec): Promise<ContentBlock[]> {
const input = parseEditArgs(args)
const target = await ctx.fs.resolve(input.filePath)
const outcome = await ctx.fs.edit(
target,
{ oldString: input.oldString, newString: input.newString, replaceAll: input.replaceAll },
exec,
exec.signal,
)
return [{ type: 'text', text: formatEditOutput(target.displayPath, outcome) }]
},
}))
}
/** Cordis plugin name used by loader diagnostics. */
export const name = 'fs-edit'
/** Services required by the `edit` tool plugin. */
export const inject = ['tools', 'fs', 'systemPrompt']
/** Named helper for direct registration in the root plugin and tests. */
export const applyEditTool = apply