Skip to content

feat(agents): add the pi coding agent to the shipped agents bundle - #111

Merged
psinghal20 merged 7 commits into
mainfrom
feat/pi-a2a-agent
Oct 20, 2026
Merged

psinghal20 merged 7 commits into
mainfrom
feat/pi-a2a-agent

Conversation

@psinghal20

@psinghal20 psinghal20 commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds src/agent_env/agents/agents/pi, the pi coding agent wrapped with the agentenv_protocol.a2a_agent framework, to the shipped agents bundle beside Claude Code. It deploys as @local/agentenv-framework/agents/pi, and agent-env run agents --task pi-smoke runs its smoke task, which needs [model] default (or the agent role) set, since pi takes its model from the prompt.

  • Each task runs pi --mode json once in /workspace. The prompt goes in on stdin. Images and text files are attached with @path; other files are saved to disk and their paths added to the prompt for pi's tools.
  • Each task gets a fresh pi config dir:
    • models.json points provider agentenv at LITELLM_BASE_URL. The key is a ${LITELLM_API_KEY} reference, so it never reaches disk.
    • mcp.json lists the registered MCP servers with exposure: "direct". pi's default codemode would hide their tools from the model.
  • A context maps to one pi session id (--session-id), one-to-one, so follow-up tasks resume the conversation.
  • The directory is a self-contained build context. The protocol package is pinned from PyPI, and install.sh (Node, pi, Python env) is shared by the image build and install/v1.
Extension Implementation
agent-config PiConfig: model, effort (pi thinking level), system prompt, tools, model_params, timeout
mcp-config, triggers SDK defaults
skill-config inline and bundle skills installed as SKILL.md dirs, passed with --skill
trajectory pi JSON events, with streaming deltas dropped
snapshot save/load of the pi session JSONL plus a workspace tarball; load replaces the workspace (staged, so a bad archive changes nothing) and is refused while a task runs
snapshot changelog one NNNNNN.tar per tool result: changed files under the roots, deletions and the session. Replay writes only under the agent's registration roots, with symlinks resolved. A failed upload is carried by the next increment; the last one is retried when the task ends, and the task fails as pi.changelog_incomplete if it still can't upload. Runs are serialized while a changelog is enabled
peer-agents registers a loopback-only MCP server (/mcp) whose peer_list and peer_send_message tools send A2A messages, one conversation per A2A context and peer
install copies the context into the task container, runs install.sh, writes the LiteLLM credentials through a heredoc into a 0600 agent.env, and starts start.sh

Registration env vars (agent-env a2a-agent put --env-var):

  • PI_A2A_MODEL_PARAMS: request fields agent-env reserves and won't forward as model_params (e.g. user for a key that needs project attribution).
  • PI_A2A_MODEL: the model used when agent-config sets none, as for a peer that other agents message directly.
  • PI_A2A_CHANGELOG_ROOTS: colon-separated changelog roots, default /workspace:/app. Enable requests may only narrow them.

Test plan

  • pytest tst/unit/agents/pi: 40 tests, offline, against a fake pi that replays JSON events and writes real session files. They run in the unit tier like Claude Code's. shipped_bundles_test, the release pin and clean-install wheel tests pass with the new folder; the full unit tier passes (9216 passed).
  • The image builds from src/agent_env/agents/agents/pi and serves its card.
  • The shipped agent deployed from the installed agents bundle on a local sandbox, against a LiteLLM proxy: the pi-smoke steps pass (deploy, prompt, response_contains 42) in 6.2s. Our proxy key needs project attribution, so that run deployed @local/agentenv-framework/agents/pi from a scratch task that sets PI_A2A_MODEL_PARAMS={"user": ...} in deploy_agent.env_vars. pi-smoke itself, which sets no attribution, reached pi and the proxy, and the proxy refused the call (pi.model_error, 400 no project attribution).
  • Greptile review findings addressed (5 rounds).
  • Direct container runs against a LiteLLM proxy with the real pi 1.1.0: tool use, session resume, skills, trajectory.
  • agent-env a2a-agent validate --sandbox local on agent v7. Passing: agent card, protocol, agent-config, mcp-config, skill-config, trajectory, snapshot (save, load, recall), changelog (enable, apply, marker round trip), and peer-agents (set/list, self-registered /mcp, relayed reply). Input types passing: text, png/jpeg/gif, HTTPS image, PDF, video.
  • Credential heredoc checked in a real container: mode 600, and a key containing $ and ' round-trips.
  • Codex review: approved after 4 rounds, with the install/v1 limitation below accepted.
  • install/v1 end to end in the validator. The agent installs into a bare ubuntu:24.04 container and serves its card. A prompt sent from inside the container reaches pi and the proxy. On a local sandbox, the validator can't reach the installed agent (see below). The review fixes after v7 are covered by unit tests, not by another validator run.

