Files
ycode/src/main/agent/tools/sandbox-workspace.ts
T

21 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Tool } from './index'
import type { SandboxWorkspaceAction } from '@shared/sandbox'
import { workspaceAction } from '../../sandbox/workspace-service'
export const sandboxWorkspaceTool: Tool = {
name: 'sandbox_workspace',
description: '管理当前会话的长期沙盒草稿。status 查询已保存状态;changes 同步宿主未冲突的外部编辑并查看差异;commit 经批准写入宿主项目;discard 归档草稿并重新读取宿主;recover 恢复中断或核对宿主结果。用 execute_command 的 workspace=persistent 读写草稿,普通文件工具仍读写宿主。默认私有 Git 不写宿主 .git;若已用 sandbox_git 导入真实仓库或创建/克隆新仓库,commit/discard/recover 会统一处理文件与 Git 元数据。不接受其他会话或任意目录。',
parameters: { type: 'object', properties: { action: { type: 'string', enum: ['status', 'changes', 'commit', 'discard', 'recover'] }, expectedRevision: { type: 'string', description: '可选的已观察版本;版本变化时拒绝操作。' } }, required: ['action'], additionalProperties: false },
async run(args, ctx) {
if (Object.keys(args).some(key => key !== 'action' && key !== 'expectedRevision')) throw new Error('长期工作区不接受路径或其他调用归属参数')
if (typeof args.action !== 'string' || !['status', 'changes', 'commit', 'discard', 'recover'].includes(args.action) || args.expectedRevision !== undefined && typeof args.expectedRevision !== 'string') throw new Error('长期工作区参数无效')
if (!ctx.sessionId) throw new Error('长期工作区必须由宿主会话调用')
const data = await workspaceAction(args.action as SandboxWorkspaceAction, { ...ctx, sessionId: ctx.sessionId }, args.expectedRevision as string | undefined)
const ok = !data.reason && !['conflict', 'stale', 'interrupted', 'invalid'].includes(data.state) && data.writeback !== 'rejected'
const content = [`长期工作区:${data.state};${data.changes.length} 项待提交变更。`,
data.writeback === 'committed' ? data.git ? '已按审批一起保存项目文件与真实宿主 Git 元数据。' : '已按审批保存到宿主项目;私有 Git 不写宿主 .git。' : '此草稿尚未自动写入宿主项目。',
...data.changes.slice(0, 50).map(change => `${change.operation}: ${change.path}`), data.reason ?? ''].filter(Boolean).join('\n')
return { ok, content, data }
}
}