@@ -646,14 +646,13 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
646646 }
647647
648648 // Use per-request model override if set (e.g. heartbeat uses cheaper model).
649- chatMessages := messages
650649 model := l .model
651650 if req .ModelOverride != "" {
652651 model = req .ModelOverride
653652 }
654653
655654 chatReq := providers.ChatRequest {
656- Messages : chatMessages ,
655+ Messages : messages ,
657656 Tools : toolDefs ,
658657 Model : model ,
659658 Options : map [string ]any {
@@ -899,10 +898,10 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
899898 argsJSON , _ := json .Marshal (tc .Arguments )
900899 slog .Info ("tool call" , "agent" , l .id , "tool" , tc .Name , "args_len" , len (argsJSON ))
901900
902- argsHash := loopDetector .record (tc .Name , tc .Arguments )
901+ registryName := l .resolveToolCallName (tc .Name )
902+ argsHash := loopDetector .record (registryName , tc .Arguments )
903903
904904 toolSpanStart := time .Now ().UTC ()
905- registryName := l .resolveToolCallName (tc .Name )
906905 toolSpanID := l .emitToolSpanStart (ctx , toolSpanStart , tc .Name , tc .ID , string (argsJSON ))
907906
908907 stopSlowTimer := toolTiming .StartSlowTimer (tc .Name , l .id , req .RunID , slowToolEnabled , emitRun )
@@ -936,7 +935,7 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
936935
937936 // Record result for loop detection.
938937 loopDetector .recordResult (argsHash , result .ForLLM )
939- loopDetector .recordMutation (tc . Name )
938+ loopDetector .recordMutation (registryName )
940939
941940 if result .Async {
942941 asyncToolCalls = append (asyncToolCalls , tc .Name )
@@ -956,7 +955,7 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
956955 teamTaskSpawns ++
957956 }
958957 }
959- if hadBootstrap && bootstrapToolAllowlist [tc . Name ] {
958+ if hadBootstrap && bootstrapToolAllowlist [registryName ] {
960959 bootstrapWriteDetected = true
961960 }
962961
@@ -1006,14 +1005,14 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
10061005 pendingMsgs = append (pendingMsgs , toolMsg )
10071006
10081007 // Check for tool call loop after recording result.
1009- if level , msg := loopDetector .detect (tc . Name , argsHash ); level != "" {
1008+ if level , msg := loopDetector .detect (registryName , argsHash ); level != "" {
10101009 if level == "critical" {
1011- slog .Warn ("tool loop critical" , "agent" , l .id , "tool" , tc . Name , "message" , msg )
1012- finalContent = "I was unable to complete this task — I got stuck repeatedly calling " + tc . Name + " without making progress. Please try rephrasing your request."
1010+ slog .Warn ("tool loop critical" , "agent" , l .id , "tool" , registryName , "message" , msg )
1011+ finalContent = "I was unable to complete this task — I got stuck repeatedly calling " + registryName + " without making progress. Please try rephrasing your request."
10131012 break
10141013 }
10151014 // Warning: inject message so model knows to change strategy.
1016- slog .Warn ("tool loop warning" , "agent" , l .id , "tool" , tc . Name , "message" , msg )
1015+ slog .Warn ("tool loop warning" , "agent" , l .id , "tool" , registryName , "message" , msg )
10171016 messages = append (messages , providers.Message {Role : "user" , Content : msg })
10181017 }
10191018
@@ -1032,10 +1031,10 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
10321031
10331032 // Check for same tool returning identical results with different args.
10341033 if rh := hashResult (result .ForLLM ); rh != "" {
1035- if level , msg := loopDetector .detectSameResult (tc . Name , rh ); level != "" {
1034+ if level , msg := loopDetector .detectSameResult (registryName , rh ); level != "" {
10361035 if level == "critical" {
10371036 slog .Warn ("tool loop critical: same result" ,
1038- "tool" , tc . Name , "agent" , l .id , "run" , req .RunID )
1037+ "tool" , registryName , "agent" , l .id , "run" , req .RunID )
10391038 finalContent = msg
10401039 break
10411040 }
@@ -1047,11 +1046,12 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
10471046 // Tool instances are immutable (context-based) so concurrent access is safe.
10481047 // Results are collected then processed sequentially for deterministic ordering.
10491048 type indexedResult struct {
1050- idx int
1051- tc providers.ToolCall
1052- result * tools.Result
1053- argsJSON string
1054- spanStart time.Time
1049+ idx int
1050+ tc providers.ToolCall
1051+ registryName string
1052+ result * tools.Result
1053+ argsJSON string
1054+ spanStart time.Time
10551055 }
10561056
10571057 // 1. Emit all tool.call events upfront (client sees all calls starting)
@@ -1104,7 +1104,7 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
11041104 }
11051105 stopSlowTimer ()
11061106 l .emitToolSpanEnd (ctx , spanID , spanStart , result )
1107- resultCh <- indexedResult {idx : idx , tc : tc , result : result , argsJSON : string (argsJSON ), spanStart : spanStart }
1107+ resultCh <- indexedResult {idx : idx , tc : tc , registryName : registryName , result : result , argsJSON : string (argsJSON ), spanStart : spanStart }
11081108 }(i , tc )
11091109 }
11101110
@@ -1130,9 +1130,9 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
11301130 toolTiming .Record (r .tc .Name , time .Since (r .spanStart ).Milliseconds ())
11311131
11321132 // Record for loop detection.
1133- argsHash := loopDetector .record (r .tc . Name , r .tc .Arguments )
1133+ argsHash := loopDetector .record (r .registryName , r .tc .Arguments )
11341134 loopDetector .recordResult (argsHash , r .result .ForLLM )
1135- loopDetector .recordMutation (r .tc . Name )
1135+ loopDetector .recordMutation (r .registryName )
11361136
11371137 if r .result .Async {
11381138 asyncToolCalls = append (asyncToolCalls , r .tc .Name )
@@ -1147,12 +1147,12 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
11471147 }
11481148
11491149 // Count successful spawn calls for orphan detection (post-execution).
1150- if l . resolveToolCallName ( r . tc . Name ) == "spawn" && ! r .result .IsError {
1150+ if r . registryName == "spawn" && ! r .result .IsError {
11511151 if tid , _ := r .tc .Arguments ["team_task_id" ].(string ); tid != "" {
11521152 teamTaskSpawns ++
11531153 }
11541154 }
1155- if hadBootstrap && bootstrapToolAllowlist [r .tc . Name ] {
1155+ if hadBootstrap && bootstrapToolAllowlist [r .registryName ] {
11561156 bootstrapWriteDetected = true
11571157 }
11581158
@@ -1202,23 +1202,23 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
12021202 pendingMsgs = append (pendingMsgs , toolMsg )
12031203
12041204 // Check for tool call loop.
1205- if level , msg := loopDetector .detect (r .tc . Name , argsHash ); level != "" {
1205+ if level , msg := loopDetector .detect (r .registryName , argsHash ); level != "" {
12061206 if level == "critical" {
1207- slog .Warn ("tool loop critical" , "agent" , l .id , "tool" , r .tc . Name , "message" , msg )
1208- finalContent = "I was unable to complete this task — I got stuck repeatedly calling " + r .tc . Name + " without making progress. Please try rephrasing your request."
1207+ slog .Warn ("tool loop critical" , "agent" , l .id , "tool" , r .registryName , "message" , msg )
1208+ finalContent = "I was unable to complete this task — I got stuck repeatedly calling " + r .registryName + " without making progress. Please try rephrasing your request."
12091209 loopStuck = true
12101210 break
12111211 }
1212- slog .Warn ("tool loop warning" , "agent" , l .id , "tool" , r .tc . Name , "message" , msg )
1212+ slog .Warn ("tool loop warning" , "agent" , l .id , "tool" , r .registryName , "message" , msg )
12131213 messages = append (messages , providers.Message {Role : "user" , Content : msg })
12141214 }
12151215
12161216 // Check for same tool returning identical results with different args.
12171217 if rh := hashResult (r .result .ForLLM ); rh != "" {
1218- if level , msg := loopDetector .detectSameResult (r .tc . Name , rh ); level != "" {
1218+ if level , msg := loopDetector .detectSameResult (r .registryName , rh ); level != "" {
12191219 if level == "critical" {
12201220 slog .Warn ("tool loop critical: same result" ,
1221- "tool" , r .tc . Name , "agent" , l .id , "run" , req .RunID )
1221+ "tool" , r .registryName , "agent" , l .id , "run" , req .RunID )
12221222 finalContent = msg
12231223 loopStuck = true
12241224 break
0 commit comments