pi-python-core 0.9.0__tar.gz → 0.10.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/PKG-INFO +12 -2
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/README.md +8 -1
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/README.zh-CN.md +8 -1
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/COVERAGE.md +1 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/verification.json +37 -25
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/API.md +87 -0
- pi_python_core-0.10.1/docs/CODING_AGENTS.md +176 -0
- pi_python_core-0.10.1/docs/MCP_INTERACTION.md +457 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/PLUGINS.md +168 -0
- pi_python_core-0.10.1/docs/PLUGIN_DEVELOPMENT.md +288 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/PROVIDERS.md +11 -2
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/zh/API.md +66 -0
- pi_python_core-0.10.1/docs/zh/CODING_AGENTS.md +140 -0
- pi_python_core-0.10.1/docs/zh/MCP_HOST_VERIFICATION.md +130 -0
- pi_python_core-0.10.1/docs/zh/MCP_INTERACTION.md +396 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/zh/PLUGINS.md +154 -0
- pi_python_core-0.10.1/docs/zh/PLUGIN_DEVELOPMENT.md +245 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/zh/PROVIDERS.md +11 -1
- pi_python_core-0.10.1/examples/mcp_interactive.py +160 -0
- pi_python_core-0.10.1/examples/mcp_interactive_server.py +73 -0
- pi_python_core-0.10.1/examples/memory_demo.py +62 -0
- pi_python_core-0.10.1/examples/plugins/memory/plugin.py +138 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/subagent.py +2 -7
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/pyproject.toml +3 -1
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/__init__.py +7 -1
- pi_python_core-0.10.1/src/pi_python/_mcp_host.py +221 -0
- pi_python_core-0.10.1/src/pi_python/_mcp_interaction.py +1000 -0
- pi_python_core-0.10.1/src/pi_python/_mcp_process.py +183 -0
- pi_python_core-0.10.1/src/pi_python/_mcp_sampling.py +280 -0
- pi_python_core-0.10.1/src/pi_python/_version.py +1 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/agent.py +19 -0
- pi_python_core-0.10.1/src/pi_python/features.py +45 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/function_tools.py +134 -99
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/loop.py +14 -11
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/mcp.py +136 -14
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/plugins/__init__.py +373 -31
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/plugins/_compose.py +15 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/plugins/_subagents.py +5 -15
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/providers/anthropic.py +3 -1
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/providers/completions.py +34 -9
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/providers/oauth.py +3 -10
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/providers/openai.py +3 -2
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/providers/transport.py +228 -126
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/run.py +28 -2
- pi_python_core-0.10.1/src/pi_python/sync.py +150 -0
- pi_python_core-0.10.1/src/pi_python/tasks.py +134 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/tools.py +58 -2
- pi_python_core-0.10.1/tests/servers/mcp_interactive_server.py +200 -0
- pi_python_core-0.10.1/tests/servers/mcp_process_server.py +86 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/servers/mcp_server.py +16 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_completions.py +74 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_contract_v3.py +50 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_examples.py +13 -1
- pi_python_core-0.10.1/tests/test_features.py +119 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_function_tools.py +161 -0
- pi_python_core-0.10.1/tests/test_lifecycle_contracts.py +278 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_mcp.py +69 -3
- pi_python_core-0.10.1/tests/test_mcp_delta.py +477 -0
- pi_python_core-0.10.1/tests/test_mcp_host.py +907 -0
- pi_python_core-0.10.1/tests/test_mcp_interaction.py +872 -0
- pi_python_core-0.10.1/tests/test_mcp_process.py +237 -0
- pi_python_core-0.10.1/tests/test_nested_agents.py +273 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_plugins.py +428 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_providers.py +48 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_sync.py +73 -0
- pi_python_core-0.10.1/tests/test_tasks.py +158 -0
- pi_python_core-0.10.1/tests/test_typeddict_annotations.py +62 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_websocket_continuation.py +142 -0
- pi_python_core-0.9.0/src/pi_python/_version.py +0 -1
- pi_python_core-0.9.0/src/pi_python/sync.py +0 -78
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/.gitignore +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/LICENSE +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/NOTICE +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/__init__.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/baseline.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/contracts/release-candidate.example.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/contracts/release-candidate.schema.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/contracts/upstream-baseline.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C01-text.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C02-tool.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C03-sequential.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C04-parallel.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C05-one-sequential.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C06-one-failure.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C07-unknown.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C08-prepare.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C09-before-error.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C09-block.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C09-replace.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C10-length.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C11-transform.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C12-system.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C13-steering.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C14-followup-all.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C14-followup-one.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C15-prepare.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C16-continue.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C16-end.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C16-mixed.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C16-terminate.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C19-abort-stream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C19-abort-tools.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/fixtures/C24-provider-error.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-cases.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/prompts/notes.txt +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/prompts/plan.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/prompts/review.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/prompts/sub/nested.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/prompts/summarize.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/.hidden/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/alpha/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/alpha/references/notes.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/beta/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/broken/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/delta/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/gamma/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/longdesc/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/loose.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/nested/group/epsilon/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/noname/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/plain.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/zeta/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/plugin-fixtures/skills/zeta/sub/eta/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-oauth.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-request-cache-long.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-request-cache-none.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-request-replay.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-request-tools-image.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-text.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-thinking.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/anthropic-tool.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/codex-request-tools-image.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/codex-text.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-compat-strict.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-deepseek.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-format-ant-ling.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-format-baseten.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-format-string-thinking.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-format-together.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-format-zai.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-midconvo-tools.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-moonshot-usage.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-openai-off.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-openrouter.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-qwen-length.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-reasoning-content.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-request-replay.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-text.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/completions-tool-stream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-incomplete.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-request-cache-long.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-request-cache-none.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-request-reasoning.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-request-replay.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-request-tools-image.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-text.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-thinking-backfill.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-thinking.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/openai-tool.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/proxy-text.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/proxy-thinking-tool.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-anthropic-collapse-budget.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-anthropic-native-tools.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-anthropic-oauth-effort.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-anthropic-redefinition.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-anthropic-server-fallback.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-anthropic-thinking-off.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-codex-tool-search.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-openai-additional-tools.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-openai-collapse.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-openai-explicit-cache-long.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-openai-explicit-cache-none.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/provider-fixtures/session-openai-removal.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/recovery-cases.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/release.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C01-text.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C01-text.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C02-tool.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C02-tool.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C03-sequential.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C03-sequential.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C04-parallel.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C04-parallel.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C05-one-sequential.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C05-one-sequential.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C06-one-failure.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C06-one-failure.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C07-unknown.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C07-unknown.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C08-prepare.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C08-prepare.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C09-before-error.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C09-before-error.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C09-block.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C09-block.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C09-replace.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C09-replace.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C10-length.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C10-length.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C11-transform.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C11-transform.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C12-system.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C12-system.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C13-steering.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C13-steering.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C14-followup-all.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C14-followup-all.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C14-followup-one.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C14-followup-one.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C15-prepare.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C15-prepare.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-continue.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-continue.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-end.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-end.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-mixed.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-mixed.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-terminate.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C16-terminate.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C19-abort-stream.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C19-abort-stream.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C19-abort-tools.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C19-abort-tools.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C24-provider-error.python.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/C24-provider-error.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/benchmark.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/bootstrap.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/candidate-live-noop.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/conformance.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/linux-3.14.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/linux-install-hash-repair.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-0.5-regression.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-0.5-session-claude.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-0.5-session-codex.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-claude-reasoning-replay.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-final-matrix.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-initial.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-loop-initial.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-providers.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-reasoning-replay.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-refresh.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-regression-0.4-deepseek.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-regression-0.4-first-run.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-regression-0.4.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-session-claude.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-session-codex.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-websocket-cached-recheck.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-websocket-cached.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/live-websocket-final.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/plugins.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/provider-conformance.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/recovery-conformance.upstream.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/runtime-dependencies.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/source-verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.1.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.1.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.1.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.1.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.1.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.2.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.2.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.2.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.2.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.2.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.3.0/against-0.4-fixtures.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.3.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.3.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.3.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.3.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.3.0/provider-conformance.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.3.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.4.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.4.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.4.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.4.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.4.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.5.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.5.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.5.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.5.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.5.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.6.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.6.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.6.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.6.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.6.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.7.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.7.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.7.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.7.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.7.0/linux-3.14.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.7.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.8.0/artifacts.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.8.0/linux-3.11.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.8.0/linux-3.12.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.8.0/linux-3.13.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.8.0/linux-3.14.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/v0.8.0/verification.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/results/websocket-conformance.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/runner.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/websocket-fixtures/codex-continuation-lost-state.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/compat/websocket-fixtures/codex-continuation-tool-loop.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/CONCEPTS.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/IMPLEMENTATION.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/history/IMPLEMENTATION-0.3.0.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/history/IMPLEMENTATION-0.4.0.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/history/IMPLEMENTATION-0.5.0.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/history/IMPLEMENTATION-0.6.0.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/history/IMPLEMENTATION-0.7.0.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/history/IMPLEMENTATION-0.8.0.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/docs/zh/CONCEPTS.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/in_memory.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/local_model.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/mcp_tools.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/plugin_demo.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/plugins/lab_tools/agents/reviewer.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/plugins/lab_tools/ops.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/plugins/lab_tools/plugin.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/plugins/lab_tools/prompts/dedup.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/plugins/lab_tools/skills/dedup-window/SKILL.md +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/provider_chat.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/quickstart.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/recovery.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/examples/save_restore.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/cancellation.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/data/models.json +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/errors.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/estimate.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/events.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/hooks.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/limits.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/lowlevel.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/messages.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/models.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/plugins/_frontmatter.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/plugins/_resources.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/provider.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/providers/__init__.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/providers/common.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/proxy.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/py.typed +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/queues.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/recovery.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/stream.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/testing.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/src/pi_python/transcript.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_conformance.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_control.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_extended_core.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_loop.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_messages.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_models.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_oauth.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_plugin_conformance.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_recovery.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_recovery_conformance.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_recovery_helpers.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_release.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_session_changes.py +0 -0
- {pi_python_core-0.9.0 → pi_python_core-0.10.1}/tests/test_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pi-python-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.1
|
|
4
4
|
Summary: An embeddable asyncio agent core with opt-in Claude and OpenAI providers
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -23,6 +23,9 @@ Requires-Dist: jsonschema<5,>=4.18
|
|
|
23
23
|
Requires-Dist: websockets>=14.2
|
|
24
24
|
Provides-Extra: mcp
|
|
25
25
|
Requires-Dist: mcp>=1.10; extra == 'mcp'
|
|
26
|
+
Provides-Extra: mcp-interactive
|
|
27
|
+
Requires-Dist: jsonschema[format-nongpl]<5,>=4.18; extra == 'mcp-interactive'
|
|
28
|
+
Requires-Dist: mcp<3,>=2.3; extra == 'mcp-interactive'
|
|
26
29
|
Provides-Extra: oauth
|
|
27
30
|
Requires-Dist: pyjwt[crypto]<3,>=2.8; extra == 'oauth'
|
|
28
31
|
Provides-Extra: providers
|
|
@@ -37,6 +40,9 @@ An embeddable Python agent core, ported from [Pi](https://github.com/earendil-wo
|
|
|
37
40
|
|
|
38
41
|
`pi-agent-core` on PyPI is a separate project that ports an older version from pi-mono (early 2026). This library follows the behavior of Pi v1.0.0, compared case by case with the upstream code's actual output, and ships its own connectors for Claude, OpenAI, DeepSeek and local models, with no model SDK required.
|
|
39
42
|
|
|
43
|
+
**Using a coding agent?** Start with the [library integration guide](docs/CODING_AGENTS.md).
|
|
44
|
+
To build an extension, follow the [plugin development workflow and complete example](docs/PLUGIN_DEVELOPMENT.md).
|
|
45
|
+
|
|
40
46
|
## Install
|
|
41
47
|
|
|
42
48
|
Python 3.11–3.14 (including free-threaded 3.14t) and PyPy 3.11. No Node.js or model SDK needed.
|
|
@@ -53,6 +59,7 @@ You install `pi-python-core` and import `pi_python`.
|
|
|
53
59
|
| `[oauth]` | Verifies the identity token when you sign in with a ChatGPT account (`openai-chatgpt`); it brings in the compiled `cryptography` package. Claude subscription and Codex sign-in do not need it |
|
|
54
60
|
| `[providers]` | Same as `[oauth]`; keeps install commands from 0.8.1 and earlier working |
|
|
55
61
|
| `[mcp]` | Gives the agent the tools of MCP servers, including those a plugin declares |
|
|
62
|
+
| `[mcp-interactive]` | Lets MCP services request host model calls and user forms; includes sampling profiles, metering and retries. See [MCP interaction](docs/MCP_INTERACTION.md) |
|
|
56
63
|
|
|
57
64
|
Dependencies are version ranges rather than pins, so the package fits into most existing environments.
|
|
58
65
|
|
|
@@ -92,6 +99,7 @@ To try it offline first: `python examples/quickstart.py`.
|
|
|
92
99
|
| Use MCP tools | `async with connect_stdio(...) as tools`, or `connect_http(url)` for a remote server | [mcp_tools](examples/mcp_tools.py) |
|
|
93
100
|
| Let one agent call another | Wrap the sub-agent as a tool; cancellation propagates down. Plugins can also define subagents in Markdown | [subagent](examples/subagent.py) |
|
|
94
101
|
| Package and share capabilities | A plugin bundles tools, instructions, hooks, skills, prompt templates, subagents and MCP servers; load it by name or path with `load_plugins` and build the agent with `plugins.agent(...)` | [plugin_demo](examples/plugin_demo.py) |
|
|
102
|
+
| Remember across conversations | Not built in, as in Pi's core; an example plugin saves facts to a file and puts them in the system prompt, ready to copy and adapt | [memory_demo](examples/memory_demo.py) |
|
|
95
103
|
| Intervene mid-run | `steer` injects guidance, `follow_up` queues the next task, `abort` cancels at any time (callable from any thread) | |
|
|
96
104
|
| Context full, service errors | `is_context_overflow` and `is_retryable_error` tell you why, `continue_run()` retries, `transform_context` compacts | [recovery](examples/recovery.py) |
|
|
97
105
|
| Save and restore conversations | `encode_messages` / `decode_messages`; your application decides where to store them | [save_restore](examples/save_restore.py) |
|
|
@@ -107,6 +115,8 @@ A few differences are deliberate, such as strict tool-argument validation withou
|
|
|
107
115
|
|
|
108
116
|
## Documentation
|
|
109
117
|
|
|
118
|
+
- [Coding agents: integrate the library, run an offline example, and verify behavior](docs/CODING_AGENTS.md)
|
|
119
|
+
- [Plugin development: scaffold, readiness checks, packaging, and installed verification](docs/PLUGIN_DEVELOPMENT.md)
|
|
110
120
|
- [Concepts on one page: five ideas and one turn](docs/CONCEPTS.md)
|
|
111
121
|
- [Public API](docs/API.md)
|
|
112
122
|
- [Model connectors, subscription sign-in and local models](docs/PROVIDERS.md)
|
|
@@ -118,7 +128,7 @@ A few differences are deliberate, such as strict tool-argument validation withou
|
|
|
118
128
|
## Development
|
|
119
129
|
|
|
120
130
|
```bash
|
|
121
|
-
uv sync --locked --extra oauth --extra mcp
|
|
131
|
+
uv sync --locked --extra oauth --extra mcp-interactive
|
|
122
132
|
uv run pytest -q
|
|
123
133
|
uv run python scripts/verify.py # every check, including the comparison with upstream (needs Node)
|
|
124
134
|
```
|
|
@@ -6,6 +6,9 @@ An embeddable Python agent core, ported from [Pi](https://github.com/earendil-wo
|
|
|
6
6
|
|
|
7
7
|
`pi-agent-core` on PyPI is a separate project that ports an older version from pi-mono (early 2026). This library follows the behavior of Pi v1.0.0, compared case by case with the upstream code's actual output, and ships its own connectors for Claude, OpenAI, DeepSeek and local models, with no model SDK required.
|
|
8
8
|
|
|
9
|
+
**Using a coding agent?** Start with the [library integration guide](docs/CODING_AGENTS.md).
|
|
10
|
+
To build an extension, follow the [plugin development workflow and complete example](docs/PLUGIN_DEVELOPMENT.md).
|
|
11
|
+
|
|
9
12
|
## Install
|
|
10
13
|
|
|
11
14
|
Python 3.11–3.14 (including free-threaded 3.14t) and PyPy 3.11. No Node.js or model SDK needed.
|
|
@@ -22,6 +25,7 @@ You install `pi-python-core` and import `pi_python`.
|
|
|
22
25
|
| `[oauth]` | Verifies the identity token when you sign in with a ChatGPT account (`openai-chatgpt`); it brings in the compiled `cryptography` package. Claude subscription and Codex sign-in do not need it |
|
|
23
26
|
| `[providers]` | Same as `[oauth]`; keeps install commands from 0.8.1 and earlier working |
|
|
24
27
|
| `[mcp]` | Gives the agent the tools of MCP servers, including those a plugin declares |
|
|
28
|
+
| `[mcp-interactive]` | Lets MCP services request host model calls and user forms; includes sampling profiles, metering and retries. See [MCP interaction](docs/MCP_INTERACTION.md) |
|
|
25
29
|
|
|
26
30
|
Dependencies are version ranges rather than pins, so the package fits into most existing environments.
|
|
27
31
|
|
|
@@ -61,6 +65,7 @@ To try it offline first: `python examples/quickstart.py`.
|
|
|
61
65
|
| Use MCP tools | `async with connect_stdio(...) as tools`, or `connect_http(url)` for a remote server | [mcp_tools](examples/mcp_tools.py) |
|
|
62
66
|
| Let one agent call another | Wrap the sub-agent as a tool; cancellation propagates down. Plugins can also define subagents in Markdown | [subagent](examples/subagent.py) |
|
|
63
67
|
| Package and share capabilities | A plugin bundles tools, instructions, hooks, skills, prompt templates, subagents and MCP servers; load it by name or path with `load_plugins` and build the agent with `plugins.agent(...)` | [plugin_demo](examples/plugin_demo.py) |
|
|
68
|
+
| Remember across conversations | Not built in, as in Pi's core; an example plugin saves facts to a file and puts them in the system prompt, ready to copy and adapt | [memory_demo](examples/memory_demo.py) |
|
|
64
69
|
| Intervene mid-run | `steer` injects guidance, `follow_up` queues the next task, `abort` cancels at any time (callable from any thread) | |
|
|
65
70
|
| Context full, service errors | `is_context_overflow` and `is_retryable_error` tell you why, `continue_run()` retries, `transform_context` compacts | [recovery](examples/recovery.py) |
|
|
66
71
|
| Save and restore conversations | `encode_messages` / `decode_messages`; your application decides where to store them | [save_restore](examples/save_restore.py) |
|
|
@@ -76,6 +81,8 @@ A few differences are deliberate, such as strict tool-argument validation withou
|
|
|
76
81
|
|
|
77
82
|
## Documentation
|
|
78
83
|
|
|
84
|
+
- [Coding agents: integrate the library, run an offline example, and verify behavior](docs/CODING_AGENTS.md)
|
|
85
|
+
- [Plugin development: scaffold, readiness checks, packaging, and installed verification](docs/PLUGIN_DEVELOPMENT.md)
|
|
79
86
|
- [Concepts on one page: five ideas and one turn](docs/CONCEPTS.md)
|
|
80
87
|
- [Public API](docs/API.md)
|
|
81
88
|
- [Model connectors, subscription sign-in and local models](docs/PROVIDERS.md)
|
|
@@ -87,7 +94,7 @@ A few differences are deliberate, such as strict tool-argument validation withou
|
|
|
87
94
|
## Development
|
|
88
95
|
|
|
89
96
|
```bash
|
|
90
|
-
uv sync --locked --extra oauth --extra mcp
|
|
97
|
+
uv sync --locked --extra oauth --extra mcp-interactive
|
|
91
98
|
uv run pytest -q
|
|
92
99
|
uv run python scripts/verify.py # every check, including the comparison with upstream (needs Node)
|
|
93
100
|
```
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
PyPI 上的 `pi-agent-core` 是另一个独立项目,移植的是 2026 年初 pi-mono 中的旧版本。本库对照 Pi v1.0.0 的行为,与上游的实际运行结果逐组比较;并自带 Claude、OpenAI、DeepSeek 和本地模型的接入,不需要安装任何模型 SDK。
|
|
8
8
|
|
|
9
|
+
**使用 coding agent 开发?** 先读 [library 接入指南](docs/zh/CODING_AGENTS.md)。
|
|
10
|
+
需要扩展能力时,按 [插件开发流程与完整示例](docs/zh/PLUGIN_DEVELOPMENT.md) 实现、打包和验证。
|
|
11
|
+
|
|
9
12
|
## 安装
|
|
10
13
|
|
|
11
14
|
支持 Python 3.11–3.14(包括无 GIL 的 3.14t)和 PyPy 3.11,不需要 Node 或任何模型 SDK。
|
|
@@ -22,6 +25,7 @@ pip install pi-python-core # 或 uv add pi-python-core
|
|
|
22
25
|
| `[oauth]` | 用 ChatGPT 账号登录(`openai-chatgpt`)时校验身份令牌,会带进需要编译的 `cryptography`。Claude 订阅和 Codex 登录不需要它 |
|
|
23
26
|
| `[providers]` | 与 `[oauth]` 相同,让 0.8.1 及以前的安装命令仍然可用 |
|
|
24
27
|
| `[mcp]` | 把 MCP 服务器的工具交给 agent,插件声明的 MCP 服务器也需要它 |
|
|
28
|
+
| `[mcp-interactive]` | 允许 MCP 服务请求宿主模型调用及用户表单,支持配置选择、计量与重试。见 [MCP 交互](docs/zh/MCP_INTERACTION.md) |
|
|
25
29
|
|
|
26
30
|
依赖写的是版本范围而不是固定版本,能和大多数已有环境共存。
|
|
27
31
|
|
|
@@ -61,6 +65,7 @@ agent = Agent(provider=llm, model=llm.model("qwen3:8b", context_window=40960), t
|
|
|
61
65
|
| 用 MCP 工具 | `async with connect_stdio(...) as tools`;远程服务器用 `connect_http(url)` | [mcp_tools](examples/mcp_tools.py) |
|
|
62
66
|
| 让一个 agent 调用另一个 | 把子 agent 包成工具,取消会一路传下去;插件也可以用 Markdown 定义子 agent | [subagent](examples/subagent.py) |
|
|
63
67
|
| 打包和分享能力 | 插件把工具、说明、钩子、技能、提示模板、子 agent 和 MCP 服务器打成一组;用 `load_plugins` 按名字或路径加载,再用 `plugins.agent(...)` 构造 agent | [plugin_demo](examples/plugin_demo.py) |
|
|
68
|
+
| 跨对话记住信息 | 与 Pi 的核心一样不内置;示例插件把事实存进文件,再放进系统提示,可以复制后修改 | [memory_demo](examples/memory_demo.py) |
|
|
64
69
|
| 中途干预 | `steer` 插入指导,`follow_up` 排队后续任务,`abort` 随时取消(任何线程都可以调用) | |
|
|
65
70
|
| 上下文满了、服务出错 | `is_context_overflow`、`is_retryable_error` 判断原因,`continue_run()` 重试,`transform_context` 压缩 | [recovery](examples/recovery.py) |
|
|
66
71
|
| 保存与恢复对话 | `encode_messages` / `decode_messages`,应用决定存在哪里 | [save_restore](examples/save_restore.py) |
|
|
@@ -76,6 +81,8 @@ agent = Agent(provider=llm, model=llm.model("qwen3:8b", context_window=40960), t
|
|
|
76
81
|
|
|
77
82
|
## 文档
|
|
78
83
|
|
|
84
|
+
- [Coding agents:接入 library、运行离线示例、验证行为](docs/zh/CODING_AGENTS.md)
|
|
85
|
+
- [插件开发:目录结构、就绪检查、打包与安装验证](docs/zh/PLUGIN_DEVELOPMENT.md)
|
|
79
86
|
- [一页看懂:五个概念和一轮的流程](docs/zh/CONCEPTS.md)
|
|
80
87
|
- [公开 API](docs/zh/API.md)
|
|
81
88
|
- [模型接入、订阅登录与本地模型](docs/zh/PROVIDERS.md)
|
|
@@ -87,7 +94,7 @@ agent = Agent(provider=llm, model=llm.model("qwen3:8b", context_window=40960), t
|
|
|
87
94
|
## 开发
|
|
88
95
|
|
|
89
96
|
```bash
|
|
90
|
-
uv sync --locked --extra oauth --extra mcp
|
|
97
|
+
uv sync --locked --extra oauth --extra mcp-interactive
|
|
91
98
|
uv run pytest -q
|
|
92
99
|
uv run python scripts/verify.py # 全部检查,含与上游的差分(需要 Node)
|
|
93
100
|
```
|
|
@@ -133,6 +133,7 @@ CI 第一次在 GitHub 上运行,Linux 和 macOS 全部通过,另外发现
|
|
|
133
133
|
- 上游由命令行程序发现和加载 package(`pi install`、`settings.json`、项目信任)。本库没有应用程序,由应用代码指定加载哪些插件,不自动发现。已安装的插件通过 entry point 组 `pi_python.plugins` 注册,对应 `pi install npm:...`。
|
|
134
134
|
- 插件代码是 Python 的 `setup(api)`,对应 Pi 扩展的工厂函数。`PluginAPI` 只保留与界面无关的部分(工具、系统提示、钩子、事件、MCP),没有命令、快捷键、渲染器等终端界面接口;另加了 `service`(应用提供的对象)、`options`(按插件分开的设置)、`add_check`(自检)和 `on_close`。
|
|
135
135
|
- 插件处理函数出错时交给 `on_error`,默认写日志;上游交给 `emitError`,显示在界面上。`before_tool_call` 与上游一样,出错时让这次调用失败。应用自己的钩子保持核心行为,不做隔离。
|
|
136
|
+
- 插件注册处理函数时检查它能否接收该钩子传入的位置参数(`subscribe` 为事件一个参数,`add_check` 和 `on_close` 没有参数),不能就报 `ConfigurationError`,加载停止(0.10.1 加入)。上游没有这一步:TypeScript 在编译时检查类型,JavaScript 调用时多出的参数会被忽略。Python 会在每次调用时抛出 `TypeError`,插件处理函数的错误又只写日志,不检查的话这样的处理函数会悄悄失效。应用自己的钩子不做这项检查。
|
|
136
137
|
- 模型用 `read_skill` 工具读取技能(上游让模型用通用的 `read` 工具)。它只能读技能目录里的文件,单个文件不超过 256 KiB。
|
|
137
138
|
- 子 agent 在同一进程、同一事件循环里运行(上游为每个子 agent 启动一个 pi 子进程),使用主 agent 的 Provider 和合并后的全部钩子。上游的子进程会加载同样的扩展,所以插件的处理函数同样作用于子 agent,这一点与上游一致。不指定模型时,子 agent 用调用那一刻主 agent 的模型(上游从设置里取默认模型)。没有上游的 `agentScope`、`cwd` 参数和项目级 agent 的确认步骤。
|
|
138
139
|
- MCP:工具名为 `mcp__<服务器>__<工具>`,但工具名里的 `-` 保留(上游换成 `_`)。字符串里只展开 `${PLUGIN_ROOT}`、`${PYTHON}` 和环境变量,前两个是本库新增;不支持 `!命令`。不支持 OAuth、`exposure` / `toolExposure` 和单次请求超时,这些设置会被忽略并给出警告。新增 `pi_python.mcp.connect_http`,连接 streamable HTTP 服务器;在 MCP SDK 1.10、1.30 和 2.3 上测过。
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
"--extra",
|
|
16
16
|
"providers",
|
|
17
17
|
"--extra",
|
|
18
|
-
"mcp"
|
|
18
|
+
"mcp-interactive"
|
|
19
19
|
],
|
|
20
20
|
"exit_code": 0,
|
|
21
|
-
"seconds": 0.
|
|
21
|
+
"seconds": 0.02251266618259251,
|
|
22
22
|
"stdout": "",
|
|
23
|
-
"stderr": "Resolved
|
|
23
|
+
"stderr": "Resolved 60 packages in 2ms\nAudited 57 packages in 8ms\n"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"command": [
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"scripts"
|
|
36
36
|
],
|
|
37
37
|
"exit_code": 0,
|
|
38
|
-
"seconds": 0.
|
|
38
|
+
"seconds": 0.0649345419369638,
|
|
39
39
|
"stdout": "All checks passed!\n",
|
|
40
40
|
"stderr": ""
|
|
41
41
|
},
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"scripts"
|
|
54
54
|
],
|
|
55
55
|
"exit_code": 0,
|
|
56
|
-
"seconds": 0.
|
|
57
|
-
"stdout": "
|
|
56
|
+
"seconds": 0.024958166992291808,
|
|
57
|
+
"stdout": "110 files already formatted\n",
|
|
58
58
|
"stderr": ""
|
|
59
59
|
},
|
|
60
60
|
{
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"src/pi_python"
|
|
66
66
|
],
|
|
67
67
|
"exit_code": 0,
|
|
68
|
-
"seconds": 0.
|
|
69
|
-
"stdout": "Success: no issues found in
|
|
68
|
+
"seconds": 0.5702685830183327,
|
|
69
|
+
"stdout": "Success: no issues found in 43 source files\n",
|
|
70
70
|
"stderr": ""
|
|
71
71
|
},
|
|
72
72
|
{
|
|
@@ -77,8 +77,8 @@
|
|
|
77
77
|
"-q"
|
|
78
78
|
],
|
|
79
79
|
"exit_code": 0,
|
|
80
|
-
"seconds":
|
|
81
|
-
"stdout": "........................................................................ [
|
|
80
|
+
"seconds": 149.19938791706227,
|
|
81
|
+
"stdout": "........................................................................ [ 9%]\n........................................................................ [ 19%]\n........................................................................ [ 28%]\n........................................................................ [ 38%]\n........................................................................ [ 47%]\n........................................................................ [ 57%]\n........................................................................ [ 67%]\n...............................................ss....................... [ 76%]\n........................................................................ [ 86%]\n........................................................................ [ 95%]\n................................ [100%]\n750 passed, 2 skipped in 148.30s (0:02:28)\n",
|
|
82
82
|
"stderr": ""
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"examples/in_memory.py"
|
|
90
90
|
],
|
|
91
91
|
"exit_code": 0,
|
|
92
|
-
"seconds": 0.
|
|
92
|
+
"seconds": 0.6022720420733094,
|
|
93
93
|
"stdout": "The telemetry contains 3 complete records.\n",
|
|
94
94
|
"stderr": ""
|
|
95
95
|
},
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"test/agent.test.ts"
|
|
105
105
|
],
|
|
106
106
|
"exit_code": 0,
|
|
107
|
-
"seconds": 1.
|
|
108
|
-
"stdout": "\n> @earendil-works/pi-agent-core@1.0.0 test\n> vitest --run test/agent-loop.test.ts test/agent.test.ts\n\n\n RUN v4.1.11 /Users/daidong/Documents/gitrepos/pi-python/reference/pi/packages/agent\n\n\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\n\n Test Files 2 passed (2)\n Tests 77 passed (77)\n Start at
|
|
107
|
+
"seconds": 1.9349422920495272,
|
|
108
|
+
"stdout": "\n> @earendil-works/pi-agent-core@1.0.0 test\n> vitest --run test/agent-loop.test.ts test/agent.test.ts\n\n\n RUN v4.1.11 /Users/daidong/Documents/gitrepos/pi-python/reference/pi/packages/agent\n\n\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\n\n Test Files 2 passed (2)\n Tests 77 passed (77)\n Start at 12:01:38\n Duration 1.40s (transform 916ms, setup 0ms, import 2.00s, tests 281ms, environment 0ms)\n\n",
|
|
109
109
|
"stderr": ""
|
|
110
110
|
},
|
|
111
111
|
{
|
|
@@ -121,8 +121,8 @@
|
|
|
121
121
|
"test/openai-codex-stream.test.ts"
|
|
122
122
|
],
|
|
123
123
|
"exit_code": 0,
|
|
124
|
-
"seconds": 1.
|
|
125
|
-
"stdout": "\n> @earendil-works/pi-ai@1.0.0 test\n> vitest --run test/transcript-tool-changes.test.ts test/validation.test.ts test/anthropic-mid-conversation-effort.test.ts test/openai-codex-stream.test.ts\n\n\n RUN v4.1.11 /Users/daidong/Documents/gitrepos/pi-python/reference/pi/packages/ai\n\n\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\n\n Test Files 4 passed (4)\n Tests 70 passed (70)\n Start at
|
|
124
|
+
"seconds": 1.3067305411677808,
|
|
125
|
+
"stdout": "\n> @earendil-works/pi-ai@1.0.0 test\n> vitest --run test/transcript-tool-changes.test.ts test/validation.test.ts test/anthropic-mid-conversation-effort.test.ts test/openai-codex-stream.test.ts\n\n\n RUN v4.1.11 /Users/daidong/Documents/gitrepos/pi-python/reference/pi/packages/ai\n\n\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\u00b7\n\n Test Files 4 passed (4)\n Tests 70 passed (70)\n Start at 12:01:39\n Duration 992ms (transform 1.03s, setup 0ms, import 1.86s, tests 252ms, environment 0ms)\n\n",
|
|
126
126
|
"stderr": ""
|
|
127
127
|
},
|
|
128
128
|
{
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"scripts/conformance.py"
|
|
134
134
|
],
|
|
135
135
|
"exit_code": 0,
|
|
136
|
-
"seconds":
|
|
136
|
+
"seconds": 5.7676790410187095,
|
|
137
137
|
"stdout": "C01-text: passed []\nC02-tool: passed []\nC03-sequential: passed []\nC04-parallel: passed []\nC05-one-sequential: passed []\nC06-one-failure: passed []\nC07-unknown: passed []\nC08-prepare: passed []\nC09-before-error: passed []\nC09-block: passed []\nC09-replace: passed []\nC10-length: passed []\nC11-transform: passed []\nC12-system: passed []\nC13-steering: passed []\nC14-followup-all: passed []\nC14-followup-one: passed []\nC15-prepare: passed []\nC16-continue: passed []\nC16-end: passed []\nC16-mixed: passed []\nC16-terminate: passed []\nC19-abort-stream: passed []\nC19-abort-tools: passed []\nC24-provider-error: passed []\n",
|
|
138
138
|
"stderr": ""
|
|
139
139
|
},
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
"scripts/provider_conformance.py"
|
|
146
146
|
],
|
|
147
147
|
"exit_code": 0,
|
|
148
|
-
"seconds":
|
|
148
|
+
"seconds": 15.009326208150014,
|
|
149
149
|
"stdout": "anthropic-oauth.json passed\nanthropic-request-cache-long.json passed\nanthropic-request-cache-none.json passed\nanthropic-request-replay.json passed\nanthropic-request-tools-image.json passed\nanthropic-text.json passed\nanthropic-thinking.json passed\nanthropic-tool.json passed\ncodex-request-tools-image.json passed\ncodex-text.json passed\ncompletions-compat-strict.json passed\ncompletions-deepseek.json passed\ncompletions-format-ant-ling.json passed\ncompletions-format-baseten.json passed\ncompletions-format-string-thinking.json passed\ncompletions-format-together.json passed\ncompletions-format-zai.json passed\ncompletions-midconvo-tools.json passed\ncompletions-moonshot-usage.json passed\ncompletions-openai-off.json passed\ncompletions-openrouter.json passed\ncompletions-qwen-length.json passed\ncompletions-reasoning-content.json passed\ncompletions-request-replay.json passed\ncompletions-text.json passed\ncompletions-tool-stream.json passed\nopenai-incomplete.json passed\nopenai-request-cache-long.json passed\nopenai-request-cache-none.json passed\nopenai-request-reasoning.json passed\nopenai-request-replay.json passed\nopenai-request-tools-image.json passed\nopenai-text.json passed\nopenai-thinking-backfill.json passed\nopenai-thinking.json passed\nopenai-tool.json passed\nproxy-text.json passed\nproxy-thinking-tool.json passed\nsession-anthropic-collapse-budget.json passed\nsession-anthropic-native-tools.json passed\nsession-anthropic-oauth-effort.json passed\nsession-anthropic-redefinition.json passed\nsession-anthropic-server-fallback.json passed\nsession-anthropic-thinking-off.json passed\nsession-codex-tool-search.json passed\nsession-openai-additional-tools.json passed\nsession-openai-collapse.json passed\nsession-openai-explicit-cache-long.json passed\nsession-openai-explicit-cache-none.json passed\nsession-openai-removal.json passed\n",
|
|
150
150
|
"stderr": ""
|
|
151
151
|
},
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"scripts/websocket_conformance.py"
|
|
158
158
|
],
|
|
159
159
|
"exit_code": 0,
|
|
160
|
-
"seconds": 0.
|
|
160
|
+
"seconds": 0.9335567080415785,
|
|
161
161
|
"stdout": "codex-continuation-lost-state.json passed\ncodex-continuation-tool-loop.json passed\n",
|
|
162
162
|
"stderr": ""
|
|
163
163
|
},
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
"scripts/recovery_conformance.py"
|
|
170
170
|
],
|
|
171
171
|
"exit_code": 0,
|
|
172
|
-
"seconds": 0.
|
|
172
|
+
"seconds": 0.628341041970998,
|
|
173
173
|
"stdout": "recovery classifiers: 44/44 match upstream \n",
|
|
174
174
|
"stderr": ""
|
|
175
175
|
},
|
|
@@ -181,8 +181,8 @@
|
|
|
181
181
|
"scripts/plugin_conformance.py"
|
|
182
182
|
],
|
|
183
183
|
"exit_code": 0,
|
|
184
|
-
"seconds":
|
|
185
|
-
"stdout": "....... [100%]\n7 passed in 0.
|
|
184
|
+
"seconds": 1.306608916958794,
|
|
185
|
+
"stdout": "....... [100%]\n7 passed in 0.74s\n",
|
|
186
186
|
"stderr": ""
|
|
187
187
|
},
|
|
188
188
|
{
|
|
@@ -193,10 +193,22 @@
|
|
|
193
193
|
"examples/plugin_demo.py"
|
|
194
194
|
],
|
|
195
195
|
"exit_code": 0,
|
|
196
|
-
"seconds": 0.
|
|
196
|
+
"seconds": 0.576676958007738,
|
|
197
197
|
"stdout": "loaded: lab_tools 0.1.0\ncheck: counts_duplicates passed\nprompt: Find duplicate events in events.csv using a 30 second window. Read the dedup-window skill first.\ntools used: ['read_skill', 'subagent']\nanswer: The reviewer found 2 duplicate rows.\n",
|
|
198
198
|
"stderr": ""
|
|
199
199
|
},
|
|
200
|
+
{
|
|
201
|
+
"command": [
|
|
202
|
+
"uv",
|
|
203
|
+
"run",
|
|
204
|
+
"python",
|
|
205
|
+
"examples/mcp_interactive.py"
|
|
206
|
+
],
|
|
207
|
+
"exit_code": 0,
|
|
208
|
+
"seconds": 1.8445827078539878,
|
|
209
|
+
"stdout": "Model task=demo-run request=1 profile=default attempt=1 usage=None\nModel task=demo-run request=2 profile=default attempt=1 usage=None\nModel task=demo-run request=3 profile=json attempt=1 usage={'input': 4, 'output': 3, 'cacheRead': 1}\nModel task=demo-run request=4 profile=text attempt=1 usage={'input': 4, 'output': 3, 'cacheRead': 1}\nForm from business: Choose output for report\nDemo user chooses: short, confirmed\n{\"label\": \"report\", \"model_reply\": \"[report] [ready]\", \"action\": \"accept\", \"selection\": {\"style\": \"short\", \"confirmed\": true}, \"auxiliary\": {\"json\": {\"ok\": true}, \"text\": \"Ready\"}}\n",
|
|
210
|
+
"stderr": ""
|
|
211
|
+
},
|
|
200
212
|
{
|
|
201
213
|
"command": [
|
|
202
214
|
"uv",
|
|
@@ -206,7 +218,7 @@
|
|
|
206
218
|
"--help"
|
|
207
219
|
],
|
|
208
220
|
"exit_code": 0,
|
|
209
|
-
"seconds": 0.
|
|
221
|
+
"seconds": 0.6522026660386473,
|
|
210
222
|
"stdout": "usage: provider_chat.py [-h]\n --provider {anthropic,openai,openai-codex,openai-chatgpt,deepseek}\n --model MODEL [--prompt PROMPT]\n [--credential-file CREDENTIAL_FILE] [--login]\n [--device]\n [--thinking {off,minimal,low,medium,high,xhigh,max}]\n [--transport {sse,websocket,websocket-cached,auto}]\n [--session-id SESSION_ID]\n\nExplicit API/OAuth example. Invoke --help; never imported by the core.\n\noptions:\n -h, --help show this help message and exit\n --provider {anthropic,openai,openai-codex,openai-chatgpt,deepseek}\n --model MODEL Model ID enabled for this account\n --prompt PROMPT\n --credential-file CREDENTIAL_FILE\n App-owned OAuth file (never reuse another client file)\n --login\n --device Codex device authorization instead of browser callback\n --thinking {off,minimal,low,medium,high,xhigh,max}\n --transport {sse,websocket,websocket-cached,auto}\n --session-id SESSION_ID\n Required for websocket-cached\n",
|
|
211
223
|
"stderr": ""
|
|
212
224
|
},
|
|
@@ -216,9 +228,9 @@
|
|
|
216
228
|
"build"
|
|
217
229
|
],
|
|
218
230
|
"exit_code": 0,
|
|
219
|
-
"seconds": 1.
|
|
231
|
+
"seconds": 1.0952744169626385,
|
|
220
232
|
"stdout": "",
|
|
221
|
-
"stderr": "Building source distribution...\nBuilding wheel from source distribution...\nSuccessfully built dist/pi_python_core-0.
|
|
233
|
+
"stderr": "Building source distribution...\nBuilding wheel from source distribution...\nSuccessfully built dist/pi_python_core-0.10.1.tar.gz\nSuccessfully built dist/pi_python_core-0.10.1-py3-none-any.whl\n"
|
|
222
234
|
}
|
|
223
235
|
],
|
|
224
236
|
"status": "passed"
|
|
@@ -48,6 +48,8 @@ Every event passes the same check: blocks must pair up, deltas must land in an o
|
|
|
48
48
|
|
|
49
49
|
Message data also allows `pending` and `deferred`. `pending` is only for in-stream snapshots and cannot be committed to history; `deferred` can hold a background handle, but the library does not yet poll background tasks. For `length`, every tool call gets a not-executed result, and the model may then handle the error. `error` / `aborted` messages cannot declare tool calls: before the message is committed, its tool calls are removed, the rest of the partial content is kept, and a `removed_tool_calls` entry is added to `diagnostics`.
|
|
50
50
|
|
|
51
|
+
The Agent closes each request's response iterator when the request ends, including error and cancellation paths. Custom iterators that own resources should implement `aclose()`. This does not close the shared Provider.
|
|
52
|
+
|
|
51
53
|
## Tool
|
|
52
54
|
|
|
53
55
|
`Tool(name, description, input_schema, execute, output_schema=None, execution_mode="parallel", prepare_arguments=None)`.
|
|
@@ -81,8 +83,34 @@ def search_papers(query: str, year: int | None = None, limit: int = 10) -> list[
|
|
|
81
83
|
|
|
82
84
|
Supported parameter types: `str`, `int`, `float`, `bool`, `None`, `list`, `set`, `tuple`, `dict[str, T]`, `Literal`, `Enum`, `Optional` and other unions, `Annotated[T, "description"]`, `TypedDict`, dataclasses, `datetime`, `date`, `UUID`, `Path`, and pydantic models. Before the call, the JSON arguments are converted to the types the function asks for, such as enum members, dates, dataclasses or pydantic models. A parameter annotated as `ToolContext` receives the call context and does not appear in the schema. `*args`, `**kwargs` and types that cannot be represented as JSON raise `ConfigurationError` at registration.
|
|
83
85
|
|
|
86
|
+
For a union, conversion tries branches in annotation order, using only branches whose JSON Schema matches the input. For example, `list[int] | str` preserves `"abc"` as a string. When several branches match, the first successful conversion wins.
|
|
87
|
+
|
|
88
|
+
Schema and conversion are compiled together at registration, including recursive types and union branches. Bare `set`, `frozenset` and `tuple` annotations also convert JSON arrays to the requested Python container. Nested pydantic definitions are isolated between parameters and union branches, even when their class names match.
|
|
89
|
+
|
|
90
|
+
`TypedDict` requiredness follows resolved `Required` and `NotRequired` annotations,
|
|
91
|
+
including inherited fields and `Annotated` wrappers when annotations are postponed.
|
|
92
|
+
|
|
84
93
|
Concurrency is unlimited by default: a batch of tools all run at once, as in Pi; set `RunLimits(max_concurrency=...)` when you need a cap. If any tool requires `sequential`, the whole batch runs one at a time. When running concurrently, preparation completes in call order before execution starts; end events follow the order in which post-processing finishes, and results in history follow call order.
|
|
85
94
|
|
|
95
|
+
Parallel tool and subagent batches own their child tasks: failure or cancellation cancels unfinished siblings and waits for their cleanup. Repeated caller cancellation does not interrupt that cleanup. The Run's existing cleanup deadline still applies; `cleanup_complete` reports whether cleanup actually finished.
|
|
96
|
+
|
|
97
|
+
Inside a tool, use `await context.run_agent(child, message)` to run an exclusively
|
|
98
|
+
owned, idle child Agent. It returns the child's `RunResult` and closes that Agent;
|
|
99
|
+
the shared Provider stays open. See [the subagent example](../examples/subagent.py).
|
|
100
|
+
An already running child is rejected without cancelling or closing it. Ordinary
|
|
101
|
+
model/tool failures remain results that the calling tool can handle.
|
|
102
|
+
|
|
103
|
+
Nested calls preserve two separate facts: whether an external operation's outcome
|
|
104
|
+
is known, and whether its work has stopped. An unknown child outcome raises
|
|
105
|
+
`ToolOutcomeUnknownError`, marks the enclosing Agent as requiring reconciliation,
|
|
106
|
+
and stops further execution. This also applies across parallel siblings and multiple
|
|
107
|
+
nesting levels. An unfinished child keeps its enclosing tool pending. The parent's
|
|
108
|
+
cleanup deadline still bounds its run, which reports `cleanup_complete=False` until
|
|
109
|
+
the descendant actually finishes. Repeated cancellation cannot abandon that cleanup.
|
|
110
|
+
Standalone `ToolContext` callers must keep awaiting the call or manage its lifetime
|
|
111
|
+
with `TaskScope`; without an enclosing Agent there is no Run cleanup deadline.
|
|
112
|
+
Check `require_features(["nested-agent-ownership-v1"])` when depending on this API.
|
|
113
|
+
|
|
86
114
|
A standalone program can call `await run_tool_call(tool, call, context, before_tool_call=..., after_tool_call=...)` to reuse the same validation and hook path. For standalone calls, the program manages lifetime, timeouts and cancellation itself; `Agent` adds batch management and `RunLimits`.
|
|
87
115
|
|
|
88
116
|
## Hooks
|
|
@@ -159,6 +187,23 @@ async with connect_stdio("uvx", ["mcp-server-fetch"], prefix="web") as tools:
|
|
|
159
187
|
|
|
160
188
|
Requires `pip install 'pi-python-core[mcp]'` and works with the official MCP SDK 1.10 and later, including 2.x. `connect_stdio` starts a stdio MCP server and closes it when the `async with` block exits. `connect_http(url, headers=None, prefix=None, names=None)` connects to a streamable HTTP server in the same way; the legacy SSE transport is not supported, as in Pi. It follows redirects only within the server's origin, so headers are never sent to another one. It is tested with MCP SDK 1.10, 1.30 and 2.3. If you already have a `ClientSession`, wrap its tools with `await mcp_tools(session, prefix=None, names=None)`. Conversion follows Pi's MCP adapter: text and images convert directly; embedded text or image resources are unpacked; audio, resource links and binary resources become short text descriptions; a result with only structured content becomes JSON text and is also kept as `structured_content`; MCP's `isError` becomes a tool error; progress notifications become `tool_execution_update` events. After the prefix is added, tool names keep only letters, digits, `_` and `-`, up to 64 characters. A tool whose schema cannot be used is skipped with a warning, without affecting the server's other tools. A stdio server written with Python MCP SDK 2.3 cannot start on PyPy (`fcntl.F_DUPFD_CLOEXEC` is missing); this is a limitation of the SDK itself, and the client side is unaffected.
|
|
161
189
|
|
|
190
|
+
On POSIX, `connect_stdio(..., process_scope=True)` also cleans surviving process
|
|
191
|
+
groups and nested pi-python stdio connections on exit. It is opt-in at the outer
|
|
192
|
+
connection and inherited by nested connections. Non-POSIX systems reject explicit
|
|
193
|
+
enablement. See [process ownership](MCP_INTERACTION.md) for scope and limitations.
|
|
194
|
+
|
|
195
|
+
All three MCP entry points accept optional `call_metadata`, a JSON object passed to
|
|
196
|
+
`ClientSession.call_tool(meta=...)`. It is copied per registration and call, stays out
|
|
197
|
+
of tool arguments, and requires an SDK with `meta` support; otherwise registration
|
|
198
|
+
raises `ConfigurationError`. See [runtime metadata and readiness](PLUGINS.md#mcp-servers)
|
|
199
|
+
for plugin configuration and startup checks.
|
|
200
|
+
|
|
201
|
+
`connect_stdio` and `connect_http` also accept `callbacks=MCPCallbacks(...)` for
|
|
202
|
+
host-authorized sampling and form elicitation. `SamplingHandler` adapts a host Provider;
|
|
203
|
+
`SamplingProvider` runs a server Agent through the current MCP request. This opt-in
|
|
204
|
+
feature requires SDK >=2.3,<3. See [MCP interaction](MCP_INTERACTION.md) for public APIs,
|
|
205
|
+
protocol constraints, cancellation, and the runnable offline example.
|
|
206
|
+
|
|
162
207
|
## Plugins
|
|
163
208
|
|
|
164
209
|
`pi_python.plugins` loads plugins: named bundles of tools, system prompt text, hooks, skills, prompt templates, subagents and MCP servers, in the format of Pi's packages. `async with load_plugins([...], services=..., options=...) as plugins:` loads them, and `plugins.agent(...)` builds an Agent with everything they contribute. The [plugin guide](PLUGINS.md) covers writing, distributing and combining plugins.
|
|
@@ -216,3 +261,45 @@ OpenAI may add encrypted_content back in the final response. If the visible reas
|
|
|
216
261
|
`AssistantMessage.provider_thinking_level` matches upstream: it records this answer's effort only for Claude models that use effort markers, so later requests can rebuild the markers in history. Read `thinking_level` when you need the requested level.
|
|
217
262
|
|
|
218
263
|
When replaying history, Providers skip `error` / `aborted` answers following upstream's rules; reasoning from a different model is converted to plain text and its signature is dropped; a system message that sits between a tool call and its result is moved after the result. The session history itself is unchanged.
|
|
264
|
+
|
|
265
|
+
Host sampling profiles, usage observation, retry policy, and build feature markers are documented in [MCP interactions](MCP_INTERACTION.md#real-providers-profiles-accounting-and-retries).
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
## Owned tasks and calls from worker threads
|
|
269
|
+
|
|
270
|
+
`TaskScope` owns the asynchronous calls passed to `await scope.run(awaitable,
|
|
271
|
+
cancel=token)`. Each call runs in a child task. Cancelling the caller or token
|
|
272
|
+
cancels that task and waits for its cleanup. `await scope.aclose()` rejects new
|
|
273
|
+
calls, cancels active calls, and joins them, including calls waiting on an
|
|
274
|
+
application lock. Use `async with TaskScope() as scope`, or a plugin's
|
|
275
|
+
`api.task_scope()` to register automatic cleanup. Exceptions go to the individual
|
|
276
|
+
caller. Closing does not re-raise a completed call's error. Work must cooperate
|
|
277
|
+
with cancellation; this API does not terminate threads or impose a deadline.
|
|
278
|
+
An owned task cannot close its own scope. A scope is bound to its first event loop.
|
|
279
|
+
|
|
280
|
+
`LoopPortal` submits async work from a synchronous worker thread onto an **existing**
|
|
281
|
+
event loop. This differs from `run_sync`, which owns a separate background loop.
|
|
282
|
+
Create and close the portal on the loop that owns the connection:
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
import asyncio
|
|
286
|
+
from pi_python import LoopPortal
|
|
287
|
+
|
|
288
|
+
async def request(connection):
|
|
289
|
+
async with LoopPortal() as portal:
|
|
290
|
+
# A callable is passed, not a coroutine created in the worker thread.
|
|
291
|
+
return await asyncio.to_thread(portal.call, connection.fetch, "item")
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`portal.call(async_function, *args, timeout=None, **kwargs)` returns the result or
|
|
295
|
+
raises the error in the worker thread, preserving its context variables. Blocking
|
|
296
|
+
an event-loop thread is rejected. Closing cancels and joins submitted work without
|
|
297
|
+
closing the borrowed loop. A timeout bounds the blocking wait and requests async
|
|
298
|
+
cancellation; `aclose()` waits for that cleanup. Keep the owning loop running until
|
|
299
|
+
the portal has closed. Application threads themselves remain application-owned.
|
|
300
|
+
|
|
301
|
+
`FEATURES` is the immutable set of versioned APIs provided by the current build.
|
|
302
|
+
`require_features(names, where="Application")` raises `ConfigurationError` for
|
|
303
|
+
unknown or unavailable features. It does not validate installed optional packages,
|
|
304
|
+
MCP peer capabilities, credentials, or host authorization. `MCP_FEATURES` remains
|
|
305
|
+
available and is a subset. Plugin declarations are described in [Plugins](PLUGINS.md#declaring-required-framework-features).
|