Known gaps

  • Install credentials in script text (accepted for this PR): core's install/v1 contract substitutes litellm_api_key into command text, so the key is part of the script the sandbox runs. The agent keeps it off the first line (the only part InstallAgentTaskStep logs), off process argv and env, and out of docker inspect. A sandbox that logs whole scripts still records it; the local sandbox does at DEBUG. Fixing that needs core: a stdin/secret channel for install params, or redacted script logging. Follow-up PR.
  • Install on a local sandbox: RunDockerContainerTaskStep publishes p:p, but the local sandbox's tunnel URL uses the allocated host port (sandbox.host_port(p)), so the validator polls a port nothing listens on. Core bug, follow-up PR.
  • COPY . . in put: put packs the build context from the Dockerfile's COPY sources and drops COPY . ., so the Dockerfile names its files explicitly. Core bug, follow-up PR.
  • Attribution for installed agents: an installed agent gets no registration env vars, so it has no PI_A2A_MODEL_PARAMS.
  • Audio input: audio probes time out after 120s. pi has no audio input and tries to install transcription tools. Audio isn't declared on the card.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The changes since the previous review appear safe to merge.

Summary

Adds the pi coding agent to the shipped agents bundle, with task runs, saved sessions, workspace snapshots, and peer-agent messaging. It also adds an install path and smoke task so the agent can be deployed and tried through the bundle.

  • Pi runs each task with its own context-linked conversation.
  • Pi sessions and workspace changes can be saved and replayed.
  • Pi can list peer agents and send them messages.
  • The pi agent is available in the shipped bundle and install flow.

Reviews (10) · Last reviewed commit: "refactor(agents): move the pi agent into..." · Reviewed by Greptile

@psinghal20
psinghal20 requested a review from a team as a code owner October 8, 2026 00:57
Comment thread plugins/agents/pi/pi_agent.py Outdated
Comment thread plugins/agents/pi/changelog.py Outdated
Comment thread plugins/agents/pi/changelog.py Outdated
Comment thread plugins/agents/pi/pi_agent.py Outdated
Comment thread plugins/agents/pi/peers.py Outdated
Comment thread src/agent_env/agents/agents/pi/pi_agent.py
Comment thread plugins/agents/pi/pi_agent.py Outdated
Comment thread plugins/agents/pi/changelog.py Outdated
Comment thread plugins/agents/pi/pi_agent.py Outdated
@earakely-scale

Copy link
Copy Markdown
Collaborator

🤖 Automated Claude routine — Env Pod PR Context Review. This is a bot, not Edgar Arakelyan; not a human review.

Context from the CI config rather than the diff.

plugins/ is a new top level, and no CI tier collects anything under it — so the 22 tests here only ever run by hand. Every suite names its paths explicitly: the unit tier is pytest tst/unit packages/agentenv-protocol/tests (.github/workflows/local-backends.yml:53), the integration tier is tst/integration (:101), the installer tier is tst/installer (:217), and make test is pytest tst/ -v (Makefile:68-69). [tool.pytest.ini_options] in pyproject.toml sets no testpaths, so there is no implicit fallback that would pick up plugins/agents/pi/tests/pi_agent_test.py either. main has no plugins/ directory at all, which is why no existing filter happens to cover it.

The installer tier's path filter does mention plugins (:189, src/agent_env/(plugins|config)/), but that is the agent_env.plugins module, not a repository directory, and the job it gates still runs only tst/installer.

Worth a glance at the sibling PR #115 for the convention this is diverging from: its new tests land in tst/unit/a2a_agent/ and packages/agentenv-protocol/tests/, both inside the collected paths. Either adding the directory to the unit tier's path list or homing the tests under tst/unit would put the fake-pi suite in front of CI; as it stands a later change to pi_agent.py or changelog.py can go green without running them.


