Repository navigation
agentty 0.9.7 — custom hosts, end to end
All about reaching any OpenAI-compatible endpoint, and telling the truth about what happened when you do.
Added
- Type an endpoint into
^Pand it offers to connect. agentty has always spoken to any OpenAI-compatible server (--provider host:port, or the "Custom host…" row), but the picker never said so: typing a hostname made every familiar provider disappear and left one muted grey row behind, which reads as "no". Now a query that looks like an endpoint — a dot, ahost:port, anhttps://— promotes a concrete "Use<host>as a custom OpenAI-compatible host" row to the TOP, andEntercarries the typed text straight into the connect probe instead of reopening an empty field. Saved custom hosts are searchable too (they used to vanish the moment you typed, so the only way back to one was scrolling past every built-in), the escape hatch is no longer painted in the muted style this TUI reserves for unavailable, and the footer says whatEnterwill actually do. - The connect probe says what went wrong and what to do about it. Three very different mistakes used to arrive as the same unhelpful string. A 200 with HTML — what you get from pasting a dashboard URL instead of the API base — now reads "that's a web page, not an API — use the API base URL (usually ends in /v1)" instead of "HTTP 200, no model list at any known path". A 401/403 means the address was right, so it routes you straight to the key prompt instead of dumping you back into a URL field you typed correctly. And the probe now ranks its attempts, so a 401 on the configured path is no longer buried under a 404 from the
/v1fallback.
Fixed
- A
Retry-Aftermeasured in hours is a quota, not a burst limit. A 429 carryingretry-after: 29410(8 hours, from a provider's daily free-tier cap) was clamped to 600s in the reducer and 30s in the agent loop, then retried three times — 95 seconds of waiting to print the exact message the first response already carried. agentty now honours a server hint up to 15 minutes and treats anything beyond it as terminal: 95s → 1.5s, with the provider's own actionable text. Burst limits are unaffected, and the error is still classifiedRateLimitso the loop-backoff schedule is unchanged. - A context window a gateway made up no longer breaks compaction. The window drives the gauge and auto-compaction, and the extraction narrowed straight to
int— so18446744073709551615became-1,4000000000became-294967296, and the string"1e6"became1. A negative window disables compaction entirely (everyused < windowtest is false) and a window of 1 compacts every turn; both read as "agentty is broken" rather than "this gateway reported nonsense". Values are now validated before narrowing and rejected outside a plausible 1024–100M band, and a partial string parse is treated as a misread rather than a lenient read. - Headless runs had an empty model catalog.
agentty runandagentty acpnever build a Model, so the subagent config was installed withoutcandidates— leavingcontext_windowat 0 on every headless turn (the Ollama transport then fell back to the daemon's ~2k/4k default, truncating exactly the long runs headless is for),cheapest_capable_model()with nothing to choose from (read-only subagent roles never routed down), and Smart Mode's role resolver with no candidates (pinned slots silently fell back to the parent model). Seeded from the same bundled catalog the TUI uses. - Reasoning text no longer disappears on gateways that send both spellings. Some OpenRouter passthroughs emit an empty
reasoning_contentalongside a populatedreasoning; taking the first key that merely exists dropped every reasoning token, silently.
Changed
- The OpenAI-compatible dialect is now observed through one table, not scattered
ifs. Every way this spec-less wire spells a field — the two reasoning spellings, three error envelopes, Mistral's structured content parts, optional tool-call indices — lives in one place with the endpoint each was observed on. Two sites were separately parsing error envelopes by hand, neither knowing all three shapes; an unrecognised envelope reaches you as "the model stopped for no reason". - What agentty sends, and to which endpoints, is now written down and enforced. The request body is a pure function with unit tests, so the field policy is a contract rather than a comment. Notably
max_tokensis sent deliberately instead of OpenAI's newermax_completion_tokens: vLLM, llama.cpp and Together accept only the old name, and OpenAI still honours it — one spelling that works everywhere beats conformance that works on one host. - The context-window toast says where the number came from —
131k ctx (advertised)when the endpoint told us,ctx: defaultwhen nothing did. A window the server promised and one we assumed used to look identical, which made a wrong window impossible to debug.