Skip to content

0.6.0

Latest

Choose a tag to compare

@frostming frostming released this 31 Oct 08:58
· 5 commits to main since this release
760691d

Bub 0.6.0 is the first stable release of the 0.6 line. It splits Bub into an embeddable agent kernel, bub.core, and the full app, bub[app]. It also moves model access to Republic and turns the agent loop into events that plugins and SDK users share. This note covers everything since 0.5.1. If you tested the 0.6.0 alphas, the changes after 0.6.0a3 are listed in Since 0.6.0a3.

Highlights

pip install bub installs only the agent kernel

bub.core installs and imports without the rest of Bub. Its only dependencies are republic, pydantic, loguru and typing-extensions. The CLI, gateway, channels, plugin system and TUI prompts are in the app extra:

pip install "bub[app]"      # full Bub: CLI, gateway, channels, plugins
pip install bub             # kernel only, for embedding bub.core.Agent

If you run bub without the extra, it lists the missing packages and tells you how to install them. The Docker image, install.sh / install.ps1 and bub install already install bub[app].

An event-driven core Agent

bub.core.Agent runs the agent loop over a tape store and reports every step on an EventBus: RunStarted / RunFinished, LLMCallStarted / LLMCallFinished, ToolCallStarted / ToolCallFinished, StepFinished, MessagesPending, ChatFinished. It also accepts:

  • Republic built-in tools (WebSearch, WebFetch, CodeExecution, ImageGeneration, NativeTool) alongside ordinary tools. The provider runs them server-side.
  • max_tool_concurrency= to limit how many tool calls from one response run at once.

The system prompt and tools are now prepared once per run, so the request prefix stays stable across the steps of a turn and prompt caching works better. The system prompt is recorded on the tape only when it changes.

Reuse Bub plugins with any core Agent

bub.hooks.agent.AgentPlugins connects plugin agent-loop hooks (before/after_llm_call, before/after_tool_call, continue_prompt, provide_steering_inbox, system_prompt, tape store/context/sidecar, load_state, provide_environment, and the new provide_tools) to any bub.core.Agent:

plugins = AgentPlugins()                      # builtin + installed plugins
agent = Agent(model=model, **plugins.components())
plugins.attach(agent)

BubAgent uses the same adapter, so plugins behave the same in both.

Code mode as a reusable component

Code mode lives in bub.core.codemode. Any core agent can use it without the app extra. Code can call Republic models and pass media attachments.

from bub.core.codemode import CodeMode

code_mode = CodeMode([search, fetch], models="openai:gpt-5")
agent = Agent(model=model, tools=[code_mode.run_code], system_prompt=["You are ...", code_mode.prompt])

Models and accounts through Republic

Built-in model requests use Republic for provider authentication, message encoding and streaming. Reasoning and provider data survive tape reload and replay.

  • ChatGPT plan access: codex:<model> with bub login codex (supports --device-auth). openai:<model> uses API credentials.
  • Named endpoints keep separate credentials. Provider-specific request fields go in extra_body.

CLI improvements

  • bub without a command starts bub chat.
  • bub --version / -V, and bub plugins shows each loaded plugin's distribution and version.
  • ,model completion lists the models each configured provider offers. ,model <provider>: narrows the list to one provider.
  • Token speed is measured from the first streamed chunk. Usage events now report elapsed_seconds, ttft_seconds and total_seconds.
  • Bub reports its status to the terminal with OSC 7501. The sequences are not written when output is redirected.

Docker images on GHCR

Each release publishes a multi-arch image: ghcr.io/bubbuild/bub:0.6.0, :0.6 and :latest. See Deploy the app.

New docs

The docs at bub.build are reorganized into SDK (bub.core) and app (bub[app]) guides, in English and Chinese.

Fixes

  • Context size errors such as exceed_context_size_error now start the automatic handoff instead of failing the turn.
  • Models no longer call tool_describe again for deferred tools they have already loaded. tool_describe lists them under already_loaded.
  • The "reply via channel" instruction is added only to turns run by the channel manager, so bub acp and direct process_inbound() turns no longer look for a Telegram token.
  • A failed tool call is reported in tool_results as a BubError, so consumers such as the ACP server can mark it failed.
  • The bub chat prompt no longer redraws itself forever.
  • Fuzzy and non-ASCII tape search works again, and multi-byte UTF-8 characters split across shell output chunks are preserved.
  • Tool calls recorded in Chat Completions format by older tapes replay correctly.
  • Security updates for aiohttp, multidict, urllib3, certifi and uv.

Upgrade notes

  • Install the app extra wherever you use the CLI, gateway, channels or plugins: pip install "bub[app]" / uv add "bub[app]". pip install -U bub alone leaves the bub command without its dependencies.
  • Module moves. bub.tape, bub.tools, bub.store and bub.sidecars are now in bub.core.*. The old names still import as aliases, and so do LlmCallRequest / LlmCallResult / LlmCallDecision, so most 0.5.x plugins work unchanged. Code mode internals moved without aliases: bub.builtin.codemode.code_runner → bub.core.codemode.runner, bub.builtin.codemode.republic_bridge → bub.core.codemode.republic_bridge, LocalEnvironment / LocalProcess → bub.environment.
  • Event renames: BeforeLlmCall → LLMCallStarted, AfterLlmCall → LLMCallFinished, BeforeToolCall → ToolCallStarted, AfterToolCall → ToolCallFinished, ChatCompleted → ChatFinished. Hook names are unchanged.
  • Tools. @tool no longer registers tools globally, and bub.core.tools.REGISTRY is no longer filled. Plugins should provide tools with the new provide_tools hook. Tools that an entry-point plugin creates with @tool at import time are still collected, with a DeprecationWarning. To look up tools, use an agent's tools or framework.get_tools().
  • Agent overrides. Agent.pending_messages, has_pending_messages and continue_prompt are gone. Handle the MessagesPending event and set StepFinished.next_prompt instead.
  • Failed tool results. Failed entries in ToolExecution.tool_results and in tool_results event data are now BubError instances, not dicts. The tape still records them as dicts. Failed results are no longer spilled.
  • Models. For ChatGPT plan access, switch to codex:<model> and run bub login codex. Pass provider options through to Republic, and put provider-specific fields in extra_body.
  • Smaller changes: .env loading moved from bub.framework to bub.configure. run_once is an async generator. The kernel's FileTapeStore matches by substring; the builtin plugin still provides fuzzy search through bub.builtin.store.FuzzyFileTapeStore.

Since 0.6.0a3

The breaking changes in this list are AgentPlugins / provide_tools (#371) and BubError tool results (#385). The other changes are Republic-based models and bub login codex (#349), OSC 7501 status (#345), per-run prompt and tool preparation (#376), the new CLI options and ,model completion (#377, #380, #381, bub → bub chat), the token speed fix (#386), the channel prompt fix (#384), the deferred tools fix (#387), the context size fix (#388), security updates (#374, #378) and the docs overhaul (#375).

Changes

   🚨 Breaking Changes

   🚀 Features

   🐞 Bug Fixes

    View changes on GitHub