mirror of
https://github.com/open-webui/computer.git
synced 2026-11-05 01:17:24 +00:00
[GH-ISSUE #120] Proposal: Add Pi coding agent as a first-class agent profile #57
Labels
No labels
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
open-webui/computer#57
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @kelvinq on GitHub (Jul 10, 2026).
Original GitHub issue: https://github.com/open-webui/computer/issues/120
Thank you, Tim, for open-webui and now for
computer. Both have been a joy to use and to build for.Opening as an issue because PR creation is limited to collaborators. The change is complete and ready on my fork: kelvinq/computer:feat/pi-coding-agent-pr (rebased on v0.8.8, 101 tests passing). Happy to open it as a PR if you enable it, or feel free to pull the branch.
Add Pi coding agent as a first-class agent profile
Rebased on
origin/main@v0.8.8. 22 files, +4862 / −1767 (the large delta isuv.lock: auvformat-revision rewrite, not new runtime deps). No runtime dependency: Pi is invoked as a CLI subprocess, so the only new packages are the dev-group test tools. 102 tests, 101 passing.Adds Pi (
@earendil-works/pi-coding-agent) as a 7th first-class coding agent, in the same one-file-per-agent pattern as codex and cline. Admins add it from the agents panel like any other agent. Users pick a Pi model in the model picker and chat with it through the existing task runner. Unlike the single-model agents, Pi exposes a whole roster of models across providers through one profile (agent:pi · 30 modelson this box).Summary
Pi speaks JSON-RPC over stdio behind a
--mode rpcflag. This change adds aPiRpcClientstdio transport and arun_pi_agentasync generator that adapts Pi's event stream onto cptr's existingAgentEventtypes, then wires Pi into registration, dispatch, detection, and the admin UI. It sits alongside codex, claude_code, cursor, grok, opencode, and cline.The integration lives entirely in one module,
cptr/utils/agents/pi.py(626 lines), following the single-file-per-agent convention. Pi is a CLI peer ofcodex,claude, andcline, not a Python package, so this adds no runtime dependency.Changes
22 files against
origin/main(+4862 / −1767; the lockfile accounts for the bulk, see Dev deps below):cptr/utils/agents/pi.py(new, 626 lines) —PiRpcClient(stdio JSONL transport), event-translation helpers mapping Pi RPC events to cptrAgentEvents, and the publicrun_pi_agentasync generator.models.py("pi"in_VALID_AGENTS, a default profile, a default row, alaunch_args-trimming normaliser branch),chat_task.py(runners["pi"] = run_pi_agent),model_targets.py("pi"in theAgentModelTarget.agentLiteral),detection.py(apibranch:pi --mode rpc --helpprobe then RPC model listing, with api --list-modelsfallback).admin.ts("pi"in theAgentTypeunion),AgentProfileModal.svelte(Pi in the type dropdown + alaunch_argsfield),Agents.svelte(label/command maps).tests/agents/(7 files, 99 unit tests, incl. afake_pi_rpc.pyJSONL double that drivestool_execution_updatewith accumulatedpartialResult),tests/integration/test_pi_e2e.py(3 real-binary tests).README.md(Pi listed with the other coding agents),CHANGELOG.md(Unreleased entry, matching the Cline precedent).pyproject.tomladdspytest+pytest-asyncioto thedevgroup with a[tool.pytest.ini_options]block. Theuv.lockdiff is large (+4862 / −1767) but its substance is small: it adds five packages (iniconfig,packaging,pluggy,pytest,pytest-asyncio) and changes no existing version. The line churn is auvlockfile format-revision rewrite (the local resolver emits the newer format), not a dependency change. If the project pins a specificuvversion for lockfile generation, re-running it under that version collapses the diff to a handful of lines.How it works
Pi's
--mode rpcstarts a JSON-RPC server on stdio that splits records on\nonly and rejects Unicode line separators.PiRpcClientenforces that contract with manual buffer splitting and a small async read task. (One spec detail worth noting: under--mode rpc, help text goes to stderr because stdout is reserved for JSONL. The detection probe handles this.)The runner is a thin adapter: build a client, start it, call
prompt, forward each event throughtranslate_event. Pimessage_updateevents map toAgentTextDeltaandAgentReasoningDelta(reasoning blocks close implicitly, the same path every other agent uses). Thetool_execution_startandtool_execution_endevents map toAgentToolUpdate. Thebashtool name is renamed torun_commandso it renders like every other agent's shell tool.Models come from
get_available_modelsover RPC. The detection layer probes RPC first and falls back topi --list-models. Resume is supported viasession_idstored inchat.meta.agent_sessionsand proven by the e2eTestPiE2EResumeround-trip.Streaming tool output
Pi's RPC spec carries the accumulated output in
tool_execution_update.partialResult, not the new chunk. cptr'schat_taskappendsAgentToolOutputDelta.deltato existing output on the consumer side, so a naive forwarder concatenates"a" + "a b" + "a b c"into"aa ba b c". Output grows quadratically with each update and is scrambled. This is the integration's load-bearing correctness problem.The adapter handles it in
run_pi_agent: it tracks the last-forwarded text percall_idand emits only the new suffix as the delta. Because Pi models updates as replace-your-display, if a laterpartialResultis not a prefix-extension of the previous one the adapter re-emits the full new text and resets the per-call counter (so a truncation can't silently go mute or slice at a stale offset). The consumer still appends, so a genuine truncation renders asold + newconcatenated rather than a clean replace. A true display-replace would need a consumer-side change and is out of scope here.Covered by:
tests/agents/test_pi_runner.py::TestStreamingToolOutput(monotonic deltas concatenate exactly once)tests/agents/test_pi_runner.py::TestStreamingToolOutputTruncationSafety(non-monotonic and shorter-prefix resets)tests/integration/test_pi_e2e.py::TestPiE2EStreamingToolOutput(a 12-linebash printfagainst the real binary: the test whose absence would have let the bug ship)Tests
102 collected (99 in
tests/agents/, 3 intests/integration/). The single skip is a deliberately slow timeout test (test_request_timeout, off by default, run with-k test_request_timeout).Real-RPC integration tests against the
pibinary on PATH:The integration module uses
pytestmark = pytest.mark.skipif(not _AUTH_OK, ...), where_AUTH_OKruns a tinypi -pprobe against an authed provider, so CI without secrets stays green. Registration is asserted at three layers bytests/agents/test_pi_registration.py(callable runner,AgentModelTarget.agentLiteral membership, and the"pi": run_pi_agentdispatch entry).Compatibility
The change adds a new agent kind and renames or removes nothing. Existing
agents.profilesentries parse unchanged throughnormalize_agent_profiles. The default profile list grows from six to seven. The RPC client is gated behindprofile["agent"] == "pi", so other code paths never importPiRpcClient. The dispatch change is one new key in one map inside_run_agent_target, and no conditionals changed elsewhere.Trade-offs
tool_approval_mode,sandbox_mode, orpermission_modeflags (those translate into agent-specific CLI args, and Pi's RPC interface has no equivalent). This is intentional. The admin modal therefore does not surface those fields for Pi: admins configure Pi's approval behaviour through Pi's config andlaunch_args. The flags are still accepted and ignored by the normaliser, so existing profiles carrying them stay forward-compatible.\n-framed JSONL and rejects Unicode separators, and the client splits manually rather than callingreadline(covered bytest_pi_client.py). Detection has a 5-second RPC timeout with a--list-modelsfallback when RPC is unavailable. Bad provider keys or a missing binary surface immediately:PiRpcClientring-buffers the last 20 stderr lines and folds them into theAgentErroron prompt failure, timeout, or start failure (covered byTestStderrCapture).Visuals
Agents panel — Pi registered (
agent:pi · 30 models,Ready, green dot) alongside Claude Code, rendering identically to the other agent rows. The footer reads2 profiles.Add-profile modal — the agent-type dropdown offers
Pi. Selecting it fills Name=Pi, Command placeholder=pi, and surfaces theLaunch argumentsfield, so Pi profiles are addable and editable from the panel like any other agent.Checklist
origin/mainat v0.8.8@tjbck commented on GitHub (Jul 11, 2026):
Appreciate the kind words, Addressed with the latest main!