Skip to content

AgentOS 2026.8.12

Choose a tag to compare

@github-actions github-actions released this 12 Aug 17:05
· 452 commits to main since this release
f17fa38

A model-control and reasoning release. Choosing which model answers a turn is now a control in the chat composer rather than a slash command to remember, and a pin you set stays set. The Web UI shows the model thinking while it works, and a hub-installed skill that renames itself in its own manifest no longer masquerades as a local one.

Added

  • A route picker in the chat composer. One searchable list holding Auto, the text tiers your [agentos_router] config actually defines — each labelled with the model it resolves to, e.g. c1 · gpt-5.6-luna — and every model the active provider publishes. Auto hands routing back to the Pilot Router and reports the tier it last chose (Auto · c2), so automatic routing stays legible rather than opaque. With no Pilot Router configured the control is disabled rather than hidden, which keeps the composer from reflowing when the router is toggled.

    • The pin is read back from the gateway, not mirrored in the browser. A new router.hold.get RPC is the single source of truth, so a reload shows the pin that is really in force and a pin set from /c3 agrees with one set from the picker. Two surfaces holding their own copy of the same state is how they drift.

    • /use <model-id> does the same from a slash command on web, TUI and channels. It is a new verb rather than an argument to /model, whose argument already filters the listing — overloading it would make /model gpt ambiguous between "show me the gpt models" and "switch to gpt".

    • A directly-named model rides on the default tier. Thinking level and pricing baseline live on a tier, not on a model id, so a bare model id inherits them — which also keeps the router step's tiers[hold.tier] lookup valid.

    • Only the active provider's models are offered, and accepted. Every turn runs through the single configured llm.provider; a tier's provider field is metadata, not a client selector. Anything else is refused at the moment it is chosen rather than failing on the next turn. On OpenCAP that means the bare canonical ids, not the namespaced <upstream>/<model> aliases its inference endpoint also answers to.

  • The Web UI shows the model thinking. Reasoning arrives as a typed ThinkingDeltaEvent from the Anthropic, OpenAI-compatible and Ollama providers — including models that emit <think> tags inline, split back out of the text stream as it arrives — and renders as a live collapsible block that folds itself the moment reply text starts. A fresh block opens per reasoning round, so mid-turn work stays visible instead of being appended to the first one. History carries a has_thinking flag so a reloaded thread still offers the block, and control_ui.show_thinking (default true) gates the whole surface.

    • It is web-only by construction. Thinking travels on a session.event.thinking emit path and a CONTROL_ONLY chat.thinking RPC, so channel adapters never receive it — reasoning is not something to page a Telegram or Discord thread with, and a flag that could be flipped the wrong way is weaker than a path that does not exist.
  • The composer border carries a light sweep while a turn runs.

Changed

  • Breaking: a tier pin set by a user is now sticky. /c0/c3 — in the Web UI, the TUI, and every channel — hold until /auto clears them, instead of lapsing after ten idle minutes. A pin is a standing instruction, and a selection that silently reverted would have made the new composer control lie about what is running. The practical consequence is a bill: pin /c3 and forget, and every later turn keeps paying for c3 until someone runs /auto. Routing the model chooses for itself mid-turn is unchanged and still lapses on its own. Two things still outrank a pin, both pre-existing: image turns route to a vision tier before pins are consulted (the Web UI flags such a turn), and a pinned turn skips the large-context tier floor, so it fails at the provider rather than being upgraded if the conversation outgrows the pinned model's context window.

  • The router-fx strip is suppressed while a tier or model is pinned. It exists to show the router weighing candidates and settling on one; a pin decides the route up front, so the animation was dramatizing a deliberation that never happened and restating the composer's own picker every turn. It returns the moment routing goes back to Auto.

  • A pin withdraws the model's own router_control tool for the duration, along with its target menu in the system prompt. The user's choice already outranked the model inside the router step, so leaving the lever on the surface only invited calls that could not take effect and paid tokens to describe them. Holds the model installs for itself are unaffected — hiding the tool on its own hold would strand a session on a transient escalation.

Fixed

  • A hub skill whose SKILL.md renames itself no longer renders as a local one. The lockfile is keyed by the install directory — the source's slug, which is also the directory the installer writes into — but it was read back by the name the frontmatter declares, and published skills do rename themselves: hub ytdlp-transcript ships a manifest named youtube-transcript. The lookup missed, _derive_acquisition saw no entry, and a perfectly ordinary hub install rendered under "Your local skills" with no source, no version, no scan facts, and neither a Remove nor an Update button — the same wrong row reaching agentos skills list and the agent's skill_list. Entries now join by the resolved path the entry already records, falling back to the name for legacy entries written before path existed. (Fixes #285)

    • The removability guard read the manifest name too, so it reported a removable install as an orphan. The BUNDLED exception is still applied before either lookup, so a stale entry recording the packaged bundled directory cannot turn a shipped skill into a removable hub install.

    • skills.uninstall and skills.update translate through lock_key_for_skill. They address the installer, which is keyed by the directory, while every caller addresses the name a user sees. The wire contract is unchanged and a name no skill loads under is still passed through, so clearing a stale entry by its own key keeps working. The CLI's no-gateway uninstall path resolves the same way, against a loader now shared with skills list rather than built twice.

    • Installs already on disk heal themselves: no lockfile migration, no re-install, no frontend change.

  • OpenCAP and Bankr routes reported supports_reasoning=False for every model, which silently no-oped a tier's thinking_level — a setting that appeared to apply and did nothing.


Full changelog: v2026.8.11...v2026.8.12