drain advances the model until no async commands remain, a synchronous bubbletea mini-runtime. tea.BatchMsg arrives when Update wraps multiple Cmds (e.g. tea.Println from the outbox + the handler's own Cmd); each child runs, its result feeds back through Update, and any new Cmd is queued.
(m tea.Model, cmd tea.Cmd)
| 2735 | w.Header().Set("Content-Type", "text/event-stream") |
| 2736 | switch turn { |
| 2737 | case 1: |
| 2738 | fmt.Fprintf(w, "data: %s\n\n", `{"type":"response.output_item.done","output_index":0,"item":{"type":"function_call","call_id":"c1","name":"bash","arguments":"{\"cmd\":\"echo first\"}"}}`) |
| 2739 | fmt.Fprintf(w, "data: %s\n\n", `{"type":"response.output_item.done","output_index":1,"item":{"type":"function_call","call_id":"c2","name":"bash","arguments":"{\"cmd\":\"echo second\"}"}}`) |
| 2740 | fmt.Fprintf(w, "data: %s\n\n", `{"type":"response.completed","response":{"usage":{"output_tokens":5}}}`) |
| 2741 | default: |
| 2742 | // Round 2 ends the turn: a plain content reply with NO tool call. |
| 2743 | // Emitting a nonexistent tool here would loop drain forever: runRaw |
| 2744 | // returns "(unknown tool: ...)" and reenters chat indefinitely. |
| 2745 | fmt.Fprintf(w, "data: %s\n\n", `{"type":"response.output_text.delta","delta":"both echoes finished"}`) |
| 2746 | fmt.Fprintf(w, "data: %s\n\n", `{"type":"response.completed","response":{"usage":{"output_tokens":1}}}`) |
| 2747 | } |
| 2748 | }) |
| 2749 | mm, cmd := m.submit("two echoes", "two echoes", promptEntry{display: "two echoes"}) |
| 2750 | out, _ := drain(mm, cmd) |
| 2751 | final := out.(Model) |
| 2752 | |
| 2753 | if turn != 2 { |
| 2754 | t.Fatalf("expected exactly 2 LLM rounds, got %d", turn) |
| 2755 | } |
| 2756 | if !bytes.Contains(roundBodies[1], []byte("first")) { |
| 2757 | t.Fatalf("round 2 request missing tool_result for first call:\n%s", roundBodies[1]) |
| 2758 | } |
| 2759 | if !bytes.Contains(roundBodies[1], []byte("second")) { |
| 2760 | t.Fatalf("round 2 request missing tool_result for second call:\n%s", roundBodies[1]) |
| 2761 | } |
| 2762 | toolResults := 0 |
| 2763 | for _, msg := range final.history { |
| 2764 | if msg.Role == chmctx.RoleTool { |
| 2765 | toolResults++ |
| 2766 | } |
| 2767 | } |
| 2768 | if toolResults != 2 { |
| 2769 | t.Fatalf("expected 2 tool results in history, got %d:\n%+v", toolResults, final.history) |
no test coverage detected