MCPcopy Index your code
hub / github.com/codehamr/codehamr / TestToolCallRoundTripExecutesBash

Function TestToolCallRoundTripExecutesBash

internal/tui/tui_test.go:1030–1080  ·  view source on GitHub ↗
(t *testing.T)

Source from the content-addressed store, hash-verified

1028}
1029
1030func TestToolCallRoundTripExecutesBash(t *testing.T) {
1031 // Turn 1: bash tool call. Turn 2: plain content, no tool call. A turn ends
1032 // when the assistant stops emitting tool calls (handleStreamClosed →
1033 // finalizeTurn → endTurn).
1034 turn := 0
1035 m := newTestModel(t, func(w http.ResponseWriter, _ *http.Request) {
1036 w.Header().Set("Content-Type", "text/event-stream")
1037 turn++
1038 switch turn {
1039 case 1:
1040 fmt.Fprintf(w, "data: %s\n\n", `{"choices":[{"delta":{"tool_calls":[{"index":0,"id":"c1","function":{"name":"bash","arguments":"{\"cmd\":\"echo HAMMER\"}"}}]}}]}`)
1041 fmt.Fprintf(w, "data: %s\n\n", `{"choices":[{"delta":{},"finish_reason":"tool_calls"}],"usage":{"completion_tokens":5}}`)
1042 fmt.Fprint(w, "data: [DONE]\n\n")
1043 default:
1044 fmt.Fprintf(w, "data: %s\n\n", `{"choices":[{"delta":{"content":"echoed HAMMER for you"}}]}`)
1045 fmt.Fprintf(w, "data: %s\n\n", `{"choices":[{"delta":{},"finish_reason":"stop"}],"usage":{"completion_tokens":1}}`)
1046 fmt.Fprint(w, "data: [DONE]\n\n")
1047 }
1048 })
1049 mm, cmd := m.submit("run echo", "run echo", promptEntry{display: "run echo"})
1050 out, _ := drain(mm, cmd)
1051 final := out.(Model)
1052
1053 if turn != 2 {
1054 t.Fatalf("expected 2 LLM turns, got %d", turn)
1055 }
1056 // history: user, assistant(bash call), tool(bash result), assistant(content)
1057 if len(final.history) != 4 {
1058 t.Fatalf("history wrong: %d messages", len(final.history))
1059 }
1060 if final.history[2].Role != "tool" || !strings.Contains(final.history[2].Content, "HAMMER") {
1061 t.Fatalf("tool result missing: %+v", final.history[2])
1062 }
1063 if !strings.Contains(stripANSI(final.scroll.String()), "echoed HAMMER for you") {
1064 t.Fatalf("final assistant content missing from scroll: %q", final.scroll.String())
1065 }
1066 // No tool calls → idle, control back to the user.
1067 if final.phase.active() {
1068 t.Fatalf("turn ending with no tool calls must return to idle, phase=%v", final.phase)
1069 }
1070 // The frozen run summary must sum tokens across both LLM rounds, not
1071 // overwrite. Round 1 reports usage.completion_tokens=5, round 2 reports 1.
1072 // finalizeTurn freezes turnTokens into lastTokens (the avg-rate divisor). Sum = 6.
1073 if final.lastTokens != 6 {
1074 t.Fatalf("per-turn tokens should sum across rounds (5+1), got %d", final.lastTokens)
1075 }
1076 // A clean finish (no tool calls) freezes the ✓ outcome for the idle footer.
1077 if final.lastOutcome != outcomeDone {
1078 t.Fatalf("clean finish should freeze outcomeDone, got %v", final.lastOutcome)
1079 }
1080}
1081
1082// TestToolArgsStreamBumpsEstimateAndPhase: a tool-call argument fragment (a file
1083// streaming into write_file) ticks the live token estimate AND flips the phase

Callers

nothing calls this directly

Calls 6

newTestModelFunction · 0.85
drainFunction · 0.85
stripANSIFunction · 0.85
submitMethod · 0.80
StringMethod · 0.80
activeMethod · 0.80

Tested by

no test coverage detected