TestVerifyNudgeFiresOnceAtMinRounds: the finish re-grounding nudge trips one soft system note only once a turn has done real work (toolRounds >= verifyNudgeMinRounds), and never below it; the latch keeps it to once per turn.
(t *testing.T)
| 2022 | if msg.Role == chmctx.RoleSystem && strings.Contains(msg.Content, "original request") { |
| 2023 | nudges++ |
| 2024 | } |
| 2025 | } |
| 2026 | if nudges != 1 { |
| 2027 | t.Fatalf("expected exactly one finish re grounding note in history, got %d", nudges) |
| 2028 | } |
| 2029 | if final.phase != phaseIdle { |
| 2030 | t.Fatalf("turn must end idle after the re-grounded finish, phase=%v", final.phase) |
| 2031 | } |
| 2032 | } |
| 2033 | |
| 2034 | // TestEndTurnResetsVerifyNudged: the latch is per turn, so endTurn must clear it |
| 2035 | // or a later turn never re grounds. |
| 2036 | func TestEndTurnResetsVerifyNudged(t *testing.T) { |
| 2037 | m := newTestModel(t, func(http.ResponseWriter, *http.Request) {}) |
| 2038 | m.installTurnContext() |
| 2039 | m.verifyNudged = true |
| 2040 | m.endTurn() |
| 2041 | if m.verifyNudged { |
| 2042 | t.Fatal("endTurn must reset verifyNudged") |
| 2043 | } |
| 2044 | } |
| 2045 | |
| 2046 | // TestToolCallLeakWarningDetectsStrandedXML: a turn ending with leaked |
| 2047 | // tool call XML stranded in the newest assistant message warns the user; clean |
| 2048 | // text doesn't, and only the NEWEST assistant message is inspected. |
| 2049 | func TestToolCallLeakWarningDetectsStrandedXML(t *testing.T) { |
| 2050 | // XML tool call body. |
| 2051 | coderLeak := "Let me search.\n<tool_call>\n<function=bash>\n<parameter=cmd>ls</parameter>\n</function>\n</tool_call>" |
| 2052 | // General JSON tool call body, the target model class, NO `<function=`. |
| 2053 | denseLeak := "Let me search.\n<tool_call>\n{\"name\": \"bash\", \"arguments\": {\"cmd\": \"ls\"}}\n</tool_call>" |
| 2054 | clean := "Done: built and tested, all green." |
| 2055 | |
| 2056 | for name, leak := range map[string]string{"coder-xml": coderLeak, "dense-json": denseLeak} { |
| 2057 | if w := toolCallLeakWarning([]chmctx.Message{{Role: chmctx.RoleAssistant, Content: leak}}); w == "" { |
| 2058 | t.Fatalf("%s: leaked tool call must produce a warning", name) |
| 2059 | } |
| 2060 | } |
| 2061 | if w := toolCallLeakWarning([]chmctx.Message{{Role: chmctx.RoleAssistant, Content: clean}}); w != "" { |
| 2062 | t.Fatalf("clean reply must not warn, got %q", w) |
| 2063 | } |
| 2064 | // A message that carried a real structured tool call never leaked, even if |
| 2065 | // its prose quotes the `<tool_call>` tag: the ToolCalls gate keeps it clean. |
| 2066 | withCall := chmctx.Message{ |
| 2067 | Role: chmctx.RoleAssistant, |
| 2068 | Content: "Running the build via a <tool_call> now.", |
nothing calls this directly
no test coverage detected