Docs/pi agent integration#701
Conversation
Adds an end-to-end Pi Agent integration for TencentCloud#698: bilingual docs plus a runnable example project, following the layout and quality bar of the existing integration examples. - examples/pi-agent-integration/: Dockerfile (Node.js + Pi CLI on the cubesandbox-base image), run_pi_agent.py (headless one-shot run), resume_pi_agent.py (pause/resume session persistence via manual lifecycle), network_policy.py (default-deny egress + on-the-wire key injection), env_utils.py, bilingual README, .env.example, .gitignore, requirements.txt - docs/guide/integrations/pi-agent.md and docs/zh/guide/integrations/pi-agent.md - Register the guide in both integrations index tables Validation (no live cluster; dev machine is Apple Silicon macOS): - python3 -m py_compile examples/pi-agent-integration/*.py - env_utils helper checks (LLM host resolution, credential inject, vault env excludes secrets) - run/resume/network_policy --help parse cleanly - docs build (vitepress) succeeds - git diff --check clean Closes TencentCloud#698 Signed-off-by: chaojixinren <chaoji_xinren@163.com>
Replaces references to the outdated model version "claude-sonnet-4-20250514" with the updated version "claude-sonnet-4-6" in both English and Chinese documentation, as well as in example environment configurations and utility scripts. This ensures consistency across the integration guides and examples for the Pi Agent. - Updated model version in docs/guide/integrations/pi-agent.md - Updated model version in docs/zh/guide/integrations/pi-agent.md - Updated model version in examples/pi-agent-integration/.env.example - Updated model version in examples/pi-agent-integration/env_utils.py Signed-off-by: chaojixinren <chaoji_xinren@163.com>
pi_command() built the Pi command without --print, so Pi launched its interactive TUI and hung over the E2B exec channel instead of running headless. Verified against pi 0.80.3 that --print is the non-interactive flag and that --approve is a boolean (trust project-local files) with the prompt passed as the trailing positional argument. - env_utils.py: emit `pi --print --mode json ...` - docs/guide/integrations/pi-agent.md and zh: update command snippets and clarify --print / --approve semantics Signed-off-by: chaojixinren <chaoji_xinren@163.com>
b650faf to
46127c4
Compare
Addresses cubesandbox-bot review on TencentCloud#701: - network_policy.py + both integration guides: create the sandbox with allow_internet_access=False. With =True, unmatched traffic is forwarded at L3/L4 and bypasses CubeEgress, so the "default-deny" never held. With =False, CubeVS drops everything except the LLM host, which is auto-allowed from the L7 rules. - network_policy.py: remove the TypeError fallback that silently dropped allow_internet_access (it would re-enable full internet egress). - run_pi_agent.py: narrow the commands.run TypeError retry to the envs/env signature mismatch so unrelated TypeErrors are not masked. - env_utils.py: add explicit "format": "${SECRET}" on the anthropic-version inject entry instead of relying on the server default. Signed-off-by: chaojixinren <chaoji_xinren@163.com>
Verified end-to-end on a live CubeSandbox cluster. Fixes from the live run: - run_pi_agent.py: run commands as user="root" — /workspace and Pi's state dir (/root/.pi/agent) are root-owned; the default e2b exec user cannot write. - resume_pi_agent.py: sandbox.pause() can return a bool (success), not the resume handle; keep the original sandbox_id for connect(). - network_policy.py: use the native cubesandbox SDK with Rule/Match/Action/ Inject. The e2b SDK serialises network.rules as a map, which CubeAPI rejects (it expects the CubeEgress rule list); cubesandbox is the canonical path per docs/guide/security-proxy.md. - env_utils.py: provider_inject() returns CubeEgress Inject specs. - requirements.txt: add cubesandbox (used by network_policy.py). - docs: update egress snippet to the cubesandbox Rule/Inject form; fix anthropic-version to 2023-06-01. Signed-off-by: chaojixinren <chaoji_xinren@163.com>
Pi Agent Integration — Code Review SummaryOverall, this is a well-structured, thoroughly tested PR. The code is clean, the security model is thoughtfully documented, the docs are accurate and bilingual, and the example scripts are practical. Below are the findings worth flagging before merge. Security (1 issue, moderate)Self-modifying-instruction risk in Code quality / maintainability (1 issue)Fragile exception-message matching in Dockerfile (1 issue)Redundant packages — Documentation (1 issue)Missing Performance (minor)Extra sandbox round-trip for Positive highlights
|
…e, deps) Addresses cubesandbox-bot review on TencentCloud#701: - Extract run_command / ensure_success / sandbox_identifier / stream_writer into a shared _pi_common.py so run_pi_agent / resume_pi_agent / network_policy no longer import from one another (env_utils.py stays focused on .env/config). - env_utils.py: pi_command() gains an `approve` flag (default True) so callers can disable --approve (which trusts project-local AGENTS.md/CLAUDE.md) in high-security workflows. - requirements.txt: drop unused `rich`; README file trees add _pi_common.py. - docs: caveat that the direct (`envs=`) key may be cached by Pi under /root/.pi/agent and survive pause/resume; prefer the vault flavor. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: chaojixinren <chaoji_xinren@163.com>
…e, deps) Addresses cubesandbox-bot review on TencentCloud#701: - Extract run_command / ensure_success / sandbox_identifier / stream_writer into a shared _pi_common.py so run_pi_agent / resume_pi_agent / network_policy no longer import from one another (env_utils.py stays focused on .env/config). - env_utils.py: pi_command() gains an `approve` flag (default True) so callers can disable --approve (which trusts project-local AGENTS.md/CLAUDE.md) in high-security workflows. - requirements.txt: drop unused `rich`; README file trees add _pi_common.py. - docs: caveat that the direct (`envs=`) key may be cached by Pi under /root/.pi/agent and survive pause/resume; prefer the vault flavor. Signed-off-by: chaojixinren <chaoji_xinren@163.com>
a5c1dff to
939dedc
Compare
Parse the pi --mode json event stream and print assistant text, tool calls, and failures instead of raw JSONL. Add --raw / PI_STREAM_RAW to keep the raw stream, and document the behavior in the READMEs and integration guides. Signed-off-by: chaojixinren <chaoji_xinren@163.com>
004e50d to
1a4889b
Compare
network_policy.py failed end-to-end because Pi runs on Node.js, which ignores the system CA store and rejected CubeEgress's TLS-interception cert with a Connection error. Set NODE_EXTRA_CA_CERTS (override via PI_NODE_EXTRA_CA_CERTS) so Pi trusts the CubeEgress root CA; document it in the READMEs and guides. Verified on a live cluster: CubeEgress injects the real key on the wire (bare request -> HTTP 200) while the VM only holds a placeholder. Signed-off-by: chaojixinren <chaoji_xinren@163.com>
…fault, key scoping) env_utils.py: normalize PI_PROVIDER case so lookups/inject are case-insensitive; add PROVIDER_DEFAULT_MODEL and fail loudly for non-Anthropic providers without PI_MODEL instead of sending a Claude model name; build_pi_env forwards only the active provider's key(s), not every known secret. Dockerfile: install Pi in its own layer so PI_VERSION bumps don't rebuild the OS/Node layer. run_pi_agent.py / resume_pi_agent.py: document the open-egress key-exfiltration risk of the direct flavor and point to network_policy.py. Signed-off-by: chaojixinren <chaoji_xinren@163.com>
|
Thanks for your contribution |
Summary
Adds an end-to-end Pi Agent integration for #698: a bilingual guide plus a
runnable example project, following the layout and quality bar of the existing
integration examples.
What Changed
examples/pi-agent-integration/:Dockerfile— Node.js 24 +@earendil-works/pi-coding-agenton top ofghcr.io/tencentcloud/cubesandbox-base:2026.16; envd already listens on:49983.run_pi_agent.py— headless one-shot run (pi --versionpreflight → seedproject →
pi --print --mode json→ stream stdout, key injected per-command viaenvs=).resume_pi_agent.py— pause/resume across two turns; verifies/workspaceand Pi's state dir (
/root/.pi/agent) survive the snapshot. Manualtry/finallylifecycle (no context manager) so the pause is not undone.network_policy.py— default-deny egress + CubeEgressinjectso theprovider key rides the wire and never enters the VM.
env_utils.py, bilingualREADME.md/README_zh.md,.env.example,.gitignore,requirements.txt._template.mdfrontmatter,linked from both index tables:
docs/guide/integrations/pi-agent.mddocs/zh/guide/integrations/pi-agent.mdAcceptance Criteria (#698)
policy, snapshot-based session persistence. ✅
examples/with template definition + reproducibleflow + bilingual README. ✅
checkpoint/resume). ✅
docs/guide/integrationsfollowing the existing template. ✅Test Plan
python3 -m py_compile examples/pi-agent-integration/*.pyrun/resume/network_policy --helpparse cleanlycd docs && npm run docs:buildgit diff --checkcleandocker build --platform linux/amd64succeeds (~76s; image 551 MB)/healthreturns 204 (probe passes); envd 0.5.13; pi 0.80.3; node 24.18; git/python3/rg/jq presentLive CubeSandbox cluster run
Ran against a live single-node CubeSandbox cluster (a registered
pi-agent-cubetemplate, pi 0.80.3). The LLM provider was an Anthropic-compatible gateway
registered as a custom Pi provider (model
glm-5.2), because no nativeAnthropic key was available in the test environment.
run_pi_agent.py— sandbox created,pi --versionpreflight, seededproject, one-shot task drove
bash/writetool calls and wrote/workspace/result.md; exit 0. The runner's parsed transcript (assistanttext + tool calls) renders cleanly;
--rawstill dumps the JSONL stream.resume_pi_agent.py— turn 1 wrote/workspace/plan.md;sandbox.pause()then
Sandbox.connect()resumed;/workspace/plan.mdand Pi's state dir(
/root/.pi/agent) survived the snapshot; turn 2 read the plan and continued(wrote
current_time.py+progress.md,plan.mdleft intact); exit 0.network_policy.py— default-deny egress verified on-cluster: a non-LLMhost (
example.com) is blocked, andprintenvinside the sandbox shows theprovider key unset/placeholder (the real key never enters the VM).
network_policy.pyfull LLM call via CubeEgressinject— verified end-to-endon-cluster. A bare request (no auth header) is authenticated by the injected
key and the LLM returns HTTP 200, while the VM only ever holds a placeholder.
Pi (Node) additionally needs
NODE_EXTRA_CA_CERTSto trust the CubeEgressinterception CA (now set by the script).
Closes #698