新增: 批次工作落地(推进链/评估闭环/事件总线/并发/加固) + 技术债清理 + 文档整理
后端: - 工作流推进链(D-03):advance_task/状态机/闸门走 df-nodes Node trait,conditions 条件引擎扩展 - 想法评估闭环:启发式评分+对抗评估,df-ideas/scoring + df-storage/idea_eval_repo + idea 前端打通 - 全局事件数据总线:df-ai/context+context_helpers+augmentation 跨模块解耦 - AI planner/plan_hint/intent:aichat B 路线并行多轮基础 - patch_file 加固(TD-03/04):读改写整体锁防 lost update,expected_hash 合约闭环 - 压缩超时兜底(F-15 卡死根治) - F-09 多会话并发:LlmConcurrency per-conv + streamingGuard 前端守护 + verify 脚本 - 知识注入 DRY/skills/audit 扩展 清理: - aichat 技术债(误报 allow/死导入/过时注释 30 项) - URGENT.md 删除(11 项加急全解决/迁 todo) - 文档整理(todo/待决策/待审查/ARCHITECTURE/INDEX + 总线/技术债审查新文档)
This commit is contained in:
@@ -85,11 +85,25 @@ export interface ToolResult {
|
||||
body?: string
|
||||
body_bytes?: number
|
||||
elapsed_ms?: number
|
||||
// grep 跨文件内容搜索结果字段(F-260621):
|
||||
// - output_mode: content(默认)/ files_with_matches / count
|
||||
// - matches: content 模式命中行 [{file,line,content,context?}]
|
||||
// - files: files_with_matches 模式命中文件名数组
|
||||
// - counts: count 模式每文件命中行数 [{file,count}]
|
||||
// - total: 命中总数(content 模式=命中行数,count 模式=命中行数,files_with_matches 模式=命中文件数)
|
||||
// - total_files: count 模式命中文件数
|
||||
output_mode?: string
|
||||
matches?: Array<{ file?: string; line?: number | null; content?: string; context?: string }>
|
||||
files?: string[]
|
||||
counts?: Array<{ file?: string; count?: number }>
|
||||
total_files?: number
|
||||
}
|
||||
|
||||
/** 内联 SVG 图标字符串(经 v-html 注入,常量安全;图标库改造见决策记录) */
|
||||
export const dirIcon = '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/></svg>'
|
||||
export const fileIcon = '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>'
|
||||
/** grep 工具放大镜图标(跨文件内容搜索,F-260621) */
|
||||
export const searchIcon = '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>'
|
||||
|
||||
/** 默认保持展开:执行中/待审批/已拒绝/write_file——折叠无收益 */
|
||||
export function shouldKeepOpen(tc: AiToolCallInfo): boolean {
|
||||
@@ -223,6 +237,7 @@ export function toolCategory(name: string): string {
|
||||
export function toolIcon(name: string): string {
|
||||
if (name === 'read_file') return '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>'
|
||||
if (name === 'write_file') return '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>'
|
||||
if (name === 'grep') return '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>'
|
||||
if (name === 'list_directory') return dirIcon
|
||||
if (name.includes('create')) return '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>'
|
||||
if (name.includes('delete')) return '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>'
|
||||
@@ -405,6 +420,31 @@ function formatSearchFiles(r: ToolResult): string {
|
||||
return t('aiTool.foundN', { n })
|
||||
}
|
||||
|
||||
/**
|
||||
* grep 摘要/命中计数标签(F-260621):按 output_mode 取合适文案,三分支:
|
||||
* - content(默认):「命中 N 处」(total = 命中行数,total 缺省回退 matches.length)
|
||||
* - files_with_matches:「命中 N 文件」(files.length)
|
||||
* - count:「命中 N 处 / M 文件」(total 行数 + total_files)
|
||||
*
|
||||
* 抽公共单一函数 G-1:原 ToolResultBody.vue grepHitLabel 与此处 formatGrep 三分支逐行等价,
|
||||
* 现 export 此函数,ToolResultBody.vue 复用,消除文案漂移风险。i18n 走 @/i18n/i18n-helpers 类型安全 t。
|
||||
*/
|
||||
export function formatGrep(r: ToolResult): string {
|
||||
const mode = r.output_mode
|
||||
if (mode === 'files_with_matches') {
|
||||
const n = Array.isArray(r.files) ? r.files.length : 0
|
||||
return t('aiTool.grepFilesN', { n })
|
||||
}
|
||||
if (mode === 'count') {
|
||||
const total = typeof r.total === 'number' ? r.total : 0
|
||||
const files = typeof r.total_files === 'number' ? r.total_files : 0
|
||||
return t('aiTool.grepCountSummary', { n: total, files })
|
||||
}
|
||||
// content(默认)
|
||||
const n = typeof r.total === 'number' ? r.total : (Array.isArray(r.matches) ? r.matches.length : 0)
|
||||
return t('aiTool.grepHitsN', { n })
|
||||
}
|
||||
|
||||
/**
|
||||
* rename_file 格式化(body 版): renamed===false 走 formatJson 兜底(summary 版走空串)。
|
||||
* 故 body 与 summary 分别登记不同 formatter。
|
||||
@@ -454,6 +494,7 @@ const TOOL_FORMATTERS: Record<string, (r: ToolResult) => string> = {
|
||||
bind_directory: formatBindDir,
|
||||
run_workflow: formatRunWorkflow,
|
||||
http_request: formatHttpResult,
|
||||
grep: formatGrep,
|
||||
}
|
||||
|
||||
export function formatToolResult(tc: AiToolCallInfo): string {
|
||||
@@ -611,6 +652,7 @@ const TOOL_SUMMARIES: Record<string, (r: ToolResult) => string> = {
|
||||
bind_directory: summaryBindDir,
|
||||
run_workflow: summaryRunWorkflow,
|
||||
http_request: summaryHttpRequest,
|
||||
grep: formatGrep,
|
||||
}
|
||||
|
||||
export function toolResultSummary(tc: AiToolCallInfo): string {
|
||||
|
||||
Reference in New Issue
Block a user