Kyle Carberry
ddfe630757
refactor(chatd): replace fantasy.Agent with custom agent loop (#22507)
## Summary
Replaces fantasy's `Agent` abstraction with a direct step loop calling
`LanguageModel.Stream()`. Fantasy is retained as the provider
abstraction layer (streaming parsers, types, tool schema) but we no
longer use `fantasy.Agent`, `AgentStreamCall`, `AgentResult`, or
`StepResult`.
## Problems solved
| Problem | Before | After |
|---|---|---|
| **Sentinel prompt hack** | fantasy.Agent requires non-empty Prompt →
UUID sentinel generated and stripped in PrepareStep | Messages passed
directly to `model.Stream()` |
| **Discarded PersistStep errors** | `_ = opts.OnStepFinish(result)`
silently swallows errors | Errors propagate directly from
`PersistStep()` |
| **Shadow draft state** | ~160 LOC tracking content in parallel because
fantasy doesn't expose in-progress content on interruption |
`stepResult` owns content directly; `flushActiveState()` is trivial |
| **Nested retry layers** | fantasy's 2-attempt retry nested inside
chatretry's indefinite retry | Single `chatretry.Retry` layer |
| **Callback-mediated compaction** | Mutex + boolean flag + coordination
between OnStepFinish/PrepareStep callbacks | Inline `if` statement
between steps |
| **Duplicate compaction paths** | `compactStep()` + `maybeCompact()`
sharing ~80% logic | Single `tryCompact()` function |
## Changes
### `coderd/chatd/chatloop/chatloop.go` — Rewritten
- **Removed**: `fantasy.NewAgent()`, `AgentStreamCall`, sentinel prompt,
shadow draft state (~160 LOC of closures), `compactedMu`/`compacted`
flag, `PrepareStepResult`
- **Added**: `stepResult` struct, `processStepStream()` (stream
consumer), `executeTools()` (sequential tool execution),
`flushActiveState()` (interrupt handling), `buildToolDefinitions()`,
`toResponseMessages()`
- **Changed**: `Run()` return type from `(*fantasy.AgentResult, error)`
to `error` (callers already discarded the result)
- **Preserved**: Anthropic prompt caching, reasoning title extraction,
`extractContextLimit()`, `ErrInterrupted` semantics
### `coderd/chatd/chatloop/compaction.go` — Simplified
- Merged `compactStep()` + `maybeCompact()` → single `tryCompact()`
- Removed `[]StepResult` parameter from `generateCompactionSummary()`
(caller provides complete message list)
- Kept helper functions: `normalizedCompactionConfig`,
`contextTokensFromUsage`, `resolveContextLimit`, `shouldCompact`
### `coderd/chatd/chatd.go` — Caller updates
- Removed `AgentStreamCall` construction
- Changed `_, err = chatloop.Run(...)` to `err = chatloop.Run(...)`
- Model parameters moved from `AgentStreamCall` fields to `RunOptions`
fields
### Tests — 4 new tests
- `MidLoopCompactionReloadsMessages` — compaction fires mid-loop,
messages reloaded
- `PostRunCompactionSkippedAfterMidLoop` — no double compaction
- `MultiStepToolExecution` — tools execute between steps, results feed
next step
- `PersistStepErrorPropagates` — persistence errors propagate (was
silently discarded)
2026-03-02 18:51:57 -05:00
..
2026-02-24 13:26:55 +04:00
2025-06-20 13:16:55 -06:00
2026-01-21 19:06:19 +00:00
2026-02-27 16:46:19 -05:00
2026-03-02 16:02:01 +01:00
2024-09-18 21:47:53 +10:00
2026-01-08 15:24:11 +04:00
2026-02-24 16:45:56 +00:00
2023-10-30 19:44:29 +00:00
2025-12-15 13:44:44 -09:00
2026-02-06 09:52:17 -07:00
2026-02-06 10:12:58 +04:00
2026-03-02 18:51:57 -05:00
2026-02-27 00:07:14 +11:00
2025-10-16 01:56:43 +11:00
2026-01-08 15:24:11 +04:00
2026-03-02 16:31:04 -05:00
2026-02-19 09:02:19 +00:00
2026-02-03 17:52:07 +00:00
2026-01-29 13:50:15 +01:00
2026-01-08 15:24:11 +04:00
2026-01-08 15:24:11 +04:00
2026-01-08 15:24:11 +04:00
2026-01-15 16:37:05 +00:00
2026-02-23 12:18:44 +01:00
2026-02-28 16:46:51 -05:00
2026-02-03 17:52:07 +00:00
2026-02-23 22:46:17 -06:00
2025-06-20 13:16:55 -06:00
2026-02-23 12:18:44 +01:00
2026-01-08 15:24:11 +04:00
2026-02-18 16:30:16 +00:00
2026-02-23 12:18:44 +01:00
2025-10-15 17:37:37 +00:00
2024-05-13 14:37:51 -04:00
2025-08-16 01:31:00 +10:00
2026-02-19 09:02:19 +00:00
2026-02-25 08:58:50 +00:00
2026-01-30 13:30:06 +01:00
2026-02-23 22:46:17 -06:00
2025-10-23 15:38:49 -05:00
2025-06-17 09:00:32 -08:00
2026-02-27 18:06:54 -05:00
2026-03-02 15:57:04 +00:00
2025-06-20 13:16:55 -06:00
2025-07-08 14:31:05 +00:00
2026-02-19 09:02:19 +00:00
2026-02-26 02:40:45 +11:00
2026-02-27 17:46:37 +00:00
2026-02-24 17:04:42 +00:00
2025-12-14 03:00:03 +00:00
2026-01-08 15:24:11 +04:00
2026-01-08 15:24:11 +04:00
2025-08-22 16:32:35 +10:00
2025-06-20 13:16:55 -06:00
2026-02-27 17:46:37 +00:00
2026-01-08 15:24:11 +04:00
2026-02-24 23:46:43 -06:00
2026-01-08 15:24:11 +04:00
2026-02-27 14:26:48 +00:00
2025-03-31 10:55:44 -04:00
2025-12-15 11:26:41 -06:00
2025-11-17 13:24:12 +00:00
2026-02-25 13:14:32 +02:00
2026-02-27 16:50:56 +00:00
2025-09-26 11:56:34 +02:00
2026-02-24 15:27:03 +00:00
2026-02-24 15:27:03 +00:00
2023-08-18 18:55:43 +00:00
2024-08-01 12:07:19 -05:00
2026-01-08 15:24:11 +04:00
2026-01-08 15:24:11 +04:00
2025-10-27 17:14:16 -06:00
2026-02-27 16:50:56 +00:00
2026-03-02 12:00:00 -05:00
2026-03-02 16:31:04 -05:00
2023-08-18 18:55:43 +00:00
2025-06-20 13:16:55 -06:00
2026-01-08 15:24:11 +04:00
2026-02-28 23:40:17 -05:00
2026-01-08 15:24:11 +04:00
2026-01-15 16:37:05 +00:00
2026-01-15 16:37:05 +00:00
2024-02-27 16:33:32 +00:00
2025-06-25 13:03:32 +00:00
2024-06-11 12:22:59 +10:00
2025-04-22 16:21:15 +00:00
2025-06-24 09:14:41 +01:00
2026-01-12 18:19:19 -08:00
2025-12-15 17:41:47 +00:00
2025-09-04 14:28:29 +10:00
2026-01-08 15:24:11 +04:00
2025-12-15 11:26:41 -06:00
2025-05-15 15:32:52 +01:00
2025-06-20 13:16:55 -06:00
2025-06-20 13:16:55 -06:00
2026-01-26 09:24:45 +00:00
2025-08-19 10:41:33 +02:00
2025-08-19 10:41:33 +02:00
2025-06-20 13:16:55 -06:00
2026-01-08 15:24:11 +04:00
2025-03-26 01:56:39 -05:00
2023-06-06 10:26:13 -05:00
2026-01-08 15:24:11 +04:00
2026-02-03 12:48:25 -06:00
2026-02-03 12:48:25 -06:00
2026-02-13 08:19:07 -06:00
2026-01-08 15:24:11 +04:00
2026-01-15 12:41:28 +03:00
2026-01-15 12:41:28 +03:00
2026-01-15 12:41:28 +03:00
2025-07-03 18:33:47 +02:00
2026-02-23 12:18:44 +01:00
2025-10-22 15:18:42 -05:00
2024-07-25 16:07:53 -05:00
2026-02-03 17:52:07 +00:00
2025-07-15 14:55:34 +10:00
2025-07-15 14:55:34 +10:00
2026-02-02 09:03:18 -06:00
2026-02-03 17:52:07 +00:00
2026-02-19 09:02:19 +00:00
2025-07-28 15:02:26 +01:00
2025-08-21 16:03:34 -04:00
2026-02-03 17:52:07 +00:00
2025-06-20 13:16:55 -06:00
2025-10-06 13:58:37 +02:00
2026-02-03 17:52:07 +00:00
2024-07-25 16:07:53 -05:00
2026-01-12 18:19:19 -08:00
2025-09-26 11:43:32 +02:00
2025-09-26 11:43:32 +02:00
2025-06-20 13:16:55 -06:00
2026-01-08 15:24:11 +04:00
2026-02-13 19:44:50 -05:00
2026-02-13 19:44:50 -05:00
2026-02-03 10:16:53 -06:00
2026-02-03 09:45:23 +00:00
2025-06-20 13:16:55 -06:00
2023-08-18 18:55:43 +00:00
2026-02-20 09:01:00 -06:00
2026-02-20 09:01:00 -06:00
2026-02-13 08:19:07 -06:00
2026-02-03 17:52:07 +00:00
2026-03-02 21:11:20 +00:00
2026-03-02 21:11:20 +00:00
2026-01-12 18:19:19 -08:00
2025-06-18 14:07:53 +00:00
2026-01-19 12:36:33 +00:00
2026-02-25 08:45:00 -07:00
2026-02-27 16:50:56 +00:00
2025-12-22 10:21:39 +04:00
2026-02-18 09:44:06 +01:00
2026-02-18 09:44:06 +01:00
2025-06-20 13:16:55 -06:00
2025-09-26 11:56:34 +02:00
2026-02-03 09:45:23 +00:00
2026-02-23 22:46:17 -06:00
2025-12-15 11:26:41 -06:00
2026-01-08 15:24:11 +04:00
2026-02-23 08:30:32 -08:00
2026-02-27 16:50:56 +00:00
2025-04-16 10:37:09 -06:00
2026-01-08 15:24:11 +04:00