| 1 | package agent |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | |
| 6 | "reasonix/internal/evidence" |
| 7 | "reasonix/internal/tool" |
| 8 | ) |
| 9 | |
| 10 | // resolvedSkipOutcome completes proxy actions that resolve locally, without a |
| 11 | // second concrete tool dispatch. Keeping this receipt path separate also keeps |
| 12 | // proxy policy resolution small enough to audit as one deterministic gate. |
| 13 | func (a *Agent) resolvedSkipOutcome(plan *toolCallPlan, resolved tool.ResolvedCall) toolOutcome { |
| 14 | call := plan.call |
| 15 | // A connected mcp-server call completes during resolution by listing its |
| 16 | // live tools, so account for that successful call here too. |
| 17 | if resolved.ProxyAction == "call" && !resolved.Unavailable { |
| 18 | a.noteCapabilityInvocation(call.Name, json.RawMessage(call.Arguments), nil) |
| 19 | } |
| 20 | result := resolved.Result |
| 21 | if a.task.ledger != nil { |
| 22 | // inspect/decline are not mutations; unavailable call targets are not success. |
| 23 | receipt := evidence.ReceiptFromToolCall( |
| 24 | call.Name, |
| 25 | json.RawMessage(call.Arguments), |
| 26 | !resolved.Unavailable, |
| 27 | true, |
| 28 | ) |
| 29 | a.task.ledger.Record(receipt) |
| 30 | } |
| 31 | if resolved.Unavailable { |
| 32 | return toolOutcome{output: result, errMsg: firstLine(resolved.UnavailableReason)} |
| 33 | } |
| 34 | body, truncMsg, original := a.boundProviderVisibleResult(result, call.Name, call.ID) |
| 35 | out := toolOutcome{output: body, truncated: truncMsg != "" || original != "", truncMsg: truncMsg} |
| 36 | if original != "" { |
| 37 | out.rawOutput = original |
| 38 | } |
| 39 | return out |
| 40 | } |
| 41 |