doPost performs one round-trip, mapping status into the typed cloud errors Probe and sendChat share. On 200 it returns the live response with body open for streaming; on non-200 the body is drained and closed first. Budget is set only on 402. errBody returns the raw body on a non-2xx other than 401/
(parent context.Context, body chatRequest)
| 399 | } |
| 400 | // MidStream marks a drop the TUI may transparently replay. Gated on a |
| 401 | // frame having actually arrived: a PREFILL stall is deterministic, so |
| 402 | // replaying it just re-pays the same wait. A server-reported stream |
| 403 | // error is its own diagnosis ("context length exceeded") and would |
| 404 | // replay forever, so it never qualifies either. |
| 405 | var sse *serverStreamError |
| 406 | sendEvent(parent, out, Event{Kind: EventError, Err: err, MidStream: streaming.Load() && !errors.As(err, &sse)}) |
| 407 | return |
| 408 | } |
| 409 | sendEvent(parent, out, Event{ |
| 410 | Kind: EventDone, |
| 411 | Final: final, |
| 412 | Budget: budget, |
| 413 | ContextWindow: ctxWindow, |
| 414 | Tokens: tokens, |
| 415 | PromptTokens: promptTokens, |
| 416 | Elapsed: time.Since(start), |
| 417 | }) |
| 418 | } |
| 419 | |
| 420 | // sendEvent puts e on out, bailing if parent cancels first, so a slow or |
| 421 | // vanished consumer after Ctrl+C can't wedge the stream goroutine on a full |
| 422 | // buffer. |
| 423 | func sendEvent(parent context.Context, out chan<- Event, e Event) bool { |
| 424 | select { |
| 425 | case out <- e: |
| 426 | return true |
| 427 | case <-parent.Done(): |
| 428 | return false |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | // sendChat POSTs the request and returns the response on 200. On failure it |
| 433 | // returns the Event the caller forwards, populated with Kind/Err/Budget. The |
| 434 | // body is closed on every non-200 branch; 200 leaves it open for the caller. |
| 435 | func (c *Client) sendChat(parent context.Context, msgs []chmctx.Message, tools []Tool) (*http.Response, *Event) { |
| 436 | resp, budget, err := c.postChat(parent, chatRequest{ |
| 437 | Model: c.Model, |
| 438 | Messages: toWire(msgs), |
| 439 | Tools: tools, |
| 440 | Stream: true, |
| 441 | StreamOptions: &streamOptions{IncludeUsage: true}, |
no test coverage detected