Skip to content

Releases

pi-python v0.9.1

Choose a tag to compare

@github-actions github-actions released this 12 Nov 07:52
c84bb7c

This is a patch release. It has one fix: provider = "openai" now shows the thinking that a gateway streams as reasoning_content. Fixed has the details. The VS Code extension needs a new agent binary to get the fix, so it needs a new Release and a new VSIX. Changed has the new version numbers. Known issues says that the 0.9.0 list still holds.

Changed

  • New version numbers (all Python packages, TUI): pi-agent-core-lc, pi-agent-harness-lc and pi-agent-cli-lc go from 0.9.0 to 0.9.1. The three pin each other with ==, so install them at one version. Only pi-agent-core-lc has a code change. pi-agent-harness-lc and pi-agent-cli-lc change only their version and their pins, because PyPI skips a version that exists, and 0.9.0 of the two pins core ==0.9.0. The four extension packages need the new core (pi-agent-core-lc>=0.9.1, and pi-dynamic-workflows-py also pi-agent-harness-lc>=0.9.1) and get new versions, because the publish step skips a version that PyPI has already: pi-web-access-py, pi-goal-x-py and pi-dynamic-workflows-py go from 0.6.0 to 0.6.1, and pi-mcp-py from 0.4.0 to 0.4.1. They have no code change. zypi --version and the agentInfo of the agent show 0.9.1 (the TUI crates pi-pager-bin and pi-version, and tui/Cargo.lock, carry the same number). The TUI has no code change.

