toolTargetKey is the stable identity used to detect a repeated-failure loop: tool name + its target (the path for file tools, the command's first line for bash). Deliberately NOT the full argument set: a full-args key is defeated by any cosmetic change between retries (a regenerated file body, a rew
(call chmctx.ToolCall)
| 1084 | case tools.WriteFileName, tools.EditFileName, tools.ReadFileName: |
| 1085 | path, _ := call.Arguments["path"].(string) |
| 1086 | return call.Name + "|" + path |
| 1087 | case tools.BashName: |
| 1088 | cmd, _ := call.Arguments["cmd"].(string) |
| 1089 | if i := strings.IndexByte(cmd, '\n'); i >= 0 { |
| 1090 | cmd = cmd[:i] |
| 1091 | } |
| 1092 | return call.Name + "|" + strings.TrimSpace(cmd) |
| 1093 | } |
| 1094 | return call.Name |
| 1095 | } |
| 1096 | |
| 1097 | // toolResultFailed reports whether a tool result is an error the model should |
| 1098 | // react to. File tools wrap errors in parens ("(write error: ...)", "(not |
| 1099 | // found: ...)") and report success as plain text ("wrote N bytes"); bash |
| 1100 | // appends "(exit: N)" / "(timeout after ...)" on failure. A user Ctrl+C |
| 1101 | // ("(cancelled)") never counts as a failure. |
| 1102 | func toolResultFailed(name, result string) bool { |
no outgoing calls