loop: auto-infer TaskState from actual tool results each round
This commit is contained in:
parent
bfc7f15254
commit
d1ac24fb1d
|
|
@ -451,6 +451,12 @@ func run(ctx context.Context, cfg agentConfig, state state) error {
|
|||
cfg.SaveSession()
|
||||
}
|
||||
|
||||
// Auto-update TaskState from what actually happened this round.
|
||||
if ts := state.taskState(); ts != nil {
|
||||
inferTaskStateUpdate(ts, msg, results)
|
||||
state.updateTaskState(*ts)
|
||||
}
|
||||
|
||||
if interrupted {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
|
@ -540,6 +546,45 @@ func contextBudget(ctx context.Context, b backend.Backend) int {
|
|||
return ctxLen / 2
|
||||
}
|
||||
|
||||
// inferTaskStateUpdate updates TaskState fields from the actual tool round
|
||||
// without requiring model cooperation. Keeps the state current even if the
|
||||
// model ignores re-injection nudges.
|
||||
func inferTaskStateUpdate(ts *TaskState, msg backend.Message, results []toolResult) {
|
||||
// LastAction: summarize what tools ran and whether they succeeded.
|
||||
if len(msg.ToolCalls) > 0 {
|
||||
names := make([]string, 0, len(msg.ToolCalls))
|
||||
for _, tc := range msg.ToolCalls {
|
||||
names = append(names, tc.Name)
|
||||
}
|
||||
errCount := 0
|
||||
for _, r := range results {
|
||||
if r.IsError {
|
||||
errCount++
|
||||
}
|
||||
}
|
||||
action := strings.Join(names, ", ")
|
||||
if errCount > 0 {
|
||||
action += fmt.Sprintf(" (%d/%d failed)", errCount, len(results))
|
||||
}
|
||||
ts.LastAction = action
|
||||
}
|
||||
|
||||
// PlanStep: extract from PLAN: block if present in assistant text.
|
||||
if idx := strings.Index(msg.Content, "PLAN:"); idx >= 0 {
|
||||
lines := strings.Split(msg.Content[idx:], "\n")
|
||||
for _, line := range lines[1:] {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if strings.HasPrefix(trimmed, "- [ ]") {
|
||||
ts.PlanStep = strings.TrimSpace(trimmed[5:])
|
||||
break
|
||||
}
|
||||
if trimmed == "" || (!strings.HasPrefix(trimmed, "- [") && trimmed != "") {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hasTextToolCall returns true when the assistant text contains a registered
|
||||
// tool name immediately followed by ':' or '(', indicating the model tried to
|
||||
// invoke a tool by writing the call as plain text rather than via the API.
|
||||
|
|
|
|||
Reference in New Issue