Fixed

  • provider = "openai" shows the thinking that a gateway streams (pi-agent-core): a gateway that serves a reasoning model (LiteLLM, vLLM, SiliconFlow, OpenRouter) puts the thinking in delta.reasoning_content (OpenRouter and newer vLLM: delta.reasoning). langchain_openai.ChatOpenAI does not read these fields, so the adapter never got any thinking and a client showed none: no thinking_delta event, no thinking block in the session file. ChatDeepSeek keeps them, but the zycode-agent binary (the VS Code extension, the registry archives) has no langchain_deepseek, and provider = "openai" with a base_url is the one way to reach a gateway there. Found in the VS Code extension: sessions of one model with provider = "deepseek" had thinking blocks, and sessions with provider = "openai" had none. The openai provider now builds a small subclass of ChatOpenAI (adapters/openai_reasoning.py) that puts the thinking of a streamed chunk into additional_kwargs["reasoning_content"], as ChatDeepSeek does, with the same two field names in the same order. A chunk with no such field is not touched, so api.openai.com does not change. The request does not change: the thinking is not sent back (provider = "deepseek" still does that on DeepSeek's own API), and a thinking block of an earlier turn is left out of the request as before. A session that now holds thinking blocks replays with provider = "openai" without error (test: the request of a history with thinking and a tool call). Tests: pi_agent_core/tests/test_openai_reasoning.py; with the change taken out, four of them fail, and the first turn of the stream test has a toolCall block and no thinking block, as in the session files. Verified with a streamed answer through the real ChatOpenAI class and a fake HTTP client. Not verified: against a live gateway, and in a built zycode-agent or a VSIX (the extension needs a new agent binary: a new Release and a new VSIX). A thinking that is not streamed (a call that is not astream) is not covered; the adapter always streams.

Known issues

The known issues of 0.9.0 still hold. This release changes none of them.

pi-python v0.9.0

Choose a tag to compare

@github-actions github-actions released this 11 Nov 10:40
6e96066

This release is about Auto. permission = "auto" is a real permission mode now: it runs the calls that are clearly in scope and asks about the rest. The Python agent runs it, and zypi offers it. A bash command that no rule decides goes to a model by default. Changed has the changes that you can see: permission = "auto" no longer means "no question", Auto sends your messages and that command to a model, and zypi keeps pasted images in a new folder. Fixed has two security fixes for holes that v0.8.0 has (git status at the start of a session, and the isolation of the workflow tool), and a fix for new installs that got agent-client-protocol 1.0.0 and did not start. Removed has more dead code of the TUI. Known issues says what does not work yet and what nobody tried by hand.

Added

  • The README tells how to run zycode as a subagent of DeepSeek Harness (docs): the new section "In DeepSeek Harness (as a subagent)" has the install command for @deepseek-ai/dsh-subagent-acp and @deepseek-ai/dsh-tool-subagent (alpha), the two config rows, the permission behaviour, and a warning: permission: allow in the DSH row answers zycode's project-trust question with "Trust and remember", so keep reject and set default_project_trust = "never" in the [extensions] table of an isolated PI_HOME. Verified end to end with a real model (OpenRouter deepseek/deepseek-v4.1-flash: one read task, one write task with permission = "auto"; DSH main model and zycode child both real) and with a mock model for the wiring. It was run with DSH 0.2.2-alpha.2 (headless profile) and pi-agent-cli-lc 0.7.0 on Linux: install, spawn, handshake, the result in DSH's completion notice, cwd, read and write through a scripted tool call, a denied and an allowed permission request, SIGTERM and SIGKILL of dsh (the child's tool process is reaped), the first-run message, and the trust hazard and its mitigation. Not tried: the [deepseek] extra, a long real task, a cold uvx download, DSH Web/Desktop, Windows and macOS. No code changes.
  • The README tells how to run zycode as a full session in DeepSeek Harness through a community plugin (docs): the new section "In DeepSeek Harness (full session, community plugin)" covers the third-party plugin @zaimokuza/dsh-acp-adapter, with an unofficial notice (DeepSeek has not reviewed it, it does not list zycode as tested). It has the install commands, the agent row (command: uvx, an isolated PI_HOME, loginHint), and notes on key, first run, permissions, project trust, models, resume, cancel and the MCP notice. Verified end to end with a real model (OpenRouter deepseek/deepseek-v4.1-flash for DSH's main model and for zycode) in the DSH Web app on Linux, with DSH 0.2.1-rc.4, adapter 0.2.1-rc.4.1 (the newest adapter, pinned to exactly that DSH; the installer refuses it on 0.2.1-rc.5) and pi-agent-cli-lc 0.8.0: a read task, a bash and a write request that were rejected and allowed on DSH's permission card, the project-trust question with its original options (nothing answered for you), a model switch in a session, resume after a restart of dsh, and Stop with a running bash command. The plugin does not offer a terminal login, so zycode gets no login there and the first run needs --setup in a shell. Not tried: other DSH versions, the Desktop app, Windows and macOS, session/load, zycode with pi-mcp-py. No code changes.
  • Auto is a real permission mode in the Python agent: it runs the calls that are clearly in scope and asks about the rest (pi-agent-cli): permission = "auto" in agent.toml, or the new mode item of a session (see below), turns on rules that judge each tool call before it runs. These run with no question: a tool that declares itself harmless (read, grep, find, ls, fetch_url, web_search; the same test as in ask), a write or edit inside the project folder (a new file, or a file in a git work tree), and a bash command that the parser shows to be read-only. These ask, and the question holds one fixed sentence that says why, for example bash (Auto: leaves the project folder) (it never holds command text or a file name): a path outside the project folder or on the protected list, a delete or an overwrite that git cannot undo, network use that sends or installs, secrets, a command that hides what it does (eval, $(...), python -c, here-documents), project code in a project that is not trusted, and a tool that declares nothing (a third-party tool, an MCP tool, workflow). Auto never refuses a call by itself: the outcomes are "run" and "ask", and an error, a timeout or a state that Auto cannot read is an "ask". A bash command that the rules cannot show to be safe goes to the model step (see the entry about it below), or asks the user when [auto] classifier = "rules". The [auto] table of the home agent.toml has classifier, model, timeout_seconds, extra_roots, protected, bash_timeout_seconds and bash_max_output_mb; agent.example.toml shows them. zypi offers Auto: its Shift+Tab ring and its settings page have ask, auto and always-approve (see the zypi change below). Design, decisions and test plan: docs/specs/2026-11-02-auto-mode-design.md.
  • Auto runs the calls of one message one by one, and checks the session before each call (pi-agent-cli, pi-agent-harness): the rules judge a call on the files as they are at that moment. The harness used to judge all calls of one assistant message first and run them after, so a write could change the files that the next call was judged on (a link that the first call made, for example). While a session is in Auto, the order is decide, run, decide, run: AgentHarness has a new attribute tool_execution and the methods get_tool and get_tools, and Auto sets the mode to sequential and puts it back when the session leaves Auto. A call that is judged while an earlier call of its message is still open asks. A workflow sub-agent whose calls pass a gate runs them one by one too. The rules also trust a context that they cannot check themselves, so Auto checks it when it starts and before each call: the project folder is absolute and exists; the home folder, PI_HOME, every extra_roots entry and every protected path are absolute; a tool is one of ours (bash, write, edit) by the identity of the tool object, not by its name, so a tool that an extension registers as bash always asks; PATH has no empty or relative entry; and the Bash tool runs bash. While a check fails, every call that does not declare itself harmless asks, and the user is told what is wrong when the session starts. A value of [auto] that Auto cannot use is told at the start of a session in any mode.
  • Auto asks before a write to a file that something else runs later (pi-agent-cli): .husky/*, .githooks/*, .claude/*, .cursor/*, .mcp.json, .vscode/tasks.json and .github/workflows/* are on the default protected list (auto_rules.DEFAULT_PROTECTED_GLOBS, one constant; a test covers each entry). Makefile, package.json and conftest.py are not on it: the agent changes them in ordinary work, and a question each time would make Auto useless. [auto] protected in the home agent.toml adds globs. An entry that is not text makes Auto ask about every call until the file is right, because a bad entry would otherwise loosen the list.
  • A bash call that Auto allowed has a time limit and an output limit (pi-agent-core, pi-agent-cli): 300 seconds and 64 MB by default ([auto] bash_timeout_seconds, bash_max_output_mb). The shorter of the limit and the model's own timeout wins. A call that the user allowed after a question has none: the user chose it. The core has a new BashLimits and create_bash_tool(limits_for_call=); without it the tool does not change.
  • Auto keeps a record, and /auto-log shows it (pi-agent-cli): each decision is a pi.auto_decision entry of the session file (tool call id, tool, outcome, who decided, reason code, rule id, milliseconds; no command text and no file name). The calls that a tool declares harmless are not recorded. /auto-log shows the counts and the last 20 decisions, and it exists in every session.
  • The mode belongs to the session, and a client can change it with the standard items (ACP, pi-agent-cli): session/new, load and resume return a mode config option (category mode; ask and auto) and modes, and a client changes the mode with session/set_config_option or session/set_mode. always-approve shows as the current value of a session that is in it, and a client cannot choose it with these items. The legacy items of the pager still work: _meta.autoMode and _meta.yoloMode in the session requests (a flag that is false or missing says nothing), and the notification pi/yolo_mode_changed, which has no session id and so moves every open session and sets the start mode of sessions that open later. A session that enters Auto gets a message that says what runs, what asks, and what Auto does not guard.
  • Auto is not a sandbox (docs): Auto guards what a call writes or runs. It does not guard what a call reads or sends. read, grep, find, ls, fetch_url and web_search run with no question for any path or URL, and so does a recursive or glob read inside bash (grep -r token ., rg --hidden -uuu, git grep, git log -p, cat *). Such a call can show a secret to the model, and fetch_url can send it to a server (the old gap of ask mode, kept as it is). The boundary is a sandbox (zypi --sandbox, a container, a VM). The root AGENTS.md (invariants 9b to 9d), packages/pi-agent-cli/AGENTS.md, README.md, docs/TUI-AND-CODE-AGENT.md, agent.example.toml, the entry message of Auto and the design record say so.
  • Auto asks a model about a bash command that no rule decides (pi-agent-cli): `auto_classi...
Read more

pi-python v0.8.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 10:31
a5d32d5

This release is about the agent as a program that needs no Python. The agent can now run as a frozen (PyInstaller) executable, and the new workflow agent-binaries.yml builds one executable for each of five platforms and attaches the archives to the GitHub Release of a tag. These archives are the base of the binary entry for the ACP registry (the entry is not submitted yet). pi-agent-cli-lc now installs the OpenAI-format provider (langchain-openai) by default, so a bare uvx pi-agent-cli-lc can call a model. Changed also has two changes of zypi that you can see: it refuses 21 flags that the Python agent does not back, and its settings page has eight rows fewer. Known issues says what does not work yet, and that includes a macOS finding about the workflow sandbox.

Added

  • The agent can run as a frozen executable (PyInstaller): three places in the code assumed a Python interpreter next to the agent. The workflow sandbox started its script process with sys.executable -I -S -B -X utf8 child.py, which a frozen program refuses. A frozen build now starts a program of its own for that, child.py frozen alone with the standard library and nothing else, from the folder frozen-child next to sandbox/host.py. The layers of the sandbox do not change. The older form of the terminal login (_meta["terminal-auth"]) named sys.executable -m pi_agent_cli --setup; a frozen build names its own program and --setup. A provider that a frozen build does not hold (anthropic, deepseek, any other) now fails with a text that says to set provider = "openai" and base_url, not with pip install ..., which cannot help there. --setup offers only the providers that the build holds. PI_SANDBOX_FROZEN_CHILD=<program> runs the whole sandbox test suite against the frozen program. Tests: pi_agent_core/tests/test_frozen_providers.py, packages/pi-dynamic-workflows/tests/test_sandbox_frozen.py and conftest.py, and additions to test_acp_auth_methods.py and test_setup_command.py.
  • A workflow builds the agent as one executable for each of five platforms (CI, packaging): .github/workflows/agent-binaries.yml builds the agent with PyInstaller (one file) on ubuntu-22.04, ubuntu-22.04-arm, macos-15, macos-15-intel and windows-2022. There is no windows-aarch64 build, because tiktoken has no wheel for it. Each program is tested on its own platform: a smoke test, 13 ACP contract tests against the program, and the sandbox tests against the frozen script process. The archives are named zycode-agent-<target>-<version>.tar.gz (.zip for Windows). The workflow starts after the Release workflow succeeds for a tag push (workflow_run) and uploads the five archives to that release with gh release upload --clobber. It stops when the tag is not v<version of pi-agent-cli-lc>. A pull request that touches the agent runs it as a dry run, and by hand (workflow_dispatch with a tag) it repairs a release whose upload failed. The frozen agent holds only the OpenAI-format provider; for Anthropic or DeepSeek use provider = "openai" with base_url, or the Python package. Not signed. Code: packaging/agent/. Design, release steps and trial results: docs/specs/2026-10-31-agent-binaries.md. Not tried yet: the publish job (it runs only after a tag), the rule of GitHub that a workflow_run workflow uses the file on the default branch, and the first start of a program in Zed or JetBrains.
  • The Landlock layer of pi-sandbox is tested on a Landlock kernel, and the flags and settings of zypi are measured against the Python agent (TUI, tests): the new test landlock_enforcement_e2e (workspace, read-only and strict profiles; the parent stays free; a child inherits the layer) passed on kernel 6.12 (Landlock ABI 6). The probes for flags and settings (scripts/tui_pty/) are the base of the two changes of zypi below. Test code only: zypi does not change by these. (#57, #58)

Changed

  • pi-agent-cli-lc depends on the OpenAI-format provider (langchain-openai): it asks for pi-agent-core-lc[openai]. A registry entry cannot add --with, so a bare uvx pi-agent-cli-lc had no provider and could not call a model. The other providers are extras of the package now: pi-agent-cli-lc[anthropic] and pi-agent-cli-lc[deepseek] (the extras of pi-agent-core-lc stay). Behaviour change: installing pi-agent-cli-lc now also installs langchain-openai and its dependencies (openai, tiktoken).

  • An interactive zypi refuses a flag that the Python agent does not back, and says why (TUI): an interactive session passes no flag to the agent, so 21 flags that came from the upstream project did nothing: --allow, --deny, --reasoning-effort, --worktree, --max-turns, --disable-web-search and 15 more. --deny was the worst case. The agent still asked about a call that matched the rule, and it never refused the call. Now zypi prints error: zypi did not start., names each of these flags with its reason, and exits with status 2 before it starts the agent. 19 of the flags are no longer in zypi --help. --rules and --system-prompt-override stay there with the note "-p only", because -p passes them to the agent. An interactive session reads .pi/SYSTEM.md and .pi/APPEND_SYSTEM.md instead. -p, the subcommands and the hidden compatibility flags do not change. Behaviour change: a script that starts an interactive zypi with one of these flags now fails with status 2.

  • The settings page does not offer eight settings that change nothing (TUI): remember_tool_approvals, default_selected_permission, default_model, toolset.ask_user_question.timeout_enabled, fork_secondary_model, prompt_suggestions, hunk_tracker_mode and auto_update steered the Rust runtime, or a feature that left with it. With the Python agent, a change on the page did nothing, or it did something other than the row said. default_model saved a key that the next start ignores. default_selected_permission showed "Always allow on all sessions" for a prompt that starts on "Allow once". The page has eight rows fewer, and the Models category is gone. The code and the keys of config.toml stay. A value that an earlier version saved is still read, and default_selected_permission = "reject" in config.toml still selects "Reject" in the first prompt of a session. Together with the change above, this ends the known issue of v0.7.0, "Some flags and settings have no effect", for everything that was measured.

  • The workflow sandbox on macOS has no kernel limit on memory or on the number of processes (docs, tests): measured in CI on macos-15 and macos-15-intel. The layers that work there are process, rlimit-core, rlimit-cpu, rlimit-nofile, rlimit-fsize and the audit hook. rlimit-as has no effect (the system does not enforce RLIMIT_AS: a 1 GiB allocation succeeds under a 256 MiB limit), and rlimit-nproc has no effect (a script can start child processes). So only the audit hook stands in the way there. Before this, the design said that macOS was not tested. README.md, AGENTS.md, packages/pi-dynamic-workflows/README.md and docs/specs/2026-10-01-workflow-sandbox-design.md say it now, and the sandbox tests check what each platform has. No code of the sandbox changes. With the default permission mode ask, every workflow call is asked about first.

  • The release workflow builds the macOS arm64 binary on macos-15 (CI): GitHub removes the macos-14 runner on 2026-11-02. Only the runs-on of build-tui-macos-arm changes. Not run: this job runs only for a tag, so the first run is the release of 0.8.0. (#69)

  • The TUI CI runs the tests of pi-sandbox, with enforcement required (CI): the new suite is in scripts/tui_baseline.toml (105 passed, 3 skipped). The job installs bubblewrap, lifts the AppArmor block on unprivileged user namespaces of ubuntu-24.04, and sets SANDBOX_E2E_REQUIRE_ENFORCEMENT=1. A runner without Landlock or a working bwrap now fails the job; before, the tests returned early and counted as passed. (#59)

  • New version numbers (all Python packages, TUI): pi-agent-core-lc, pi-agent-harness-lc and pi-agent-cli-lc go from 0.7.0 to 0.8.0. The three pin each other with ==, so install them at one version. The four extension packages need the new core (pi-agent-core-lc>=0.8.0) and get new versions, because the publish step skips a version that PyPI has already: pi-web-access-py, pi-goal-x-py and pi-dynamic-workflows-py go from 0.4.0 to 0.5.0, and pi-mcp-py from 0.2.0 to 0.3.0. zypi --version and the agentInfo of the agent show 0.8.0 (the TUI crates pi-pager-bin and pi-version, and tui/Cargo.lock, carry the same number).

Removed

  • More dead code in the TUI: 16 unused modules, the MCP loaders, and the folder-trust gate that guarded them (TUI): the call graph (scripts/tui_callgraph.py units) listed 16 modules that no live code refers to, and plan decision 10 named the MCP loaders of pi-shell and recent_dirs of pi-pager. All of it is gone. The modules are: in pi-hooks, dispatcher, result, runner, runner::command and runner::http (the hook dispatcher and the hook runners, 4,339 lines, and the crate's own integration test); in pi-shell, session::events, session::telemetry, session::unified_list, upload, upload::turn, auth::flow and config::reloader; and pi-workspace::publish, pi-tools::implementations::editor_infra, pi-mcp::wire and pi-agent::prompt::browser_verification. The compiler then found the code that only these called, and that is gone too: the plugin-registry and session-registry helpers of pi-shell, the consume side of the folder-trust gate (the cache of verdicts and project_scope_allowed; nothing calls the gate, because the loaders that it guarded are gone), the resolver of the [plugins] config, and the module...
Read more

pi-python v0.7.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 12:09
7cb9e23

This release is about the first run. pi-agent-cli-lc now has a console script with the name of the package, so uvx pi-agent-cli-lc works, and a user who has no model and no key can set both with python -m pi_agent_cli --setup. An ACP client that can run a terminal login (Zed) gets the same dialog as a login. Nobody has run that login inside Zed yet. Fixed has the benchmark runner that showed the verifier's tests to the agent, -p that exited 0 after a failed model call, and the extension API defects of audit batch 9. Changed has the new version numbers: the extension packages need the new core. Known issues says what does not work yet.

Added

  • A console script with the name of the package (pi-agent-cli): pi-agent-cli-lc starts the same function as pi-agent-cli, which stays. uvx <package> runs the executable that has the name of the package, and it stops with an error when the package has none. The package had only pi-agent-cli, so uvx pi-agent-cli-lc==0.6.0 printed "An executable named pi-agent-cli-lc is not provided by package pi-agent-cli-lc". The ACP registry starts a PyPI agent only in this form (uvx <package> <args>; it has no --from), so a registry entry needs this script. It is on PyPI from 0.7.0. uvx --from pi-agent-cli-lc pi-agent-cli works with every release. Test: packages/pi-agent-cli/tests/test_console_scripts.py.
  • The README tells how to start the agent in Zed as a custom agent (docs): the section "In Zed (custom agent)" has the agent_servers entry (uvx --from pi-agent-cli-lc), the place of the model and key settings, and the entry for a checkout. The command of the entry was run with the published 0.6.0 package: the agent answered initialize in an empty home. It was not run inside Zed.
  • --setup, and a terminal login for ACP clients (pi-agent-cli): a user who has no model and no key can now set both from a terminal. python -m pi_agent_cli --setup asks for the provider (OpenAI, Anthropic or DeepSeek), the model and the key. It writes a [model] table to agent.toml (a new file, or the end of a file that has no such table; the text that is there stays to the byte) and the line NAME=key to local.env (mode 0600 on POSIX). The key is read without echo and is never printed, logged or put in agent.toml. It stops, before the first question, for a file that is not TOML, for a [model] table that sets no provider, and for a home that has only the old config.toml. The agent also offers the dialog to the client as an authentication method (pi-setup, "Set up model and API key"). A client that announces auth.terminal (Zed) gets a method of type terminal. A client that announces only _meta["terminal-auth"] (older clients, the registry validator) gets a method with the command in _meta. Other clients, zypi included, get authMethods: [] as before. While the agent has no usable model, session/new answers auth_required (-32000) to a client that can run the login, and the agent reads agent.toml and local.env again at session/new, session/load and session/resume. session/load and session/resume never refuse. A key that --setup replaces needs a new agent process (load_local_env never overwrites a variable that is set). Not run inside Zed. A script that acts as the client ran a live agent process on Linux (initialize, session/new, the login command in a pseudo-terminal, session/new, authenticate). Design: docs/specs/2026-10-28-acp-terminal-auth-setup-design.md. Tests: packages/pi-agent-cli/tests/test_setup_command.py, test_acp_auth_methods.py.
  • The product site for zycode (web/, docs): a static site at https://zycode.dev, in English (/) and in Chinese (/zh/). It is not a Python package, and no file of a release contains it. web/README.md has the commands, the deploy, and the rules for what the site may claim (every claim has a source in the repository). The <head> of a page has the canonical link, the hreflang links, the Open Graph and Twitter tags, JSON-LD data (WebSite and SoftwareSourceCode) and the icons; robots.txt and sitemap.xml are generated. The new workflow web-ci.yml runs npm run check and npm run build for a PR that changes web/. A merge to main that changes web/ deploys the site by itself (Cloudflare Workers Builds, not GitHub Actions). The root README.md links to the site.

Changed

  • The release workflow builds the Linux binary on ubuntu-24.04, not on ubuntu-latest (CI): GitHub moves the label ubuntu-latest to Ubuntu 26. A binary that is built there can need a newer glibc than the 2.39 of Ubuntu 24.04, and then a machine with Ubuntu 24.04 could not start it. The job build-tui in release.yml now names the image, as TUI CI does (ADR6) and as build-tui-macos-arm does with macos-14. Nothing changes for the files of a release: the build of v0.6.0 ran on ubuntu-24.04 already. The other jobs of release.yml (tests, Python packages, publishing) still use ubuntu-latest; they ship no binary.

  • The documentation says that the Linux binary needs glibc 2.39 or newer (docs): docs/TUI-AND-CODE-AGENT.md, Option A. The binary of v0.6.0 has GLIBC_2.39 as its highest versioned symbol, so a system with an older glibc cannot start it (Ubuntu 22.04 has 2.35). Option B (build from source) works there.

  • The workflows use the Node 24 versions of three GitHub Actions (CI): actions/upload-artifact v4 to v6, actions/download-artifact v4 to v7, and actions/cache v4 to v5. GitHub removed Node 20 from its runners on 2026-09-23. It runs the old versions on Node 24 and prints a warning. The new versions change only the runtime; the inputs that the workflows use are the same. arduino/setup-protoc@v3 stays: it has no release for Node 24, and it works on Node 24 (the runs of 2026-10-26 passed). download-artifact runs only in the jobs that publish, so a dry run of release.yml does not test it.

  • A change of the Python agent alone runs one test target of the pager, not the whole TUI CI (CI): tui-ci.yml started for packages/pi-agent-cli/pi_agent_cli/** and packages/pi-agent-cli/tests/_tool_agent.py, because the end-to-end tests of the pager (python_agent_e2e) talk to the agent. But it runs ten suites and takes 18 to 35 minutes, and a change of the Python agent can change only that one target. The runs for the PR of --setup took 25 to 35 minutes, and the first two failed on a Rust test that the PR does not touch (fixed in #47). Now these two paths start the new workflow tui-e2e.yml, which runs that target alone. It restores the cache of the test job of tui-ci.yml and never saves one. tui-ci.yml runs for tui/**, scripts/tui_baseline.py, scripts/tui_baseline.toml and its own file, and it still includes the end-to-end tests. A change of both runs both workflows. Tests: scripts/tests/test_tui_baseline.py keeps the two workflows in line (paths, command, environment, install lines, cache key).

  • The cache of the TUI CI keeps its key when GitHub updates the runner image (CI): Swatinem/rust-cache puts the version of every Rust toolchain on the runner into the cache key. The image has its own stable, and the image of 2026-10-25 changed it from 1.99.0 to 1.99.1. The key changed, no cache matched, and the test job built everything again: 35 minutes, 31 of them for the build (18 minutes with the cache). Now the jobs of tui-ci.yml and tui-e2e.yml that install the pinned toolchain make it the default and uninstall the other toolchains before the cache step (the step Keep only the pinned Rust toolchain). So the key depends on the pinned toolchain, on the files of tui/ and on the CARGO_* and RUST_BACKTRACE variables of the workflow, and not on the image. The first run on main after this change builds everything once and saves the cache (only main saves). add-rust-environment-hash-key: false is not a substitute: it also removes the hash of Cargo.lock from the key, so the key never changes and the cache is saved only once. Tests: scripts/tests/test_tui_baseline.py keeps the step equal in every job and before the cache step, and keeps the hashed variables equal in the two workflows.

  • The PyPI pages link to the site (packaging): the [project.urls] of the seven pyproject.toml files have Website = "https://zycode.dev", and the README of pi-agent-cli-lc says that the agent is the one of zycode. The link shows on PyPI from this release.

  • New version numbers (all Python packages, TUI): pi-agent-core-lc, pi-agent-harness-lc and pi-agent-cli-lc go from 0.6.0 to 0.7.0. The three pin each other with ==, so install them at one version. zypi --version and the agentInfo of the agent show 0.7.0 (the Cargo.toml files of pi-pager-bin and pi-version and tui/Cargo.lock carry the version of pi-agent-cli-lc, and a test checks it). The extension packages are released with the core, so all four now require pi-agent-core-lc>=0.7.0, and pi-dynamic-workflows-py also requires pi-agent-harness-lc>=0.7.0. pi-web-access-py, pi-goal-x-py and pi-dynamic-workflows-py go from 0.3.0 to 0.4.0, and pi-mcp-py goes from 0.1.0 to 0.2.0. Their behaviour has not changed since 0.6.0 (pi-dynamic-workflows-py has a new comment in runtime.py); the new requirement and the Website link are the changes. The publish step skips a version that is on PyPI already, so a new requirement needs a new version number.

Fixed

  • The first turn without a model named a missing package (pi-agent-cli): with no [model] table the provider is mock. LangChain has no such provider, and in an install without the langchain package the turn failed with "Provider 'mock' needs init_chat_model from the 'langchain' package: pip install langchain". That text hid the real cause. Now the turn fails with "No model is set. Run the agent with --setup, or add a [mode...
Read more

pi-python v0.6.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 09:41
5f73e07

This release makes zypi ask the Python agent for sessions, and it adds an optional package that connects MCP servers. Changed says how --continue, --resume and --session-id work now, and that a session in which nobody typed has no file. pi-mcp-py (Added) connects the MCP servers that an editor such as Zed passes to the agent; without it, the agent still has no MCP client. Fixed has the Zed thread that did not open again after a restart. Removed lists the TUI code that read session files, and other dead code. Known issues says what does not work yet. Changed also has the new version numbers: the extension packages need the new core.

Added

  • Tools that find tests which share process-wide state, and a helper that keeps such a test apart (TUI tests): scripts/tui_envspy/ and in_own_process. All tests of one Rust test binary run as threads of one process, so they share the environment variables, the working directory and every static. The vendored tests were written for cargo nextest (one process per test), so their locks are partial, and a test that changes such state can break another test in some runs only. envspy.sh runs cargo test with an LD_PRELOAD shim over getenv, setenv, unsetenv, putenv and chdir, and analyze.py lists the tests that change a variable while another test runs, leave it changed, or read what another test has changed. stress.sh runs the lib tests of one package many times, each time in a random order (--shuffle-seed, so a failing run can be repeated) and with many test threads. It can also run a few named tests (a suspect pair, or a victim beside all tests of one module), and with ENVSPY_TAG it runs the tests through the spy. Linux only. 10 new pytest tests cover the analyzer. crate::test_util::in_own_process(|| { … }) in pi-pager runs the body of a test in a child process (the same test binary, --exact, one test thread), and the test fails when the child fails; 57 tests use it, directly or through with_rtl_bidi, with_theme_test_env and with_test_env, and 2 new tests check it. The README of scripts/tui_envspy/ has the rules for a test that changes process-wide state, and what the tools do not find. Numbers: section 3.4 of docs/baselines/tui.md.
  • Extensions can take over the MCP servers a client passes, tell the user something, and hold a turn back (pi-agent-core, pi-agent-harness, pi-agent-cli): the agent still has no MCP client, and it still does not read mcp.json. What a client passes in mcp_servers now goes to the harness as data: ClientMcpServer (name, transport, command, args, env, url, headers; its repr shows only name and transport, because the other fields can hold tokens), AgentHarness.set_client_mcp_servers() (before the extensions load), and ExtensionAPI.client_mcp_servers with claim_client_mcp_servers(names). Three general entry points come with it. ExtensionAPI.notify(text) shows one line to the user (a NoticeEvent, which is an agent message in ACP; the model does not see it, the session does not save it, and the agent holds it until the client knows the session). ExtensionAPI.register_cleanup(callback) is the public name of what the bridge already had. ExtensionAPI.add_turn_barrier(wait) makes the harness await wait before it builds the tool list of a turn; session/cancel, closing the session and opening it again end that wait in the CLI. initialize says that the agent takes http and sse MCP servers only when the pi-mcp extension entry point is installed. The extension that uses these entry points is pi-mcp-py (next entry). Design: docs/specs/2026-10-23-mcp-extension-design.md.
  • pi-mcp-py: an optional extension that connects the MCP servers an ACP client passes (new package packages/pi-mcp, version 0.1.0): an editor such as Zed passes its MCP servers in session/new. With this package installed, the agent connects them (stdio, Streamable HTTP and SSE) and gives their tools to the model. The core, the harness and the CLI still have no MCP client, and the agent still reads no mcp.json; the extension takes the servers from pi.client_mcp_servers and claims them, so the notice "its tools are not available" does not appear. Without the package, nothing changes. Tools: each tool is named mcp__<server>__<tool> (letters, digits, _ and -; at most 64 characters, cut with a hash; a repeated name gets _2, _3). The prefix is needed: a tool of an extension that has the name of a built-in tool replaces it, and an MCP tool named bash would take over bash. The permission mode ask asks about every MCP tool call unless the server declares the tool harmless (readOnlyHint, or neither destructive nor open-world), as for all tools. A result is text; text over 50 KB is cut with a note, a result with only structuredContent is sent as JSON text, and an MCP error result becomes an error tool result. One task for each server: the MCP SDK uses anyio cancel scopes, which must end in the task that began them. session_start starts the servers and returns at once; a turn waits at most 10 s for servers that are still starting (session/cancel ends the wait) and then goes on without them. A server that is slower sends one notice, and its tools join in a later turn. Limits (environment variables): PI_MCP_STARTUP_TIMEOUT (60 s) and PI_MCP_CALL_TIMEOUT (120 s); a call also ends when the user cancels the turn. When a server stops: the user gets one notice for each server and kind of event (did not start, stopped, cannot reconnect), and a good start gets none, so a thread without MCP trouble stays blank. The next tool call connects the server again, at most 3 times in a row (a call that gets an answer starts the count again). A call that was already sent when the server died is not repeated, because the server may have run it. /mcp lists the servers (name, transport, state, number of tools), and /mcp reconnect <name> connects one again with no limit. Secrets: env, headers, args and url hold tokens. Notices, /mcp, errors and logs show only the server name, the name of the executable, or the host; the values of env, the values of headers and the URL are masked in error text. Environment of a stdio server: the default list of the MCP SDK, the proxy, certificate, locale and time zone variables, and the env of the client. ${VAR} is not expanded (langchain-mcp-adapters would expand it from the environment of the agent, which has the LLM key, so the extension starts stdio servers itself), and the keys of the LLM provider are not passed. stderr of a server goes to <home>/logs/mcp/<name>.log, not to the stderr of the agent, where a full pipe would stop it. Servers on this machine are reached without the proxy of the system: httpx reads the proxy settings of Windows and does not skip loopback addresses. End: when the session closes, each server gets its stdin closed first, and then its process tree is stopped; a test checks that no process stays, on Windows and on Linux. Not supported: OAuth (it works only if the editor passes a token in headers; not verified), MCP resources, prompts, sampling and elicitation, a server shared by two sessions (each session starts its own), and a configuration file. A legacy SSE server whose POST fails ends a call only with the call timeout (the SDK hides the error). Limits of the package: it needs pi-agent-core-lc 0.6.0 or later; an older core makes it log a warning and do nothing. The Release workflow installs the package for its pre-release tests and builds it with the other packages, so the upload to PyPI has it (pip install pi-mcp-py). Tests: 192 in packages/pi-mcp/tests with real child processes (stdio, HTTP, SSE), the real AgentHarness, and the real PiAcpAgent over ACP, run on Windows and WSL. Design: docs/specs/2026-10-23-mcp-extension-design.md.

Changed

  • zypi --continue, --resume and --session-id ask the agent which session is meant (TUI): zypi used to look for the session in the session files of the old Rust agent. The Python agent writes another layout, so --resume <title> found no session, an unknown id failed only after the UI had started, a used --session-id left the UI open with Session creation failed: Invalid params, and --continue took the session that was created last (the first of the Known issues of 0.5.0). Now zypi starts the agent first and then asks it over ACP, with session/list (page after page) and session/load. It reads no session file for this. A session that does not exist ends the run before the event loop starts: the terminal is restored, the agent is stopped, the message is printed, and the exit status is 1. Behaviour changes: --continue and --resume without a value take the session of this directory with the latest activity (the time of its last write), not the one that was created last. --resume <id> finds the id in every directory and loads the session in the directory it belongs to. --resume <title> matches the title, which is the first message of the session, among the sessions of this directory, without regard to letter case and to spaces at the ends; two sessions with the same title are an error that lists their ids and last activity. --session-id <id> reads every page of the session list and refuses an id that any session has (Session ID <id> is already in use., exit status 1); that costs one pass through the list (scripts/session_list_bench.py prints it as walk all), and an agent that offers no session/list skips the check and refuses a used id itself. The lookup stops after 30 s, the limit of the connect (GROK_CONNECT_UI_TIMEOUT_SECS). A session in which nobody typed has no file now, so --continue cannot take it (see the next entry). Not solved, and left as it is: the agent lists its session directory a...
Read more

pi-python v0.5.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 07:34
be3f8a8

zypi no longer has an agent of its own. It draws the terminal screen and talks ACP to the Python agent (python -m pi_agent_cli), and that agent is now the only agent. Removed says what went with the Rust agent runtime. Known issues says what does not work yet. This release also has the Phase 6 and Phase 7 changes to the Python packages: project trust, a sandbox for workflow scripts, DeepSeek thinking with tools, and tool annotations.

Added

  • Project trust (Phase 7): a project's own extensions, saved workflows (.pi-python/workflows), .pi/SYSTEM.md, .pi/APPEND_SYSTEM.md and project-relative [skills].paths are now used only once the user has vouched for the project; before, opening a repository imported its extensions and turned its saved workflows into slash commands. [extensions] default_project_trust = "ask" (the default; or "never" / "always") has the ACP client answer a session/request_permission (Don't trust / Trust and remember; no allow_once, so a client that auto-approves tool calls cannot answer it) before anything of the project loads. The answer is saved in ~/.pi-python/agent/trust.json with a sha256: fingerprint of the files, so a git pull that changes them asks again. trusted_projects, trust_project_extensions = true, --trust-project-extensions and PI_TRUST_PROJECT_EXTENSIONS=1 also trust; headless (-p) runs never ask but honour a saved answer that still matches. Extensions read the answer as pi.project_trusted; library users pass AgentHarness(trust_project_extensions=True). Behaviour change: ACP sessions in such projects now ask (default_project_trust = "never" keeps the old silent skip). Not covered: a client may auto-approve the request, files changed after the session started are not re-checked, and AGENTS.md / CLAUDE.md are not gated (as in upstream pi). Design: Phase 7 spec, sections 4.4 and 16.
  • Workflow scripts run in a process of their own, under limits the operating system enforces (Phase 7): scripts used to be exec'd in the host's interpreter, where the narrowed __builtins__ had two known ways out and a while True froze the host's event loop. Each WorkflowRuntime.execute() now starts a child process with an empty environment; the host does everything with an effect (sub-agents, journal, logs, budget) over a JSON-lines pipe and treats the child as hostile. The kernel limits the child (rlimits on POSIX, plus no_new_privs and no fork on Linux; a Job Object and a lowered integrity level on Windows), and WorkflowRuntime(sandbox_limits=SandboxLimits(...)) sets them (an optional wall-clock deadline among them). What this is not: the audit hook is a speed bump, and what the kernel still allows differs per platform (a script can still read the files the user can read and use the network), so run the agent in a container if scripts cannot be trusted. Behaviour changes: values cross the process boundary as JSON, budget in a script is read-only, a run costs a process start (about 0.06 s on Linux, 0.14 s on Windows), Windows needs the default event loop, and execute() raises WorkflowScriptError for a script that raises and a SandboxError for one that is stopped. Design: docs/specs/2026-10-01-workflow-sandbox-design.md.
  • DeepSeek thinking works together with tools (Phase 6): with thinking on, DeepSeek's own API answers 400 to a request with tools unless earlier assistant messages bring their reasoning_content back, which ChatDeepSeek leaves out. The adapter now keeps it and sends it back on every assistant message (adapters/deepseek_replay.py), and it states whether to think (thinking: enabled | disabled, reasoning_effort) instead of leaving it to the API's default (on). Both apply to DeepSeek's own API only (no base_url, or one on deepseek.com), not to gateways serving DeepSeek models. Behaviour change: with the default thinking_level="off", requests now send thinking: disabled; code that relied on the old default to get reasoning blocks must set Model.reasoning=True and a thinking_level. Not verified against the live API (no key). Spec: Phase 6, section 5.5.
  • [model] reasoning in agent.toml (Phase 6): whether the configured model can reason (Model.reasoning); unset, any thinking_level other than off says it can. This is what makes thinking_level take effect through the CLI, which built every model with reasoning=False (the level was dropped on OpenAI and Anthropic). A model that rejects reasoning parameters needs reasoning = false.
  • Tools can declare what they do: ToolAnnotations (Phase 7): MCP's four hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint; a tool that declares nothing claims nothing). SimpleTool, CodingTool and ToolDefinition take annotations=, from_langchain_tool reads them from tool.metadata, and tool_call hooks receive them as ToolCallEvent.annotations. Built in, read, grep, find, ls, web_search and fetch_url declare themselves read-only, goal_update and goal_complete neither destructive nor open-world, and bash, edit, write and workflow declare nothing, on purpose. The hints are the tool author's word and are not verified; ask mode uses them (see Changed). Design: Phase 7 spec, section 12.
  • The TUI keeps the agent's stderr: zypi points its own stderr at /dev/null and the agent inherited it, so a Python traceback or warning from the agent went nowhere. It is now appended to <home>/logs/agent.stderr.log (mode 0600 on Unix, one --- agent started ... --- line per run, moved to agent.stderr.log.1 once it is over 1 MiB at the next start). zypi -p is unchanged: the agent's stderr stays on the terminal.
  • A sandbox that cannot be put in force says so (TUI): on a kernel without Landlock (Linux before 5.13, or with it disabled) zypi --sandbox <profile> used to start without the file and network limits and without a word; the only trace was an ApplyFailed line in sandbox-events.jsonl. It now prints a warning on stderr at start-up and shows sandbox:<profile> (not enforced) in the welcome page's top bar and the status bar, where the label of an applied profile is drawn. Where the sandbox is applied nothing changes.
  • session/list comes in pages (pi-agent-cli, pi-agent-harness): the agent answers with at most 50 sessions, newest first, and a nextCursor while more follow; the cursor is opaque, carries the position in it (the agent keeps nothing between requests, so it survives a restart) and anything the agent did not issue is invalid_params. The TUI keeps asking until the cursor is gone, so its session picker still lists everything. For library users JsonlSessionRepo.list_page(...) returns one page and JsonlSessionRepo.find(id) reads one session's header instead of the directory. With 1,000 sessions of 120 entries on Windows, the first answer took 2.0 s and a session/load of one of them 2.0 s; reading a file's first line no longer reads the file and a lookup by id no longer lists the directory, which makes them 0.11 s and 0.12 s (scripts/session_list_bench.py; numbers and method in docs/PLAN/archive/PLAN-RUST-AGENT-RUNTIME-REMOVAL-EXECUTION-LOG.md §10.11). updated_at is still the file's mtime and need not follow the list's order, which is by creation time.
  • The agent says which MCP servers a session ignored (pi-agent-cli): the agent connects to no MCP server (a Phase 4 non-goal), which departs from ACP's "an agent MUST support stdio servers"; session/new, load and resume used to drop the list without a word. Each session set up with a non-empty list now logs a warning and sends one agent message naming the servers (names only: env, headers, args and url hold tokens). zypi no longer forwards what it finds in .mcp.json, ~/.claude.json and Cursor's mcp.json, so there the message never shows; it is for other ACP clients, an editor that passes its own servers, say.
  • A client can choose the id of a new session, and the agent says which directory a session works in (pi-agent-cli, pi-agent-harness): zypi --session-id <uuid> has always sent the id in session/new's _meta.sessionId; the agent ignored it and picked its own, so the flag did nothing on the Python agent. It now becomes the session's id. It must be a UUID in any form uuid.UUID reads (kept as lower case with hyphens); anything else is invalid_params, because the id ends up in a file name. An id some session already has is refused with invalid_params, whatever directory that session belongs to, and two requests for the same id at once make one session. session/new, load and resume answer with _meta["pi/cwd"], the directory the session works in; for load and resume the one saved with the session wins over the cwd the client sent. For library users JsonlSessionRepo.has_session(id) says whether an id is taken and opens only the files whose names do not already say they belong to another session (find reads every header for an id nobody has). A free id costs the directory listing: 0.07 s at 1,000 sessions, 0.3 s at 5,000, on Windows and WSL2 alike (scripts/session_list_bench.py). Not yet in the TUI: zypi still checks for a used id in the old session layout, so it never sees the Python agent's sessions; the agent refuses the id and the TUI shows Session creation failed: Invalid params: {...} instead of exiting 1 with a message (scripts/tui_pty/resume_matrix.py, case 11), and nothing reads pi/cwd yet (execution log section 10.11, ADR1 PR 2).
  • A call graph of the TUI workspace (scripts/tui_callgraph.py): it reads the Rust source as text, so it needs no cargo and no network, and it gives the same answer on Windows, Linux and macOS. crates shows the dependency closure of the product crates (78 crates in the workspace, 74 in the closure; --without pi-shell shows what only `...
Read more

pi-python v0.4.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 02:16

Added

  • Phase 6 (git context): pi_agent_cli injects a bounded, read-only <git_status> block into the system prompt on every turn. Disable with [git] enabled = false or headless --no-git-context. Non-repos, timeouts, and git failures omit the section. MCP stays out of the product path; callers still adapt langchain-mcp-adapters tools with from_langchain_tool().
  • Provider matrix: opt-in live tests for OpenAI, Anthropic, DeepSeek, and SiliconFlow (pytest -m real_llm pi_agent_core/tests/test_provider_matrix.py). Manual workflow .github/workflows/provider-matrix.yml (workflow_dispatch only; missing secrets skip).
  • Phase 7 extension packages are built and published with the release: pi-web-access-py, pi-goal-x-py, pi-dynamic-workflows-py. CI and the pre-release test job install all three.

Changed

  • pi-agent-core-lc, pi-agent-harness-lc, and pi-agent-cli-lc are version 0.4.0.

pi-python v0.3.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 03:40

Added

  • TUI binary in GitHub Releases (beta): prebuilt zypi Linux x86_64 binary is now included in GitHub Releases alongside Python wheels. Download zypi-linux-x86_64 from the release assets page. Build from source for other platforms.
  • Phase 5 (Coding Agent prompt engine): pi-aligned build_system_prompt() / build_coding_agent_harness_system_prompt() in pi_agent_cli; tool prompt_snippet / prompt_guidelines contributions; AGENTS.md / CLAUDE.md / SYSTEM.md / APPEND_SYSTEM.md context files; <available_skills> XML format; bash PI_* env.
  • FrontierHarness 30-task evaluation: scripts/run_eval.py CLI with 21 Terminal-Bench + 9 DeepSWE industrial tasks; dual runtime (Windows local NTFS junctions + WSL2 Docker sandbox); v2ray proxy integration; full report in docs/benchmarks/FRONTIER-HARNESS-30-EVAL-REPORT.md.
  • TUI & Code-Agent guide: new docs/TUI-AND-CODE-AGENT.md covering installation, configuration, and usage for both zypi TUI and pi_agent_cli.
  • Release workflow: build-tui job builds the Rust TUI binary (cargo build --profile release-dist -p pi-pager-bin) and uploads zypi-linux-x86_64 to GitHub Releases.

Changed

  • TUI x.ai/ residual cleanup (P4P5-1 resolution): systematic purge of 680 x.ai/ references across 115 files in tui/crates/codegen/pi-pager/src/. New acp/vendor.rs centralises vendor-prefix constants and helpers; 4 inbound filter sites use vendor::is_vendor_ext_method() as defensive guards; doc comments, test fixtures, views/dispatch literals all scrubbed. Only vendor.rs (4 constants) and worktree_cmd/mod.rs (20, deferred) retain x.ai/ strings.
  • Test regression fixes: fixed 5 x.ai cleanup regressions where test data was over-renamed to pi/ while handler code still used original constant names (TITLE_IS_MANUAL_META_KEY, PI_SESSION_UPDATE_METHOD, is_vendor_meta_key).
  • Grok-specific tests marked #[ignore]: 62 tests for features removed from pi-python (grok slash commands, /loop scheduler, /share, dashboard, ~/.grok path, agent subcommand) annotated with #[ignore = "pi-python: grok-specific feature not supported"].
  • TUI test result: 8880 passed, 0 failed, 72 ignored.
  • TUI and code-agent marked as beta in README.
  • README restructured: added Status table, TUI install section, and updated roadmap.

pi-python v0.2.0

Choose a tag to compare

@github-actions github-actions released this 31 Aug 03:09

Added

  • Phase 4 P0–P4 (Coding Agent CLI): vendored grok-build TUI under tui/ (Apache-2.0, excluded from wheels); packages/pi-agent-cli standard ACP agent over AgentHarness (no x.ai/*); TUI spawn python -m pi_agent_cli, skip xAI login, drop vendor extension RPCs, home ~/.pi-python, product binary zypi. TUI Cargo crates renamed xai-* → pi-*, then P5 de-grok: pi-grok-* → pi-*, grok CLI subcommands removed, auth/prefetch startup skipped when auth_methods is empty. /new→session/new, /resume→session/list+session/load; @ is in-process directory listing; zypi -p / python -m pi_agent_cli -p is Python headless. P4: config.toml (model, permission, skills, [agent].command), coding system prompt + skills XML, Windows notes in docs/WINDOWS.md.
  • Pelican-on-a-bicycle foundation benchmark: pi_agent_cli.benchmarks.pelican, scripts/smoke_pelican.py, docs/benchmarks/PELCAN-BICYCLE.md — structural SVG smoke test for the pi TUI agent path.
  • PyPI: pi-agent-cli-lc included in the release workflow (tag v* builds and publishes core, harness, and cli wheels/sdists; Rust TUI excluded).

pi-python v0.1.0

Choose a tag to compare

@github-actions github-actions released this 05 Aug 06:10

Initial public release.

Added

pi-agent-core

  • Core runtime (Phase 1): Agent with steering/follow-up queues, abort, subscribe() event barrier; agent_loop with pi-compatible event protocol, parallel/sequential tool execution, terminate semantics.
  • LangChain adapter: StreamFn over astream() for OpenAI / Anthropic / DeepSeek / any init_chat_model provider; mock stream for tests (no API keys needed).
  • Production hardening (Phase 2/2.5):
    • Cross-provider message replay (transform_messages: tool-call id normalization, thinking downgrade, image stripping).
    • Usage & cost tracking with CostCalculator.
    • Thinking/reasoning: provider param mapping, streamed thinking_delta events, Anthropic signature replay, DeepSeek-style reasoning_content.
    • Stream-level retries with exponential backoff + jitter, Retry-After aware.
    • Runaway protection: max_turns / tool_timeout.
    • Guardrail hooks: before_llm_call (with ContextBudget), after_llm_call, on_agent_end.
    • Observability: on_payload / on_response hooks; run_id / turn_id on every event.
    • Granular stream events: text_start/end, thinking_start/end, toolcall_start/end.
    • Structured output: response_schema (Pydantic model or JSON schema).
    • Tool-result images: Anthropic native blocks, user-message fallback elsewhere.
    • OpenAI-compatible gateways via Model.base_url.
  • Tool ecosystem (P6):
    • 7 built-in coding tools: read, bash, edit, write, grep, find, ls.
    • Group factories: create_coding_tools() / create_read_only_tools().
    • LangChain BaseTool → AgentTool adapter (from_langchain_tool).

pi-agent-harness

  • Session tree (H1): SessionRepo with filesystem storage, uuid7 IDs, branch/fork semantics, message append/list.
  • AgentHarness runtime (H2): orchestration layer over Agent, queue rollback, abort aggregation, event-based idle wait.
  • Compaction & tree navigation (H3): token-based compaction with branch summaries, navigate_tree for branch exploration.
  • Skills, templates & env (H4): skill discovery, prompt templates, system prompt injection, LocalExecutionEnv for sandboxed execution.