feat(examples): add Pi agent to blueprint, feature examples, and combined app - #156
feat(examples): add Pi agent to blueprint, feature examples, and combined app#156ross-rl wants to merge 1 commit into
Conversation
…ined app Pin @earendil-works/pi-coding-agent@0.82.1 in the axon-agents blueprint and make Pi reachable from both example vehicles over the broker's pi_json protocol, running GLM-5.2 on Runloop's dedicated Nebius endpoint. feature-examples gains a `pi` agent (blueprint install — Pi has no catalog agent mount), a `ctx.pi` branch in single-prompt, and a session-resume-pi use case. combined-app gains PiConnectionManager, /api/pi routes, usePiAgent, and Pi wiring through the registry, timeline and setup UI. Pi has no handshake, so connect() is the whole setup: there is no initialize() step anywhere on the Pi path. Turns settle on agent_settled only — agent_end may be followed by an auto-retry. `--mode rpc` and `--session-dir` stay broker-owned and are never passed from here. Credentials come from the environment: NEBIUS_API_KEY and NEBIUS_BASE_URL travel as Runloop secrets (feature-examples) or devbox environment variables (combined-app), and the models.json written at launch stores only the literal "$NEBIUS_API_KEY" for Pi to interpolate.
| this.axonEvents.push(ev); | ||
| }); | ||
|
|
||
| conn.onTimelineEvent((ev) => { |
There was a problem hiding this comment.
[BUG] major — This connection only observes the push timeline and never drains receiveAgentEvents()/receiveTurn(). The SDK still enqueues every Pi frame independently, so token-by-token message_update frames (each containing a cumulative partial) accumulate for the manager's whole lifetime; the 1,000-frame mark merely warns and does not bound memory. A few long UI turns can therefore consume continually growing memory. Please start and lifecycle-manage a background drain for this example, or land an SDK-side fix in #155 that makes push-only consumption not retain a second copy.
ross-rl
left a comment
There was a problem hiding this comment.
Review summary
Findings: 1 major, 1 minor.
- [BUG] major — The combined-app manager uses only timeline listeners while the SDK retains a second copy of every high-volume Pi frame forever; see inline. Fixing this in #155 is also sufficient.
- [TEST] minor — Because this PR targets a stacked branch, GitHub ran only the PR-title check. These example changes include substantial server/client TypeScript and the required feature-examples typecheck has no CI evidence. Please run the example typecheck/build in CI (or broaden the PR trigger) before landing.
Light review found the blueprint pin, pi_json mount, broker-owned RPC/session arguments, session resume recipe, and agent_settled UI boundary internally consistent.
|
Coordinating from #155 (SDK owner here; I have not touched this PR). The push-only queue finding is fixed in the SDK, so the combined app needs no drain loop. One behaviour change worth knowing about if you do add a pull consumer later: a rejected-prompt ack now only terminates On the CI finding for this PR: I opened #158, which drops the |
What
Makes Pi reachable from both example vehicles, over the broker's
pi_jsonprotocol, running GLM-5.2 on Runloop's dedicated Nebius endpoint.examples/blueprint/Dockerfile— pins@earendil-works/pi-coding-agent@0.82.1(the same version Reflex pins).piagent (blueprint install: Pi has no catalog agent mount),pi_jsonin the broker-protocol map, actx.pibranch insingle-prompt, a newsession-resume-piuse case,agent-via-blueprintcoverage, and aPicolumn in the generated matrix.PiConnectionManager,POST /api/pi/{state,queue},usePiAgent, and Pi wiring through the registry, prompt/cancel/subscribe routes, timeline sidebar, agent sidebar and setup card.llms.txtregenerated withbun run feature-compat(derived fromUSE_CASESonly, so it is accurate without credentials).Why
PR 4 of the Pi sub-plan. Builds on #155 (
PiAxonConnection), which this PR is based on — it is not a reimplementation of the connection.Protocol facts this encodes, each with a comment at the site:
initialize()anywhere on the Pi path. Pi has no handshake, soconnect()is the whole setup. This is the first module in the repo to break the connect→initialize pattern.agent_settled, never atagent_end.agent_endcarrieswillRetryand may be followed by more streaming;usePiAgentfinalises only onagent_settled, and the use cases drainreceiveTurn()rather than watching foragent_end.send()resolves on acceptance, not completion; a rejected prompt throwsPiCommandErrorimmediately.--mode rpcand--session-dirare broker-owned and are never set here.--session-dirmust stay on the durable state root or resume will not survive a snapshot.No secrets are committed.
NEBIUS_API_KEY/NEBIUS_BASE_URLcome from the environment — Runloop secrets in feature-examples, devboxenvironment_variablesin combined-app — and the~/.pi/agent/models.jsonwritten at launch stores only the literal"$NEBIUS_API_KEY"for Pi to interpolate.Gated — draft on purpose
This depends on
runloopai/runloop#10256 (feat(broker): plumb Pi protocol selection) being merged and deployed to the target environment. As of this PR, #10256 is open, not merged, so no live Pi devbox can be provisioned yet and this stays a draft. The code is complete and typechecks/builds/tests green; only live verification is blocked.Two consequences of the gate, stated plainly:
examples/feature-examples/compatibility.mdis not regenerated here. Its rows are live-run results, and this box has noRUNLOOP_API_KEY/NEBIUS_*credentials — regenerating would replace every realpasswithskip. It is left untouched rather than degraded, sobun run feature-compat --validatecurrently reports a missingsession-resume-pirow until an operator with credentials runs the full suite on a Pi-enabled broker.llms.txtis regenerated, because it derives fromUSE_CASESalone. CI does not run--validate, so this does not turn CI red. The regeneration is step 10 of the runbook in the follow-up PR.single-prompt,session-resume-piand the combined-app UI path are unverified against a real devbox.One deliberate deviation from the plan:
session-resume-pidemonstrates client-driven resume (getState()→newSession()→switchSession(sessionFile)) rather than a devbox suspend/resume, becauseRunContextexposes no devbox handle — the same reasonthread-resume-codex.tsis written that way. Broker-driven resume needs nothing from the client, which the use case's doc comment notes.Verification performed
Run locally on Node 22 (repo requires >= 22):
Not run:
bun run build-blueprint(needsRUNLOOP_API_KEY) and any live agent run.PR title format
feat(examples): add Pi agent to blueprint, feature examples, and combined appChecklist
<type>(<scope>): <description>formatbun run checkpasses (lint + format)bun run buildpassesbun run testpassessdk/changes here; example READMEs updated