feat(tool): 写类工具文件级互斥(读共享 / 写独占)
新增 tool/fileclaims.go:FileTargeter 可选接口,由工具声明本次调用要碰的文件 (动态声明、不猜正文 —— 同一工具的 path 在读/写语义不同)。 语义:读共享 / 写独占;两个读允许并行(主人「优先性能」口径);未知操作/裸路径按写处理(保守)。 占用键含操作类别(read/write,NUL 分隔),路径 Abs+Clean+Windows 大小写折叠;随最后占用者离场删键(有界)。 Dispatcher 默认装配进程内占用表(无需 cmd 侧接线);Invoke 登记 + defer 释放(成功/报错/超时/panic 四条路径)。 loop/tools.go 唯一接线:tool.WithLegID(ParallelLegFrom(ctx)) 桥接网关路标识。 判忙不阻塞、不排队死等;显式文案回灌(含文件名与状态)让 LLM 稍后重试。 测试 3 个新文件(占用表语义 / 接线确定性并发 / loop 桥与端到端);变异 5 条,另揪出并修一个 真隐患(空串既当「无人占用」哨兵又是合法路标识 ⇒ 改 (leg,busy) 返回)。 诚实边界:①「1 普通回合 + 1 并行路」时普通回合不受保护(网关只给 parallel 路盖 legID; 修法须与 checkpoint 归属一起裁决);② 目前无真实工具实现 FileTargeter ⇒ 机制就绪但占用表恒空, 真实保护待下一片给 file 等工具加声明。
This commit is contained in:
1 parent
c0dc435770
commit
354b08a45f
7 files changed
+1367
-12
No files matched your search
@@ -299,7 +299,10 @@ func (l *Loop) invokeOne(ctx context.Context, d *tool.Dispatcher, tc agent.ToolC
|
||||
}
|
||||
_, toolSpan := l.span(ctx, "tool."+tc.Name, trace.SpanKindTool)
|
||||
l.emitToolExecution(ctx, tc, model.StreamKindToolExecutionStart, model.ToolPhaseRunning)
|
||||
result, err := d.Invoke(ctx, tc.Name, tc.Args)
|
||||
// 路标识桥(design/15 §2.5.7、主人裁决 3):网关把「本回合属于哪条并发路」经
|
||||
// loop.WithParallelLeg 挂在 ctx 上,工具层按 tool.WithLegID 读它做文件级互斥
|
||||
// (工具侧唯一来源);未挂载 ⇒ 空串 ⇒ 完全不做互斥,行为逐字不变。
|
||||
result, err := d.Invoke(tool.WithLegID(ctx, ParallelLegFrom(ctx)), tc.Name, tc.Args)
|
||||
phase := model.ToolPhaseDone
|
||||
if err != nil {
|
||||
phase = model.ToolPhaseError
|
||||
|
||||
Reference in new issue
Block a user