Generated by Claude Code

Comment thread plugins/agents/pi/changelog.py Outdated
Comment thread plugins/agents/pi/peers.py Outdated
Comment thread plugins/agents/pi/pi_agent.py Outdated
Comment thread plugins/agents/pi/pi_agent.py Outdated
Comment thread src/agent_env/agents/agents/pi/changelog.py
Comment thread src/agent_env/agents/agents/pi/pi_agent.py
Comment thread plugins/agents/pi/changelog.py Outdated
Comment thread plugins/agents/pi/pi_agent.py Outdated
@psinghal20

Copy link
Copy Markdown
Collaborator Author

@greptile-apps re-review this PR

psinghal20 and others added 7 commits October 20, 2026 14:18
Wraps the pi coding agent (earendil-works/pi) with the agentenv_protocol
a2a_agent framework under plugins/agents/pi. Each task runs `pi --mode json`
against a per-task config dir pointing at the LiteLLM endpoint and the
registered MCP servers; a context maps to one pi session.

Implements agent-config, mcp-config, skill-config, trajectory, snapshot
(save/load and the changelog feature), peer-agents (a loopback MCP server
with peer_list and peer_send_message) and install/v1. The directory is a
self-contained build context: the protocol package comes from PyPI and
install.sh is shared by the image build and install/v1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stall

- Session ids are one-to-one with contexts: plain ids pass through, any
  other id maps to a prefix plus a sha256, and the two never overlap.
- install/v1 writes the LiteLLM credentials through a heredoc into a 0600
  agent.env, which start.sh sources, so they stay off the logged first
  line, process argv and docker inspect.
- Changelog replay writes only under the registration's roots
  (PI_A2A_CHANGELOG_ROOTS), with symlinks resolved. Enable requests may
  only narrow those roots and must give absolute paths.
- A failed increment upload no longer fails the tool call. Its changes are
  carried by the next increment, the last one is retried when the task ends,
  and the task fails as pi.changelog_incomplete if it still cannot upload.
  Runs are serialized while a changelog is enabled.
- Peer conversations are per A2A context and peer, and /mcp answers
  loopback clients only.
- stderr is drained into a bounded tail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- changelog: build each increment once and upload in order, so a failed
  upload is retried as built, with its own context and session, instead of
  being rebuilt under the next task's
- peers: bind /mcp to a per-run token pi sends as a header from its
  environment, instead of trusting a ?context= value any loopback caller sets
- snapshot load replaces the workspace's contents rather than extracting
  over files written after the snapshot
- attachments fetched from a URL are streamed to disk and capped at 256 MiB

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ounded; run plugin tests in CI

- snapshot load extracts the workspace archive into a staging directory
  first, so an archive that fails to extract leaves the workspace as it was
- snapshot load and changelog apply answer 409 while a task is running,
  and tasks wait while either restores the workspace
- changelog increments held for upload are capped at 256 MiB; past it they
  are dropped and capture stops, so every later task reports the changelog
  incomplete instead of the agent running out of memory
- correct the changelog module docstring to the ordered upload queue
- the unit tier (CI and make unit-test) now collects plugins/

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…apshot saves off restores

- the 256 MiB cap counts increments left after an upload attempt, so one
  large increment uploads when the store is up instead of stopping capture
- snapshot save takes the workspace lock, so it never archives a restore's
  staging directory

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne lock

save_snapshot read the session before taking the workspace lock, so a load
in between paired the old conversation with the restored files. Both are
now copied under the lock and uploaded after it is released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The agent's folder is now src/agent_env/agents/agents/pi, beside Claude Code, so it ships in the wheel
as @local/agentenv-framework/agents/pi with a pi-smoke task; its tests move to tst/unit/agents/pi and
run in the unit tier, so the plugins test path comes out of the Makefile, CI and AGENTS.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@psinghal20 psinghal20 changed the title feat(plugins): add the pi coding agent as an A2A agent feat(agents): add the pi coding agent to the shipped agents bundle Oct 20, 2026
@psinghal20

Copy link
Copy Markdown
Collaborator Author

@greptile-apps re-review the PR

@psinghal20
psinghal20 merged commit db0146b into main Oct 20, 2026
16 of 17 checks passed
@psinghal20
psinghal20 deleted the feat/pi-a2a-agent branch October 20, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants