v0.7.0
A chat is no longer tied to the provider it started on. Pick a row on another
endpoint in /model and the chat moves there — at once before the first
reply, after you agree once a reply exists — and iota resume <id> -M now
moves a session for good. To make that possible, a session records the
providers: entry it runs on by name, and sessions written by earlier
versions are no longer read until you convert them once (below). The
Anthropic dialect asks for up to 32000 output tokens instead of 4096, a new
max_tokens: key sets that ceiling, and an output the ceiling cut off is shown
as an error instead of being passed off as the answer.
Upgrading: convert your saved sessions
Sessions saved by v0.6.1 and earlier (session format v1) record a provider
type and a URL; v0.7.0 records the provider's name and does not read v1.
Opening an old session is an error that names the script that converts it:
scripts/session-v1-to-v2.py
in the iota repository. Run it once, with the config your sessions ran under:
python3 session-v1-to-v2.py # report what it would change; writes nothing
python3 session-v1-to-v2.py --write # apply it
It rewrites each bundle's meta.json and nothing else — the transcript and
the attachments stay as they are — and skips a bundle already converted, so a
second run changes nothing. It picks the provider by the endpoint the session
recorded: the one entry of that type whose url: is that URL, or the type's
built-in provider when the session ran on the default endpoint. When that does
not settle it — no entry matches, two do, or an entry of another type has
taken the built-in's name — it reports the bundle and leaves it alone; decide
with --map TYPE=NAME (repeatable). --sessions points it at another sessions
root than ~/.iota/sessions, --config passes -c to the iota it asks for
the providers, and it exits 1 while any bundle is left unconverted.
Added
- A chat can move to another provider from
/model. A row on another endpoint used to be refused with "start a new session there". Before the first reply, picking it now moves the chat. After a reply, iota first saves the chat, then tells you how many earlier replies carry provider-specific payload (reasoning, provider-side tool state) the target will not replay, thatiota resume <id>continues on the new model afterwards, and that picking the old row moves it back — and asksMove this chat to <provider>:<model>?before anything changes. Your hand-set settings come along as they do on a-Mresume. A chat that is not saved is told to/savefirst, a model of another kind (an image model for a chat) is still refused, and a bot never moves: its config does. max_tokens:sets the output ceiling of an Anthropic-dialect model. It goes on amodels:entry or anagents:entry, the agent's winning, as foreffort,temperatureandtop_p, and must be 1 or more (config max_tokens 0: want 1 or more). A session records it, andiota resumerestores what was recorded whatever the config says today; a bot takes it from its config on each start. Thinking counts toward it. There is no/modeltab or flag for it, and on any other provider type the key does nothing and says so with a warning.
Changed
- Sessions record their provider by name, and resume there. A session now
stores the
providers:name it runs on (session format v2) instead of a provider type and a URL, andiota resume— and/session— opens that provider from the config, as if-M <provider>:<model>had been typed. A name the config no longer defines is an error that says how to resume it elsewhere (-M <provider>:<model>), never a quiet fall back to another endpoint; and a missing key on the agent's own endpoint no longer stops a session that runs on another. Older sessions need the one-time conversion above. iota resume <id> -Mmoves the session for good.-Mon a resume used to change only that run; the session now records the new provider and model, so the next plainiota resumecontinues there. What you set by hand — effort, temperature,top_p, the output ceiling — comes along unless the config there sets it; what the old endpoint's config supplied stays behind.- The Anthropic dialect asks for up to 32000 output tokens, not 4096. A
thinking model could spend all of 4096 thinking and be cut off before it
wrote a word. The ceiling is a bound, not a charge — tokens are billed as
they are produced. An endpoint that caps lower answers a too-large value
with an error; set a smaller
max_tokens:for that model. - An output the ceiling cut off is an error, never the answer. On the
Anthropic dialect and the Responses dialect, the chat shows a red
Output truncatedblock: what cut it, the tool call it was composing if any (dropped by name — it does not run), and what to do — raisemax_tokens:on Anthropic, lower the effort in/modelor ask for a shorter reply on Responses. Text the model did write is kept, marked incomplete; with nothing to keep, the turn is rolled back. A cut is not retried. With-mit fails the run (exit 1,Error: output truncated — …, nothing saved); a cut-off compaction summary fails instead of replacing the history with a fragment, and a cut-off title leaves the placeholder. /modelrows read the same wherever the chat is. A row isprovider:model, or just the model when every choice is on one provider, followed in brackets by themodels:entries that name it (relay:vendor/fast [fast]). What picking it does is an annotation beside it, like(current):(moves the chat), or(needs a new session)in a bot.- Anthropic calls without tools stream too. A
-mrun with no tools, the compaction summary and the title used a non-streaming request, which sends nothing until the whole output exists and could outlast the 120-second wait for a response. They now stream like the chat, so an Anthropic-compatible endpoint that cannot stream fails there instead of answering.
Fixed
- An Anthropic stream that stops early is an error, not an answer. A
response that ended before the message did — no
message_stop, no stop reason — was taken as complete, so-mand a compaction could succeed on a fragment. - A failing request without tools is sent 11 times, not 121. A turn that offered the model no tools retried inside a retry, so one failing request (a 5xx, a dropped connection) could go out up to 121 times with minutes of backoff. Every model call now has one set of ten retries.
- Typing a choice's name in
/modelpicks that choice. Typingfast, the name of amodels:entry, sentfastto the provider as a model id; the field now reads typed text as-Mdoes, andprovider:*picks nothing.