Repository navigation
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bub | 5c0a5a9 | Commit Preview URL Branch Preview URL |
Oct 19 2026, 03:41 AM |
Closed
…349) Builtin model requests use Republic for provider authentication, message encoding and streaming. Bub owns turn orchestration, hooks, tool execution and tape storage, and converts persisted messages into Republic messages at the request boundary. - Tape messages use text/media blocks with kind, MIME type and URL, flat Republic tool-call fields and native token usage fields. Reasoning, opaque provider data and tool metadata survive tape reload and replay for the same provider/model. Tool calls recorded by older Bub versions in the Chat Completions form are converted on replay. - The runtime consumes the Republic stream directly and reads the completed outcome from `Stream.response`. Fallback applies before a stream opens; incomplete streams raise before tool execution. Model and stream contexts close owned HTTP clients on completion, failure and cancellation, and leave caller-supplied clients open. - ChatGPT plan access uses `codex:<model>` and `bub login codex`, with Codex CLI file credentials, `--device-auth` and an optional credential directory; `openai:<model>` uses API credentials. The bundled Codex provider is removed. Named endpoints keep independent credentials. - Provider names and protocol defaults follow Republic. Provider and chat options pass directly to Republic, which deep-merges provider defaults with `extra_body`; Bub supplies only the tools, the token limit and the session's reasoning effort. Onboarding includes Magpie and saves `api_format: chat` for Chat Completions services. - `build_prompt` returns a list of text and Republic media (`republic.image/audio/video`). Legacy string and content-block results are still accepted and converted (`bub.prompt`), and hooks that receive the prompt still get the legacy form. - Model clients identify themselves with `User-Agent: bub/{version}`; a User-Agent in `client_args.headers` still wins. - Requires the Republic 0.6 preview. English and Chinese docs describe the current commands, settings and message contracts. Co-authored-by: Frost Ming <me@frostming.com>
- Add a stdlib `republic` module to run_code: media classes, messages, get_model() (chat and stream), get_embedding_model() and get_decision_model(). Model calls are proxied to Bub, which uses its provider settings and credentials; they never reach the code. - Add code-only tools attach_image/attach_audio/attach_video that accept republic media or a path/URL/data URL and attach it to the run_code result, sent to the model as a multimodal tool message. - Add content results (bub.tools.content_result) for tool results with media; spilling bounds only their text. - Add Environment.read_bytes with a default that runs the environment's python. - Document the republic module in the code mode stub and prompt. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Bub's agent loop was tangled with settings, plugin hooks, skills and commands in `bub.builtin.Agent` / `ModelRunner`. Extract a reusable agent kernel into `bub.core` and rebuild the builtin agent on top of it. bub.core: - `Agent`: the agent loop over tools, system prompt sections and a tape store. It holds no settings, model or session; each run gets the model to call and works on a fork of a named tape. `async with agent.run(prompt, model=..., tape=..., state=...)` closes the stream (merging the fork and ending the `invoke_agent` span) on exit; `agent.start(...)` returns a stream for another consumer to close. - Models: a run accepts a `republic.ChatModel` directly; the `ModelClient` protocol covers callers with their own policy (fallbacks, credentials, timeouts). - Events (`bub.core.events`): run, step, LLM call, tool call and chat events, plus user-defined events, registered with `agent.events.on()`. `Before*` events can be modified or short-circuited. Tape recording is a `TapeRecorder` handler. - Commands: with `Agent(command_prefix=...)`, a prompt starting with the prefix calls a tool (or `bash`) directly; prefix rules live in `bub.core.commands`. - System prompt: ordered sections registered with `agent.add_system_prompt(...)`, each receiving a `PromptContext`. - Tape, store, sidecars, tools and tape context move into `bub.core`. The old `bub.tape`, `bub.store`, `bub.sidecars`, `bub.tools`, `bub.builtin.commands` and `bub.builtin.context` paths remain as module aliases. Builtin: - `BubAgent` (alias `bub.builtin.Agent` kept) subclasses the core agent, adding settings, plugin hooks, skills, code mode, deferred tools and steering. - `BubModel` replaces the candidate/fallback logic of `ModelRunner`. - `PluginAgentHooks` adapts the pluggy interception hooks to core events; hookspecs are unchanged. - Tape archiving moves into `bub.builtin.archive`; `Tape` and `Agent` no longer take an archive path. Behavior changes: - A session's `reasoning_effort` is fixed at the start of a turn. - Unknown `allowed_tools` raise before the session tape is forked. - `agent.tape(name, state=...)` returns a conversation's tape for use outside runs; `session_tape_name()` computes a session's tape name. - `Agent(store=...)` takes a store instance. Builtin channels no longer create the agent before `framework.running()`, so SDK users create `BubAgent` inside `framework.running()`. BREAKING CHANGE: `bub.builtin.model_runner` and the deprecated `bub.types` module are removed; `Tape` no longer takes an archive path.
Signed-off-by: Frost Ming <me@frostming.com>
`bub.core.Agent` accepts `republic.tools` built-in tools (`WebSearch`,
`WebFetch`, `CodeExecution`, `ImageGeneration`, `NativeTool`) alongside
`Tool` objects:
agent = Agent(model=model, tools=[my_tool, republic.tools.WebSearch()])
- Function tools stay in `agent.tools` by name; built-in tools go to the
new `agent.builtin_tools` list and are appended to `tools` on every
model call. Republic maps them to each API format's native definition.
- Providers run them server-side, so they bypass `ToolExecutor`,
`BeforeToolCall` and `prepare_tools`; their calls and results round-trip
through `ProviderData` on the tape.
…kernel (#361) Users who only embed the agent loop had to install all of Bub, and importing the kernel loaded the framework. Make `bub.core` installable and importable on its own, and tidy the kernel's API while it is in alpha. Packaging: - `pip install bub` installs only the kernel's dependencies (republic, pydantic, loguru, typing-extensions). The framework, CLI, channels, hooks, skills and builtin agent need the new `app` extra; `logfire` implies it. - The `bub` script (`bub.__main__:main`) checks the `app` extra's requirements from bub's metadata and exits with an install hint instead of an ImportError. `bub.__main__` imports nothing from the extra at import time. - The dev group depends on `bub[app]`, so `uv sync` keeps a full environment. The Dockerfile, install scripts and `bub install` request the extra. A new CI job checks that a plain wheel install imports `bub.core` without app dependencies and that `bub` asks for the extra. - `bub` exports its top-level names lazily through one `_EXPORTS` table, and `.env` is loaded by `bub.configure`, where settings read the environment, instead of `bub.framework`. Kernel layout: - `bub.core` holds the agent concepts: agent, commands, context, events, model, recorder, system_prompt, tape, tools, store and sidecars. `bub.tape`, `bub.tools`, `bub.store` and `bub.sidecars` remain aliases of the `bub.core` modules and need only the kernel's dependencies. - `errors`, `prompt`, `streaming`, `tracing` and `turn` stay top-level modules that need only the kernel's dependencies. - The newest-first, deduplicated fuzzy tape search moves from `FileTapeStore` into `bub.builtin.store.FuzzyFileTapeStore`, which `provide_tape_store` returns. The kernel's `FileTapeStore` uses the plain substring query, so `bub.core` needs neither yaml nor rapidfuzz. Agent events: - New `RunFinished` (status `ok`, `error` or `cancelled`, steps, elapsed time, error). It follows every `RunStarted` when the run's stream closes, even if it is never iterated, and is recorded as `loop.finish`. - Events are renamed to `*Started` / `*Finished`: `LLMCallStarted`, `LLMCallFinished`, `ToolCallStarted`, `ToolCallFinished` and `ChatFinished`. The payloads become `LLMCallRequest`, `LLMCallResult` and `LLMCallDecision`; `bub.hooks.interception` keeps the `LlmCall*` names as aliases. Hook names such as `before_llm_call` are unchanged. Runs: - `start` hands its `invoke_agent` span and close callback to `run_on`, which builds the run's only stream. - `run_once` is an async generator that writes usage into the run's `StreamState`. BREAKING CHANGE: install `bub[app]` (e.g. `uv tool install 'bub[app]'`) to get the `bub` command and runtime; plugins should depend on `bub[app]`. The core event classes are renamed, and `Agent.run_once` returns an async generator.
agent = Agent(model=model, tools=[...], max_tool_concurrency=2) Limit how many tool calls from one model response run at once. `None` (the default) runs them all concurrently; `1` runs them one at a time, in order; values below 1 raise ValueError. `ToolExecutor` takes `max_concurrency` and holds the limiter: an `asyncio.Semaphore`, or `nullcontext()` when unlimited.
Code mode lived in `bub.builtin` and depended on settings, `bub.home` and
the `BubAgent` turn state, so kernel-only users could not use it. Move it
into `bub.core.codemode` as a reusable `CodeMode` component:
code_mode = CodeMode([search, fetch], models="openai:gpt-5")
agent = Agent(model=model, tools=[code_mode.run_code],
system_prompt=["...", code_mode.prompt])
`CodeMode` takes the tools to expose (a list, or a selector per turn
state), `environment=`, `models=` (a spec or a `ModelResolver` for the
`republic` bridge), `stub_dir=`, `media_tools=` and `name=`. Nested tool
calls still emit `ToolCallStarted`/`ToolCallFinished` with
`context.code_mode=True`.
`bub.builtin.codemode` is now thin wiring: the `CODE_MODE` instance, the
session setting, settings-based model resolution and stub files under bub
home.
BREAKING CHANGE: `bub.builtin.codemode.code_runner` is now
`bub.core.codemode.runner`, `bub.builtin.codemode.republic_bridge` is now
`bub.core.codemode.republic_bridge`, and `LocalEnvironment` and
`LocalProcess` move to `bub.environment`.
Split the docs into SDK (`bub.core`) and app (`bub[app]`) guides for 0.6.0, with new pages for agent events, app tools, reusing plugins and supported versions, and refreshed English and Chinese guides, tutorials and references.
…371) * feat!: reuse plugin agent-loop hooks with core Agent through events Add `MessagesPending` and `StepEnding` events to `bub.core.Agent`, replacing the `pending_messages`, `has_pending_messages` and `continue_prompt` override methods. `MessagesPending` handlers add user messages before a step's prompt; `StepEnding` handlers decide whether the run continues and with which prompt. Add `bub.hooks.agent.AgentPlugins`, which connects a framework's agent-loop hooks to any core Agent: interception, `continue_prompt` and the steering inbox through `attach()`, `system_prompt` as a prompt section, store, tape context and sidecars through `components()`, and `load_state` and `provide_environment` through `build_state()`. `BubAgent` now uses it. BREAKING CHANGE: subclasses overriding `Agent.pending_messages`, `has_pending_messages` or `continue_prompt` must handle `MessagesPending` and `StepEnding` instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor!: merge StepEnding into StepFinished `StepFinished` now carries the step's `prompt`, the run's `stream` state and a settable `next_prompt`, which gives the next step a user message when the status is `continue`. Whether a run continues is decided before the event: tool calls, or messages `MessagesPending` handlers supply when a step ends without tool calls. These messages are sent in the next step, so the recorded step status is final and the steering inbox needs no separate continuation handler. The last allowed step leaves pending messages with their source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor!: add the plugin system prompt section in AgentPlugins.attach Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: let AgentPlugins create its framework from a plugin list and expose running() Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat!: provide tools through the provide_tools hook instead of @tool registration @tool no longer adds tools to a global registry. Plugins provide tools with the new provide_tools hook; the builtin plugin provides its tools this way, and AgentPlugins.attach adds hook tools to an agent. For plugins that still rely on @tool registering their tools, load_hooks collects the tools an entry-point plugin without provide_tools creates while it loads, and warns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Report command, channel work, and prompt state through the native EventBus. Preserve agent execution, normal text output, and exit codes, and keep redirected output free of status sequences. Co-authored-by: Frost Ming <me@frostming.com>
Signed-off-by: Frost Ming <me@frostming.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.