Symptom
- An agent re-posts its previous session's reply verbatim on every turn-triggering message; no real turns run.
- Registry-only slash commands (
/help, unknown-command note) keep working — only turn-sending input loops.
- Observed on a simmis dev instance (dvergr checkout + spindel 0.1.35).
Evidence
- "Replies" land 0.4–0.8 s after the human message — no LLM latency, so no generation happened.
- Each replay is stored with a fresh message id, so
-store-message!'s id-idempotency can't dedupe; the room store accumulated 4 copies of the same reply.
- Zero
post-turn-error! ("⚠️ turn failed") rows in the room — the stale-reply guard never fired.
(providers/list-providers) was [] at the time (see trigger below).
Root cause
- Trigger (config, my side): the agent's provider (
:fireworks) was never registered — no *_API_KEY env vars, so init-defaults! registered nothing. Every turn failed immediately at provider resolution. (The boot-time :providers/none-registered warn fired, but is easy to miss.)
- Bug (dvergr): the failure ends the turn with no
gen/error-result? tag, so errored stays nil (src/dvergr/discourse/llm.clj:488 on main) and the loop falls through to llm.clj:527, posting last-assistant-message of the chat-ctx. On turn 0 that ctx was just seeded from the store, so "last assistant message" is the previous session's reply — re-posted as a new message, every time. The post-turn-error! guard (src/dvergr/agent/turn.clj:188, added for exactly this "repeating bug") only covers error-tagged results at llm.clj:526.
Repro
- Agent whose provider isn't registered (e.g. clear providers), in a room with existing history.
- Send any plain message → the stale prior reply is re-posted in under a second. Repeats on every message.
Suggested fix
- Gate the final reply-post on "this invocation produced a new assistant message" (e.g. compare the chat-ctx assistant-message count before/after the turn loop) instead of only on
errored — that closes every silent-failure shape, not just this one.
- Additionally, surface provider-missing as a proper error-result so
post-turn-error! reports it in-room instead of only the boot-time warn.
Side effect worth knowing
Replays permanently pollute the room store (fresh ids defeat idempotency), so affected agents carry duplicated context even after the fix.
Symptom
/help, unknown-command note) keep working — only turn-sending input loops.Evidence
-store-message!'s id-idempotency can't dedupe; the room store accumulated 4 copies of the same reply.post-turn-error!("(providers/list-providers)was[]at the time (see trigger below).Root cause
:fireworks) was never registered — no*_API_KEYenv vars, soinit-defaults!registered nothing. Every turn failed immediately at provider resolution. (The boot-time:providers/none-registeredwarn fired, but is easy to miss.)gen/error-result?tag, soerroredstays nil (src/dvergr/discourse/llm.clj:488onmain) and the loop falls through tollm.clj:527, postinglast-assistant-messageof the chat-ctx. On turn 0 that ctx was just seeded from the store, so "last assistant message" is the previous session's reply — re-posted as a new message, every time. Thepost-turn-error!guard (src/dvergr/agent/turn.clj:188, added for exactly this "repeating bug") only covers error-tagged results atllm.clj:526.Repro
Suggested fix
errored— that closes every silent-failure shape, not just this one.post-turn-error!reports it in-room instead of only the boot-time warn.Side effect worth knowing
Replays permanently pollute the room store (fresh ids defeat idempotency), so affected agents carry duplicated context even after the fix.