TestToolCallLeakWarningDetectsStrandedXML: a turn ending with leaked tool-call XML stranded in the newest assistant message warns the user; clean text doesn't, and only the NEWEST assistant message is inspected.
(t *testing.T)
| 2231 | func TestVerifyNudgeEndToEndRePromptsThenFinishes(t *testing.T) { |
| 2232 | var round int |
| 2233 | handler := func(w http.ResponseWriter, _ *http.Request) { |
| 2234 | w.Header().Set("Content-Type", "text/event-stream") |
| 2235 | round++ |
| 2236 | if round <= verifyNudgeMinRounds { |
| 2237 | // A real tool call so toolRounds climbs to the gate. |
| 2238 | fmt.Fprintf(w, "data: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"index\":0,\"id\":\"c%d\",\"function\":{\"name\":\"bash\",\"arguments\":\"{\\\"cmd\\\":\\\"echo step\\\"}\"}}]}}]}\n\n", round) |
| 2239 | fmt.Fprint(w, "data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"tool_calls\"}],\"usage\":{\"completion_tokens\":5}}\n\n") |
| 2240 | fmt.Fprint(w, "data: [DONE]\n\n") |
| 2241 | return |
| 2242 | } |
| 2243 | // A confident, toolless summary, what the galaxy runs shipped. |
| 2244 | fmt.Fprint(w, "data: {\"choices\":[{\"delta\":{\"content\":\"Done - galaxy.html built with all features.\"}}]}\n\n") |
| 2245 | fmt.Fprint(w, "data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":{\"completion_tokens\":6}}\n\n") |
| 2246 | fmt.Fprint(w, "data: [DONE]\n\n") |
| 2247 | } |
| 2248 | |
| 2249 | m := newTestModel(t, handler) |
| 2250 | final := drainFinal(t, m, "build galaxy.html") |
| 2251 | |
| 2252 | // 8 tool rounds + a summary that gets re-prompted + the final summary = 10. |
| 2253 | if round != verifyNudgeMinRounds+2 { |
| 2254 | t.Fatalf("substantial finish must re-prompt exactly once (want %d requests, got %d)", verifyNudgeMinRounds+2, round) |
| 2255 | } |
| 2256 | var nudges int |
| 2257 | for _, msg := range final.history { |
| 2258 | if msg.Role == chmctx.RoleSystem && strings.Contains(msg.Content, "original request") { |
| 2259 | nudges++ |
| 2260 | } |
| 2261 | } |
| 2262 | if nudges != 1 { |
| 2263 | t.Fatalf("expected exactly one finish re-grounding note in history, got %d", nudges) |
| 2264 | } |
| 2265 | if final.phase != phaseIdle { |
| 2266 | t.Fatalf("turn must end idle after the re-grounded finish, phase=%v", final.phase) |
| 2267 | } |
| 2268 | } |
| 2269 | |
| 2270 | // TestEndTurnResetsVerifyNudged: the latch is per-turn, so endTurn must clear it |
| 2271 | // or a later turn never re-grounds. |
nothing calls this directly
no test coverage detected