package buscalls import "encoding/json" // Unwrap reads a tool's answer whatever wraps it on its way from the tool runner (the lead's ruling 2026-11-04 13:12: // one reading, not a copy per module): a JSON string holding the answer; the protocol's content list, whose first // text is the answer and whose isError says it failed; the {output, ok, answer} form; the tool runner's {result, // error} envelope, whose error is the call's. It answers the answer itself, the words said with it (the output, the // error, or the answer's own text), and whether the tool says it succeeded. A bare answer is itself, succeeded. func Unwrap(raw json.RawMessage) (answer json.RawMessage, said string, ok bool) { var s string if json.Unmarshal(raw, &s) == nil { return Unwrap(json.RawMessage(s)) } var m map[string]json.RawMessage if json.Unmarshal(raw, &m) != nil { return raw, string(raw), true } if content, has := m["content"]; has { var items []struct { Text string `json:"text"` } var e struct { IsError bool `json:"isError"` } _ = json.Unmarshal(raw, &e) if json.Unmarshal(content, &items) == nil && len(items) > 0 { inner, out, ok := Unwrap(json.RawMessage(items[0].Text)) return inner, out, ok && !e.IsError } } var v struct { Output string `json:"output"` OK *bool `json:"ok"` Answer json.RawMessage `json:"answer"` Result json.RawMessage `json:"result"` Error string `json:"error"` } if json.Unmarshal(raw, &v) == nil { switch { case v.OK != nil: return v.Answer, v.Output, *v.OK case v.Error != "": return nil, v.Error, false case len(v.Result) > 0: return Unwrap(v.Result) } } return raw, string(raw), true }