Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
759be7b
docs/design: 429 and ESC — hold host notices behind a rate limit or a…
joyqi Oct 23, 2026
b9010d2
llm: a refusal carries its retry-after, and one over a minute is not …
joyqi Oct 23, 2026
cf5e148
repl: a 429 gets its own rungs, and notices wait behind a rate limit …
joyqi Oct 23, 2026
0c06e3e
tests/ui_tmux: scenario 35 — the notice gate on a real terminal (X-84)
joyqi Oct 23, 2026
674a125
docs: X-84 — the notice gate and a 429's own rungs
joyqi Oct 23, 2026
13a32d0
llm: RETRY_AFTER_CAP is public — should_retry's public doc names it (…
joyqi Oct 23, 2026
aa6e3b5
ui, repl: a revoked prompt hands back what won the race; a due probe …
joyqi Oct 23, 2026
dbd87dd
repl: a notice steered into a turn comes back when a later round's 42…
joyqi Oct 23, 2026
4a74ed4
repl: any status asking for more than a minute is a limit, not a ladd…
joyqi Oct 23, 2026
ac636b1
repl: the compaction offer and the meter count every notice a turn ca…
joyqi Oct 23, 2026
26fa982
repl: /model onto another account with the same model is a switch for…
joyqi Oct 23, 2026
474bede
repl: no automatic-retry promise with nothing to retry; a cancelled p…
joyqi Oct 23, 2026
999c337
docs: X-84 and the CHANGELOG as the review fixes left them; design §11.1
joyqi Oct 23, 2026
247e414
merge: rate-limit-cancel (a 429 the ladder could not clear, and the j…
joyqi Oct 23, 2026
864a339
deps: tokio 1.53.1 -> 1.54.1 (RUSTSEC-2026-0386)
joyqi Oct 23, 2026
4235dd2
llm, repl: a retry-after names a day at most, each ladder counts its …
joyqi Oct 23, 2026
f8144db
merge: rate-limit-fable (the review after the merge: a retry-after is…
joyqi Oct 23, 2026
7da84d7
ui: the queue's "↑ edit" hint appears only when something is editable
joyqi Oct 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,34 @@ All notable changes to iota are recorded here. The same notes, rendered, are at

## Unreleased

### Fixed

- **Hitting a provider's rate limit or usage cap no longer turns into an
endless loop, and Esc really stops.** When a request was refused with
429 and retrying didn't help, every background job that finished started
a new attempt and printed another `Rate limited (429)` error. Now iota
stops on its own: notices from finished jobs wait (each one says so in a
dim line), and while some are waiting iota tries once more later — when
the provider says it may (`retry-after`), otherwise after a minute, then
less and less often, at most every 30 minutes. Sending a message tries at
once and takes the waiting notices with it; switching to another model or
another provider with `/model` tries at once there. What you type is
never overtaken by these automatic tries, and a notice is no longer lost
when its turn is refused by a rate limit (any other failure still drops
it, as before). The provider's own message, with its reset time if it
gives one, is still shown. Pressing Esc now also holds the notices
queued behind the turn you stopped: they go with your next message
instead of starting new turns. A 429 now gets at most three more tries
(it used to be ten), and a provider asking to wait more than a minute —
with a 429 or any other error — is no longer waited out silently: iota
stops and holds until then (a day at the most, however long it asks),
unless the provider explicitly insists on being retried.
- **The queue's `· ↑ edit` hint no longer promises what ↑ can't do.** ↑
only brings back a message you typed — never the notice of a finished
background job — yet a queue holding nothing but such notices still
ended in `· ↑ edit`, and pressing ↑ did nothing. The hint now shows only
while the queue holds something you typed.

### Changed

- **Tool-call labels are easier to read.** The `[shell ls -la]`-style label
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ the `shell/` mechanism and `tool/builtins/agent.rs` consumes the `agents/` overl
| `headless/{mod,once,run,batch,report,images,error}.rs` | the `-m` loop: `once`, `run_once` and `execute_with_tools` over a `TurnParams`, the parallel batches, the JSON/text report, image saving — what separates it from `repl` is that there is no terminal | `mcp`, `session`, `tool` and below |
| `ui/{mod,facade,testutil}.rs`, `ui/runtime/{mod,handle,msgs,event_loop,term,osc,oneshot}.rs`, `ui/render/{mod,region,frame,spans,theme,sink,debug}.rs`, `ui/input/{mod,editor,composer,keys,paste,suggest}.rs`, `ui/surface/{mod,tabbed,panels,search,field}.rs` | the inline terminal engine, the ONLY module that names `ratatui`/`crossterm`: the `Ui` facade `repl` talks to; `runtime/` the loop thread, its mailbox, the terminal writer, the OSC probes, the one-shot pre-REPL surface; `render/` the staging region, the frame, the ANSI→span parser (the `NO_COLOR` gate), the theme, the metered previews; `input/` the shared `Editor`, the composer, the key ladder, paste, completion; `surface/` the tabbed panels, the pickers, search, the one-line field | `markdown`, `text` and below |
| `host/{mod,ansi,herdr,cmux,background}.rs` | host integration: the presenter's per-capability fan-out (progress, attention ping, session identity, exit clean-up) over the innermost detected host plus the ANSI fallback (`DETECTORS` runs inner to outer and the first match is kept — X-47), and the one capability gathered from every host, the facts it adds to the harness prompt's `<environment>` (`host: herdr`, `herdr pane: <id>`); the variables no child of the chat may inherit (`ChildEnvironment`, gathered by `host::child_env` from the host detected at assembly into an `app::env::ChildEnv` that `shell::exec::spawn` and `mcp::transport::spawn_stdio` apply — the names live in the host's file, never in the core: X-80); the ANSI host (OSC 9 / 9;4 through the facade), the herdr host (the pane's lifecycle, session and release as JSON lines over herdr's socket, or its CLI where there is no Unix socket, from one worker over a bounded queue), the cmux host, the background probe | `ui` and below |
| `repl/{mod,run,state,liveparams,catalog,editpicker,errors,title,systemtab}.rs`, `repl/turn/{mod,tools,retry,phases,steer,interrupt,approval,interact}.rs`, `repl/render/{mod,transcript,group,uisink,styles,diff,banner,replay,mcpreport}.rs`, `repl/context/{mod,meter,tokens}.rs`, `repl/commands/…` | the interactive loop over the facade: `run.rs` the loop, `state.rs` its state as `Conversation`/`SessionSlot`/`UiHandles`, `turn/` one turn (`TurnEngine` with the turn-level retry, the tool walk, steering, interrupts, approvals), `render/` what it draws, `context/` the token accounting, `catalog.rs` the `/model` listing, `liveparams.rs` the live half of the layered parameters, `commands/` the slash commands (no `/mcp`, X-42: `tools.rs` is the chat's view of the servers — one list of sources, a page per source, a reconnect on a server's page, X-79) | everything below |
| `repl/{mod,run,state,noticegate,liveparams,catalog,editpicker,errors,title,systemtab}.rs`, `repl/turn/{mod,tools,retry,phases,steer,interrupt,approval,interact}.rs`, `repl/render/{mod,transcript,group,uisink,styles,diff,banner,replay,mcpreport}.rs`, `repl/context/{mod,meter,tokens}.rs`, `repl/commands/…` | the interactive loop over the facade: `run.rs` the loop, `state.rs` its state as `Conversation`/`SessionSlot`/`UiHandles`, `noticegate.rs` whether a finished job's notice may open a turn — the hold an interrupt or a 429 leaves, the notices put aside and when they go out (X-84), `turn/` one turn (`TurnEngine` with the per-call retry ladder — a 429 on its own rungs, the tool walk, steering, interrupts, approvals), `render/` what it draws, `context/` the token accounting, `catalog.rs` the `/model` listing, `liveparams.rs` the live half of the layered parameters, `commands/` the slash commands (no `/mcp`, X-42: `tools.rs` is the chat's view of the servers — one list of sources, a page per source, a reconnect on a server's page, X-79) | everything below |
| `cmd/{mod,args,error,resolve,assemble,tuning,list,config_cmd,mcp_cmd,io,signals}.rs`, `cmd/interactive/{mod,picker,title}.rs` | the command: the clap verb set, the three-stage error taxonomy, pure run resolution, MCP/dispatcher assembly, the tuning warnings, the listings, `iota config`, `iota mcp`, `Streams` (the process's ONE stderr writer), signals, and the interactive branch with the `iota resume` picker and the title stack | everything |
| `testing/{mod,provider,dispatch,scripted}.rs` | the shared fakes behind the `testing` feature — `FakeProvider`, the fake dispatchers, the recording sink, `ScriptedUi` — not a layer | — |

Expand Down
1 change: 1 addition & 0 deletions docs/DIVERGENCES.md

Large diffs are not rendered by default.

Loading
Loading