pi-python-core 0.8.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.8.1/.gitignore +18 -0
- pi_python_core-0.8.1/LICENSE +21 -0
- pi_python_core-0.8.1/NOTICE +8 -0
- pi_python_core-0.8.1/PKG-INFO +119 -0
- pi_python_core-0.8.1/README.md +90 -0
- pi_python_core-0.8.1/compat/COVERAGE.md +119 -0
- pi_python_core-0.8.1/compat/__init__.py +1 -0
- pi_python_core-0.8.1/compat/baseline.json +32 -0
- pi_python_core-0.8.1/compat/contracts/release-candidate.example.json +21 -0
- pi_python_core-0.8.1/compat/contracts/release-candidate.schema.json +162 -0
- pi_python_core-0.8.1/compat/contracts/upstream-baseline.json +169 -0
- pi_python_core-0.8.1/compat/fixtures/C01-text.json +18 -0
- pi_python_core-0.8.1/compat/fixtures/C02-tool.json +36 -0
- pi_python_core-0.8.1/compat/fixtures/C03-sequential.json +47 -0
- pi_python_core-0.8.1/compat/fixtures/C04-parallel.json +47 -0
- pi_python_core-0.8.1/compat/fixtures/C05-one-sequential.json +47 -0
- pi_python_core-0.8.1/compat/fixtures/C06-one-failure.json +47 -0
- pi_python_core-0.8.1/compat/fixtures/C07-unknown.json +30 -0
- pi_python_core-0.8.1/compat/fixtures/C08-prepare.json +50 -0
- pi_python_core-0.8.1/compat/fixtures/C09-before-error.json +39 -0
- pi_python_core-0.8.1/compat/fixtures/C09-block.json +39 -0
- pi_python_core-0.8.1/compat/fixtures/C09-replace.json +40 -0
- pi_python_core-0.8.1/compat/fixtures/C10-length.json +42 -0
- pi_python_core-0.8.1/compat/fixtures/C11-transform.json +19 -0
- pi_python_core-0.8.1/compat/fixtures/C12-system.json +35 -0
- pi_python_core-0.8.1/compat/fixtures/C13-steering.json +64 -0
- pi_python_core-0.8.1/compat/fixtures/C14-followup-all.json +47 -0
- pi_python_core-0.8.1/compat/fixtures/C14-followup-one.json +56 -0
- pi_python_core-0.8.1/compat/fixtures/C15-prepare.json +38 -0
- pi_python_core-0.8.1/compat/fixtures/C16-continue.json +40 -0
- pi_python_core-0.8.1/compat/fixtures/C16-end.json +39 -0
- pi_python_core-0.8.1/compat/fixtures/C16-mixed.json +47 -0
- pi_python_core-0.8.1/compat/fixtures/C16-terminate.json +27 -0
- pi_python_core-0.8.1/compat/fixtures/C19-abort-stream.json +28 -0
- pi_python_core-0.8.1/compat/fixtures/C19-abort-tools.json +44 -0
- pi_python_core-0.8.1/compat/fixtures/C24-provider-error.json +21 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-oauth.json +55 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-request-cache-long.json +82 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-request-cache-none.json +82 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-request-replay.json +142 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-request-tools-image.json +100 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-text.json +54 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-thinking.json +95 -0
- pi_python_core-0.8.1/compat/provider-fixtures/anthropic-tool.json +64 -0
- pi_python_core-0.8.1/compat/provider-fixtures/codex-request-tools-image.json +128 -0
- pi_python_core-0.8.1/compat/provider-fixtures/codex-text.json +84 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-compat-strict.json +146 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-deepseek.json +188 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-format-ant-ling.json +99 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-format-baseten.json +108 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-format-string-thinking.json +105 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-format-together.json +95 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-format-zai.json +102 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-midconvo-tools.json +134 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-moonshot-usage.json +68 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-openai-off.json +104 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-openrouter.json +221 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-qwen-length.json +103 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-reasoning-content.json +157 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-request-replay.json +268 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-text.json +106 -0
- pi_python_core-0.8.1/compat/provider-fixtures/completions-tool-stream.json +251 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-incomplete.json +83 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-request-cache-long.json +108 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-request-cache-none.json +108 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-request-reasoning.json +84 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-request-replay.json +168 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-request-tools-image.json +126 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-text.json +80 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-thinking-backfill.json +115 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-thinking.json +116 -0
- pi_python_core-0.8.1/compat/provider-fixtures/openai-tool.json +63 -0
- pi_python_core-0.8.1/compat/provider-fixtures/proxy-text.json +27 -0
- pi_python_core-0.8.1/compat/provider-fixtures/proxy-thinking-tool.json +50 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-anthropic-collapse-budget.json +139 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-anthropic-native-tools.json +197 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-anthropic-oauth-effort.json +197 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-anthropic-redefinition.json +138 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-anthropic-server-fallback.json +120 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-anthropic-thinking-off.json +217 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-codex-tool-search.json +212 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-openai-additional-tools.json +267 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-openai-collapse.json +164 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-openai-explicit-cache-long.json +129 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-openai-explicit-cache-none.json +128 -0
- pi_python_core-0.8.1/compat/provider-fixtures/session-openai-removal.json +182 -0
- pi_python_core-0.8.1/compat/recovery-cases.json +245 -0
- pi_python_core-0.8.1/compat/release.py +134 -0
- pi_python_core-0.8.1/compat/results/C01-text.python.json +96 -0
- pi_python_core-0.8.1/compat/results/C01-text.upstream.json +116 -0
- pi_python_core-0.8.1/compat/results/C02-tool.python.json +281 -0
- pi_python_core-0.8.1/compat/results/C02-tool.upstream.json +306 -0
- pi_python_core-0.8.1/compat/results/C03-sequential.python.json +398 -0
- pi_python_core-0.8.1/compat/results/C03-sequential.upstream.json +423 -0
- pi_python_core-0.8.1/compat/results/C04-parallel.python.json +398 -0
- pi_python_core-0.8.1/compat/results/C04-parallel.upstream.json +423 -0
- pi_python_core-0.8.1/compat/results/C05-one-sequential.python.json +398 -0
- pi_python_core-0.8.1/compat/results/C05-one-sequential.upstream.json +423 -0
- pi_python_core-0.8.1/compat/results/C06-one-failure.python.json +398 -0
- pi_python_core-0.8.1/compat/results/C06-one-failure.upstream.json +423 -0
- pi_python_core-0.8.1/compat/results/C07-unknown.python.json +237 -0
- pi_python_core-0.8.1/compat/results/C07-unknown.upstream.json +262 -0
- pi_python_core-0.8.1/compat/results/C08-prepare.python.json +317 -0
- pi_python_core-0.8.1/compat/results/C08-prepare.upstream.json +342 -0
- pi_python_core-0.8.1/compat/results/C09-before-error.python.json +276 -0
- pi_python_core-0.8.1/compat/results/C09-before-error.upstream.json +301 -0
- pi_python_core-0.8.1/compat/results/C09-block.python.json +276 -0
- pi_python_core-0.8.1/compat/results/C09-block.upstream.json +301 -0
- pi_python_core-0.8.1/compat/results/C09-replace.python.json +281 -0
- pi_python_core-0.8.1/compat/results/C09-replace.upstream.json +306 -0
- pi_python_core-0.8.1/compat/results/C10-length.python.json +368 -0
- pi_python_core-0.8.1/compat/results/C10-length.upstream.json +393 -0
- pi_python_core-0.8.1/compat/results/C11-transform.python.json +103 -0
- pi_python_core-0.8.1/compat/results/C11-transform.upstream.json +123 -0
- pi_python_core-0.8.1/compat/results/C12-system.python.json +128 -0
- pi_python_core-0.8.1/compat/results/C12-system.upstream.json +128 -0
- pi_python_core-0.8.1/compat/results/C13-steering.python.json +435 -0
- pi_python_core-0.8.1/compat/results/C13-steering.upstream.json +465 -0
- pi_python_core-0.8.1/compat/results/C14-followup-all.python.json +209 -0
- pi_python_core-0.8.1/compat/results/C14-followup-all.upstream.json +234 -0
- pi_python_core-0.8.1/compat/results/C14-followup-one.python.json +292 -0
- pi_python_core-0.8.1/compat/results/C14-followup-one.upstream.json +322 -0
- pi_python_core-0.8.1/compat/results/C15-prepare.python.json +307 -0
- pi_python_core-0.8.1/compat/results/C15-prepare.upstream.json +332 -0
- pi_python_core-0.8.1/compat/results/C16-continue.python.json +284 -0
- pi_python_core-0.8.1/compat/results/C16-continue.upstream.json +309 -0
- pi_python_core-0.8.1/compat/results/C16-end.python.json +187 -0
- pi_python_core-0.8.1/compat/results/C16-end.upstream.json +207 -0
- pi_python_core-0.8.1/compat/results/C16-mixed.python.json +398 -0
- pi_python_core-0.8.1/compat/results/C16-mixed.upstream.json +423 -0
- pi_python_core-0.8.1/compat/results/C16-terminate.python.json +185 -0
- pi_python_core-0.8.1/compat/results/C16-terminate.upstream.json +205 -0
- pi_python_core-0.8.1/compat/results/C19-abort-stream.python.json +99 -0
- pi_python_core-0.8.1/compat/results/C19-abort-stream.upstream.json +119 -0
- pi_python_core-0.8.1/compat/results/C19-abort-tools.python.json +332 -0
- pi_python_core-0.8.1/compat/results/C19-abort-tools.upstream.json +352 -0
- pi_python_core-0.8.1/compat/results/C24-provider-error.python.json +99 -0
- pi_python_core-0.8.1/compat/results/C24-provider-error.upstream.json +119 -0
- pi_python_core-0.8.1/compat/results/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/benchmark.json +504 -0
- pi_python_core-0.8.1/compat/results/bootstrap.json +11 -0
- pi_python_core-0.8.1/compat/results/candidate-live-noop.json +7 -0
- pi_python_core-0.8.1/compat/results/conformance.json +327 -0
- pi_python_core-0.8.1/compat/results/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/linux-3.14.json +54 -0
- pi_python_core-0.8.1/compat/results/linux-install-hash-repair.json +167 -0
- pi_python_core-0.8.1/compat/results/live-0.5-regression.json +645 -0
- pi_python_core-0.8.1/compat/results/live-0.5-session-claude.json +153 -0
- pi_python_core-0.8.1/compat/results/live-0.5-session-codex.json +127 -0
- pi_python_core-0.8.1/compat/results/live-claude-reasoning-replay.json +70 -0
- pi_python_core-0.8.1/compat/results/live-final-matrix.json +618 -0
- pi_python_core-0.8.1/compat/results/live-initial.json +144 -0
- pi_python_core-0.8.1/compat/results/live-loop-initial.json +310 -0
- pi_python_core-0.8.1/compat/results/live-providers.json +477 -0
- pi_python_core-0.8.1/compat/results/live-reasoning-replay.json +194 -0
- pi_python_core-0.8.1/compat/results/live-refresh.json +49 -0
- pi_python_core-0.8.1/compat/results/live-regression-0.4-deepseek.json +221 -0
- pi_python_core-0.8.1/compat/results/live-regression-0.4-first-run.json +561 -0
- pi_python_core-0.8.1/compat/results/live-regression-0.4.json +429 -0
- pi_python_core-0.8.1/compat/results/live-session-claude.json +153 -0
- pi_python_core-0.8.1/compat/results/live-session-codex.json +127 -0
- pi_python_core-0.8.1/compat/results/live-websocket-cached-recheck.json +71 -0
- pi_python_core-0.8.1/compat/results/live-websocket-cached.json +37 -0
- pi_python_core-0.8.1/compat/results/live-websocket-final.json +78 -0
- pi_python_core-0.8.1/compat/results/provider-conformance.json +10147 -0
- pi_python_core-0.8.1/compat/results/recovery-conformance.upstream.json +222 -0
- pi_python_core-0.8.1/compat/results/runtime-dependencies.json +78 -0
- pi_python_core-0.8.1/compat/results/source-verification.json +107 -0
- pi_python_core-0.8.1/compat/results/v0.1.0/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/v0.1.0/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.1.0/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.1.0/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.1.0/verification.json +146 -0
- pi_python_core-0.8.1/compat/results/v0.2.0/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/v0.2.0/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.2.0/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.2.0/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.2.0/verification.json +173 -0
- pi_python_core-0.8.1/compat/results/v0.3.0/against-0.4-fixtures.json +6410 -0
- pi_python_core-0.8.1/compat/results/v0.3.0/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/v0.3.0/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.3.0/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.3.0/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.3.0/provider-conformance.json +3551 -0
- pi_python_core-0.8.1/compat/results/v0.3.0/verification.json +173 -0
- pi_python_core-0.8.1/compat/results/v0.4.0/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/v0.4.0/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.4.0/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.4.0/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.4.0/verification.json +187 -0
- pi_python_core-0.8.1/compat/results/v0.5.0/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/v0.5.0/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.5.0/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.5.0/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.5.0/verification.json +187 -0
- pi_python_core-0.8.1/compat/results/v0.6.0/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/v0.6.0/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.6.0/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.6.0/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.6.0/verification.json +187 -0
- pi_python_core-0.8.1/compat/results/v0.7.0/artifacts.json +12 -0
- pi_python_core-0.8.1/compat/results/v0.7.0/linux-3.11.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.7.0/linux-3.12.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.7.0/linux-3.13.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.7.0/linux-3.14.json +54 -0
- pi_python_core-0.8.1/compat/results/v0.7.0/verification.json +201 -0
- pi_python_core-0.8.1/compat/results/verification.json +201 -0
- pi_python_core-0.8.1/compat/results/websocket-conformance.json +784 -0
- pi_python_core-0.8.1/compat/runner.py +229 -0
- pi_python_core-0.8.1/compat/websocket-fixtures/codex-continuation-lost-state.json +246 -0
- pi_python_core-0.8.1/compat/websocket-fixtures/codex-continuation-tool-loop.json +281 -0
- pi_python_core-0.8.1/docs/API.md +199 -0
- pi_python_core-0.8.1/docs/CONCEPTS.md +73 -0
- pi_python_core-0.8.1/docs/IMPLEMENTATION.md +38 -0
- pi_python_core-0.8.1/docs/PROVIDERS.md +211 -0
- pi_python_core-0.8.1/docs/history/IMPLEMENTATION-0.3.0.md +53 -0
- pi_python_core-0.8.1/docs/history/IMPLEMENTATION-0.4.0.md +70 -0
- pi_python_core-0.8.1/docs/history/IMPLEMENTATION-0.5.0.md +64 -0
- pi_python_core-0.8.1/docs/history/IMPLEMENTATION-0.6.0.md +50 -0
- pi_python_core-0.8.1/docs/history/IMPLEMENTATION-0.7.0.md +47 -0
- pi_python_core-0.8.1/examples/in_memory.py +44 -0
- pi_python_core-0.8.1/examples/local_model.py +85 -0
- pi_python_core-0.8.1/examples/mcp_tools.py +43 -0
- pi_python_core-0.8.1/examples/provider_chat.py +151 -0
- pi_python_core-0.8.1/examples/quickstart.py +81 -0
- pi_python_core-0.8.1/examples/recovery.py +115 -0
- pi_python_core-0.8.1/examples/save_restore.py +58 -0
- pi_python_core-0.8.1/examples/subagent.py +80 -0
- pi_python_core-0.8.1/pyproject.toml +57 -0
- pi_python_core-0.8.1/src/pi_python/__init__.py +160 -0
- pi_python_core-0.8.1/src/pi_python/_version.py +1 -0
- pi_python_core-0.8.1/src/pi_python/agent.py +396 -0
- pi_python_core-0.8.1/src/pi_python/cancellation.py +24 -0
- pi_python_core-0.8.1/src/pi_python/data/models.json +3315 -0
- pi_python_core-0.8.1/src/pi_python/errors.py +49 -0
- pi_python_core-0.8.1/src/pi_python/estimate.py +144 -0
- pi_python_core-0.8.1/src/pi_python/events.py +138 -0
- pi_python_core-0.8.1/src/pi_python/function_tools.py +438 -0
- pi_python_core-0.8.1/src/pi_python/hooks.py +44 -0
- pi_python_core-0.8.1/src/pi_python/limits.py +28 -0
- pi_python_core-0.8.1/src/pi_python/loop.py +431 -0
- pi_python_core-0.8.1/src/pi_python/lowlevel.py +179 -0
- pi_python_core-0.8.1/src/pi_python/mcp.py +187 -0
- pi_python_core-0.8.1/src/pi_python/messages.py +405 -0
- pi_python_core-0.8.1/src/pi_python/models.py +155 -0
- pi_python_core-0.8.1/src/pi_python/provider.py +123 -0
- pi_python_core-0.8.1/src/pi_python/providers/__init__.py +21 -0
- pi_python_core-0.8.1/src/pi_python/providers/anthropic.py +673 -0
- pi_python_core-0.8.1/src/pi_python/providers/common.py +201 -0
- pi_python_core-0.8.1/src/pi_python/providers/completions.py +1149 -0
- pi_python_core-0.8.1/src/pi_python/providers/oauth.py +542 -0
- pi_python_core-0.8.1/src/pi_python/providers/openai.py +681 -0
- pi_python_core-0.8.1/src/pi_python/providers/transport.py +574 -0
- pi_python_core-0.8.1/src/pi_python/proxy.py +304 -0
- pi_python_core-0.8.1/src/pi_python/py.typed +0 -0
- pi_python_core-0.8.1/src/pi_python/queues.py +76 -0
- pi_python_core-0.8.1/src/pi_python/recovery.py +209 -0
- pi_python_core-0.8.1/src/pi_python/run.py +419 -0
- pi_python_core-0.8.1/src/pi_python/stream.py +251 -0
- pi_python_core-0.8.1/src/pi_python/sync.py +78 -0
- pi_python_core-0.8.1/src/pi_python/testing.py +25 -0
- pi_python_core-0.8.1/src/pi_python/tools.py +546 -0
- pi_python_core-0.8.1/src/pi_python/transcript.py +167 -0
- pi_python_core-0.8.1/tests/servers/mcp_server.py +45 -0
- pi_python_core-0.8.1/tests/test_completions.py +311 -0
- pi_python_core-0.8.1/tests/test_conformance.py +18 -0
- pi_python_core-0.8.1/tests/test_contract_v3.py +311 -0
- pi_python_core-0.8.1/tests/test_control.py +571 -0
- pi_python_core-0.8.1/tests/test_examples.py +39 -0
- pi_python_core-0.8.1/tests/test_extended_core.py +100 -0
- pi_python_core-0.8.1/tests/test_function_tools.py +296 -0
- pi_python_core-0.8.1/tests/test_loop.py +321 -0
- pi_python_core-0.8.1/tests/test_mcp.py +195 -0
- pi_python_core-0.8.1/tests/test_messages.py +61 -0
- pi_python_core-0.8.1/tests/test_models.py +73 -0
- pi_python_core-0.8.1/tests/test_oauth.py +350 -0
- pi_python_core-0.8.1/tests/test_providers.py +501 -0
- pi_python_core-0.8.1/tests/test_recovery.py +198 -0
- pi_python_core-0.8.1/tests/test_recovery_conformance.py +42 -0
- pi_python_core-0.8.1/tests/test_recovery_helpers.py +84 -0
- pi_python_core-0.8.1/tests/test_release.py +116 -0
- pi_python_core-0.8.1/tests/test_session_changes.py +216 -0
- pi_python_core-0.8.1/tests/test_sync.py +64 -0
- pi_python_core-0.8.1/tests/test_tools.py +433 -0
- pi_python_core-0.8.1/tests/test_websocket_continuation.py +217 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.ruff_cache/
|
|
6
|
+
.mypy_cache/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
reference/pi/
|
|
11
|
+
reference/node_modules/
|
|
12
|
+
.wheelhouse/
|
|
13
|
+
.pipilot/
|
|
14
|
+
.provcheck/
|
|
15
|
+
.claude/
|
|
16
|
+
.codex/
|
|
17
|
+
.agents/
|
|
18
|
+
pi-python-core-design/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mario Zechner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pi-python-core is an independent Python implementation, not an official Pi release.
|
|
2
|
+
Agent execution and transcript behavior are adapted from earendil-works/pi:
|
|
3
|
+
https://github.com/earendil-works/pi/tree/a13d35a742c6ef8462812a28fbe1d8c8b7431c32
|
|
4
|
+
Copyright (c) 2025 Mario Zechner. MIT license; see LICENSE.
|
|
5
|
+
The complete upstream source is fetched only for development under reference/pi.
|
|
6
|
+
Provider request conversion (Claude Messages, OpenAI and Codex Responses), the cached
|
|
7
|
+
WebSocket continuation, transcript replay helpers and the context estimate/shortHash in
|
|
8
|
+
src/pi_python/estimate.py are adapted from packages/ai of the same commit.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pi-python-core
|
|
3
|
+
Version: 0.8.1
|
|
4
|
+
Summary: An embeddable asyncio agent core with opt-in Claude and OpenAI providers
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
License-File: NOTICE
|
|
8
|
+
Classifier: Framework :: AsyncIO
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: jsonschema<5,>=4.18
|
|
22
|
+
Provides-Extra: mcp
|
|
23
|
+
Requires-Dist: mcp>=1.10; extra == 'mcp'
|
|
24
|
+
Provides-Extra: providers
|
|
25
|
+
Requires-Dist: httpx<1,>=0.27; extra == 'providers'
|
|
26
|
+
Requires-Dist: pyjwt[crypto]<3,>=2.8; extra == 'providers'
|
|
27
|
+
Requires-Dist: websockets>=14.2; extra == 'providers'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# pi-python-core
|
|
31
|
+
|
|
32
|
+
一个可嵌入的 Python agent 核心,移植自 [Pi](https://github.com/earendil-works/pi)(固定参照 `v1.0.0`)。它负责一件事:把对话发给模型,执行模型要求的工具,把结果交回模型,直到得到回答。工具就是普通的 Python 函数;模型可以是 Claude、GPT、DeepSeek,也可以是本机或集群上的开源模型。
|
|
33
|
+
|
|
34
|
+
PyPI 上的 `pi-agent-core` 是另一个独立项目,移植的是 2026 年初 pi-mono 中的旧版本。本库对照 Pi v1.0.0 的行为,与上游的实际运行结果逐组比较;并自带 Claude、OpenAI、DeepSeek 和本地模型的接入,不需要安装任何模型 SDK。
|
|
35
|
+
|
|
36
|
+
## 安装
|
|
37
|
+
|
|
38
|
+
支持 Python 3.11–3.14(包括无 GIL 的 3.14t)和 PyPy 3.11,不需要 Node 或任何模型 SDK。
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install 'pi-python-core[providers]' # 或 uv add 'pi-python-core[providers]'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
安装名是 `pi-python-core`,导入名是 `pi_python`。
|
|
45
|
+
|
|
46
|
+
| 安装选项 | 带来什么 |
|
|
47
|
+
|---|---|
|
|
48
|
+
| 不加选项 | 执行核心,只依赖 `jsonschema` |
|
|
49
|
+
| `[providers]` | 真实模型接入:Claude、OpenAI、Codex、DeepSeek,以及任何 OpenAI 兼容服务(Ollama、vLLM、llama.cpp 等) |
|
|
50
|
+
| `[mcp]` | 把 MCP 服务器的工具交给 agent |
|
|
51
|
+
|
|
52
|
+
依赖写的是版本范围而不是固定版本,能和大多数已有环境共存。
|
|
53
|
+
|
|
54
|
+
## 五分钟上手
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from pi_python import Agent, tool
|
|
58
|
+
from pi_python.providers import AnthropicProvider
|
|
59
|
+
|
|
60
|
+
@tool
|
|
61
|
+
def word_count(text: str) -> int:
|
|
62
|
+
"""Count the words in a text."""
|
|
63
|
+
return len(text.split())
|
|
64
|
+
|
|
65
|
+
agent = Agent(provider=AnthropicProvider(api_key="..."), model="claude-sonnet-4-5", tools=[word_count])
|
|
66
|
+
result = agent.prompt_sync("How many words are in 'to be or not to be'?")
|
|
67
|
+
print(result.messages[-1].content[0].text)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`@tool` 从函数签名和文档字符串生成工具;普通函数和 `async` 函数都可以。在异步程序里用 `await agent.prompt(...)`。换成本地模型只改两行:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from pi_python.providers import OpenAICompletionsProvider
|
|
74
|
+
|
|
75
|
+
llm = OpenAICompletionsProvider(base_url="http://localhost:11434/v1", name="ollama")
|
|
76
|
+
agent = Agent(provider=llm, model=llm.model("qwen3:8b", context_window=40960), tools=[word_count])
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
不联网也能先跑起来:`python examples/quickstart.py`。
|
|
80
|
+
|
|
81
|
+
## 能做什么
|
|
82
|
+
|
|
83
|
+
| 需要 | 怎么做 | 示例 |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| 写工具 | `@tool` 装饰普通函数;pydantic 模型、dataclass、枚举、日期等参数自动转换;也接受手写或 MCP 生成的 JSON Schema | [quickstart](examples/quickstart.py) |
|
|
86
|
+
| 接模型 | Claude 与 GPT 的 API key 或订阅登录;DeepSeek;任何 OpenAI 兼容服务 | [local_model](examples/local_model.py),[provider_chat](examples/provider_chat.py) |
|
|
87
|
+
| 用 MCP 工具 | `async with connect_stdio(...) as tools` | [mcp_tools](examples/mcp_tools.py) |
|
|
88
|
+
| 让一个 agent 调用另一个 | 把子 agent 包成工具,取消会一路传下去 | [subagent](examples/subagent.py) |
|
|
89
|
+
| 中途干预 | `steer` 插入指导,`follow_up` 排队后续任务,`abort` 随时取消(任何线程都可以调用) | |
|
|
90
|
+
| 上下文满了、服务出错 | `is_context_overflow`、`is_retryable_error` 判断原因,`continue_run()` 重试,`transform_context` 压缩 | [recovery](examples/recovery.py) |
|
|
91
|
+
| 保存与恢复对话 | `encode_messages` / `decode_messages`,应用决定存在哪里 | [save_restore](examples/save_restore.py) |
|
|
92
|
+
| 观察与审计 | 订阅事件;执行前后的钩子可以阻止、改写工具调用 | |
|
|
93
|
+
|
|
94
|
+
除 `provider_chat` 需要真实凭据外,示例都能离线运行,不需要 API key;测试会逐个运行它们。
|
|
95
|
+
|
|
96
|
+
## 与 Pi 的关系
|
|
97
|
+
|
|
98
|
+
执行循环、事件顺序、钩子、队列、出错与取消的处理都与 Pi 一致,并用差分验证:同一组输入分别交给固定版本的上游代码和本库运行,逐项比较模型请求、工具调用、事件和最终记录。目前核心循环 25 组、模型接入 50 组、WebSocket 多轮 2 组、出错判断 44 条样例全部一致。
|
|
99
|
+
|
|
100
|
+
有几处是有意的差异,例如工具参数严格校验、不自动转换类型,返回给调用者的状态是副本;另一些是为 Python 用户加的,例如 `@tool`、同步调用、失败后直接 `continue_run()`。逐项记录见[验收映射](compat/COVERAGE.md)。Pi 放在应用层的功能(终端界面、会话文件格式、上下文压缩)不在本库核心里;压缩可以用钩子实现,示例里有完整做法。本项目使用自己的版本号,并非 Pi 官方发行版。
|
|
101
|
+
|
|
102
|
+
## 文档
|
|
103
|
+
|
|
104
|
+
- [一页看懂:五个概念和一轮的流程](docs/CONCEPTS.md)
|
|
105
|
+
- [公开 API](docs/API.md)
|
|
106
|
+
- [模型接入、订阅登录与本地模型](docs/PROVIDERS.md)
|
|
107
|
+
- [实施与验证结果](docs/IMPLEMENTATION.md)
|
|
108
|
+
- [与 Pi 的逐项对照和有意差异](compat/COVERAGE.md)
|
|
109
|
+
- [参照重建与候选版本验证](reference/README.md)
|
|
110
|
+
|
|
111
|
+
## 开发
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
uv sync --locked --extra providers --extra mcp
|
|
115
|
+
uv run pytest -q
|
|
116
|
+
uv run python scripts/verify.py # 全部检查,含与上游的差分(需要 Node)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
CI 配置在 `.github/workflows/ci.yml`,每次推送都在 GitHub Actions 上运行,覆盖 Linux 上的各个 Python 版本(含 3.14t 和 PyPy)以及 macOS 和 Windows。
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# pi-python-core
|
|
2
|
+
|
|
3
|
+
一个可嵌入的 Python agent 核心,移植自 [Pi](https://github.com/earendil-works/pi)(固定参照 `v1.0.0`)。它负责一件事:把对话发给模型,执行模型要求的工具,把结果交回模型,直到得到回答。工具就是普通的 Python 函数;模型可以是 Claude、GPT、DeepSeek,也可以是本机或集群上的开源模型。
|
|
4
|
+
|
|
5
|
+
PyPI 上的 `pi-agent-core` 是另一个独立项目,移植的是 2026 年初 pi-mono 中的旧版本。本库对照 Pi v1.0.0 的行为,与上游的实际运行结果逐组比较;并自带 Claude、OpenAI、DeepSeek 和本地模型的接入,不需要安装任何模型 SDK。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
支持 Python 3.11–3.14(包括无 GIL 的 3.14t)和 PyPy 3.11,不需要 Node 或任何模型 SDK。
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install 'pi-python-core[providers]' # 或 uv add 'pi-python-core[providers]'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
安装名是 `pi-python-core`,导入名是 `pi_python`。
|
|
16
|
+
|
|
17
|
+
| 安装选项 | 带来什么 |
|
|
18
|
+
|---|---|
|
|
19
|
+
| 不加选项 | 执行核心,只依赖 `jsonschema` |
|
|
20
|
+
| `[providers]` | 真实模型接入:Claude、OpenAI、Codex、DeepSeek,以及任何 OpenAI 兼容服务(Ollama、vLLM、llama.cpp 等) |
|
|
21
|
+
| `[mcp]` | 把 MCP 服务器的工具交给 agent |
|
|
22
|
+
|
|
23
|
+
依赖写的是版本范围而不是固定版本,能和大多数已有环境共存。
|
|
24
|
+
|
|
25
|
+
## 五分钟上手
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from pi_python import Agent, tool
|
|
29
|
+
from pi_python.providers import AnthropicProvider
|
|
30
|
+
|
|
31
|
+
@tool
|
|
32
|
+
def word_count(text: str) -> int:
|
|
33
|
+
"""Count the words in a text."""
|
|
34
|
+
return len(text.split())
|
|
35
|
+
|
|
36
|
+
agent = Agent(provider=AnthropicProvider(api_key="..."), model="claude-sonnet-4-5", tools=[word_count])
|
|
37
|
+
result = agent.prompt_sync("How many words are in 'to be or not to be'?")
|
|
38
|
+
print(result.messages[-1].content[0].text)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`@tool` 从函数签名和文档字符串生成工具;普通函数和 `async` 函数都可以。在异步程序里用 `await agent.prompt(...)`。换成本地模型只改两行:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from pi_python.providers import OpenAICompletionsProvider
|
|
45
|
+
|
|
46
|
+
llm = OpenAICompletionsProvider(base_url="http://localhost:11434/v1", name="ollama")
|
|
47
|
+
agent = Agent(provider=llm, model=llm.model("qwen3:8b", context_window=40960), tools=[word_count])
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
不联网也能先跑起来:`python examples/quickstart.py`。
|
|
51
|
+
|
|
52
|
+
## 能做什么
|
|
53
|
+
|
|
54
|
+
| 需要 | 怎么做 | 示例 |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| 写工具 | `@tool` 装饰普通函数;pydantic 模型、dataclass、枚举、日期等参数自动转换;也接受手写或 MCP 生成的 JSON Schema | [quickstart](examples/quickstart.py) |
|
|
57
|
+
| 接模型 | Claude 与 GPT 的 API key 或订阅登录;DeepSeek;任何 OpenAI 兼容服务 | [local_model](examples/local_model.py),[provider_chat](examples/provider_chat.py) |
|
|
58
|
+
| 用 MCP 工具 | `async with connect_stdio(...) as tools` | [mcp_tools](examples/mcp_tools.py) |
|
|
59
|
+
| 让一个 agent 调用另一个 | 把子 agent 包成工具,取消会一路传下去 | [subagent](examples/subagent.py) |
|
|
60
|
+
| 中途干预 | `steer` 插入指导,`follow_up` 排队后续任务,`abort` 随时取消(任何线程都可以调用) | |
|
|
61
|
+
| 上下文满了、服务出错 | `is_context_overflow`、`is_retryable_error` 判断原因,`continue_run()` 重试,`transform_context` 压缩 | [recovery](examples/recovery.py) |
|
|
62
|
+
| 保存与恢复对话 | `encode_messages` / `decode_messages`,应用决定存在哪里 | [save_restore](examples/save_restore.py) |
|
|
63
|
+
| 观察与审计 | 订阅事件;执行前后的钩子可以阻止、改写工具调用 | |
|
|
64
|
+
|
|
65
|
+
除 `provider_chat` 需要真实凭据外,示例都能离线运行,不需要 API key;测试会逐个运行它们。
|
|
66
|
+
|
|
67
|
+
## 与 Pi 的关系
|
|
68
|
+
|
|
69
|
+
执行循环、事件顺序、钩子、队列、出错与取消的处理都与 Pi 一致,并用差分验证:同一组输入分别交给固定版本的上游代码和本库运行,逐项比较模型请求、工具调用、事件和最终记录。目前核心循环 25 组、模型接入 50 组、WebSocket 多轮 2 组、出错判断 44 条样例全部一致。
|
|
70
|
+
|
|
71
|
+
有几处是有意的差异,例如工具参数严格校验、不自动转换类型,返回给调用者的状态是副本;另一些是为 Python 用户加的,例如 `@tool`、同步调用、失败后直接 `continue_run()`。逐项记录见[验收映射](compat/COVERAGE.md)。Pi 放在应用层的功能(终端界面、会话文件格式、上下文压缩)不在本库核心里;压缩可以用钩子实现,示例里有完整做法。本项目使用自己的版本号,并非 Pi 官方发行版。
|
|
72
|
+
|
|
73
|
+
## 文档
|
|
74
|
+
|
|
75
|
+
- [一页看懂:五个概念和一轮的流程](docs/CONCEPTS.md)
|
|
76
|
+
- [公开 API](docs/API.md)
|
|
77
|
+
- [模型接入、订阅登录与本地模型](docs/PROVIDERS.md)
|
|
78
|
+
- [实施与验证结果](docs/IMPLEMENTATION.md)
|
|
79
|
+
- [与 Pi 的逐项对照和有意差异](compat/COVERAGE.md)
|
|
80
|
+
- [参照重建与候选版本验证](reference/README.md)
|
|
81
|
+
|
|
82
|
+
## 开发
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv sync --locked --extra providers --extra mcp
|
|
86
|
+
uv run pytest -q
|
|
87
|
+
uv run python scripts/verify.py # 全部检查,含与上游的差分(需要 Node)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
CI 配置在 `.github/workflows/ci.yml`,每次推送都在 GitHub Actions 上运行,覆盖 Linux 上的各个 Python 版本(含 3.14t 和 PyPy)以及 macOS 和 Windows。
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# 验收映射
|
|
2
|
+
|
|
3
|
+
首期测试证明的是本文列出的文本和工具行为,不是完整 Pi 或模型智能。27 行是设计中的用例组,不是 27 个单独测试。具体测试总数与命令见 [验证记录](results/verification.json),逐 fixture 结果见 [差分记录](results/conformance.json)。
|
|
4
|
+
|
|
5
|
+
| 用例组 | Python 行为证据 | 上游证据 / 分类 |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| C01 文本与增量 | test_C01_stream_and_end | C01-text,mapped;增量一致性另作 D7 合同 |
|
|
8
|
+
| C02 工具结果进入请求 | test_C02_result_in_next_request_and_private_details | C02-tool,mapped |
|
|
9
|
+
| C03 串行顺序 | test_C03_C05_serial_batch | C03-sequential,mapped |
|
|
10
|
+
| C04 并发结束与提交顺序 | 两个 test_C04 测试,分别屏障控制执行与后置钩子 | C04-parallel,mapped |
|
|
11
|
+
| C05 任一串行影响整批 | test_C03_C05_serial_batch | C05-one-sequential,mapped |
|
|
12
|
+
| C06 普通失败保留同批成功 | test_C06_failure_does_not_cancel_sibling | C06-one-failure,mapped |
|
|
13
|
+
| C07 未知工具和非法参数 | test_C07_C08_D1_D2 与 schema 拒绝测试 | C07-unknown,mapped;严格验证为 D1 |
|
|
14
|
+
| C08 先准备再验证 | test_C07_C08_D1_D2 | C08-prepare,mapped |
|
|
15
|
+
| C09 阻止、替换和清除结构化结果 | test_C09_block_and_clear_structure;执行前钩子抛错见 test_failing_before_hook_is_a_tool_error_not_a_rejection | C09-block / C09-replace / C09-before-error,mapped;上游独立结构化替换测试通过 |
|
|
16
|
+
| C10 长度截断零执行 | test_C10_truncation_all_tools_fail_without_execution | C10-length,mapped |
|
|
17
|
+
| C11 transform 先于 convert | test_C11_transform_before_convert_defensive_copies | C11-transform,mapped;复制隔离为 D5 |
|
|
18
|
+
| C12 系统与工具声明重放 | test_C12_system_replay / runtime_tool_declarations_track_config | C12-system,mapped;上游 transcript-tool-changes 测试通过 |
|
|
19
|
+
| C13 指导的注入时点 | test_C13_C14_queues_and_modes | C13-steering,mapped |
|
|
20
|
+
| C14 后续队列与消费模式 | test_C13_C14_queues_and_modes | C14-followup-one / all,mapped |
|
|
21
|
+
| C15 准备钩子与配置持续 | 两个 test_C15 测试 | C15-prepare,mapped |
|
|
22
|
+
| C16 停止与继续 | 参数化 test_C16 与错误结束测试 | C16-mixed / terminate / continue / end,mapped |
|
|
23
|
+
| C17 重复请求和继续边界 | test_C17_busy_and_continue / continue_queued_final... | 上游 agent.test 中 prompt/continue 用例通过;Python API 映射测试 |
|
|
24
|
+
| C18 订阅后空闲和故障 | 三个 test_C18、结束订阅取消测试 | 上游 agent.test 的异步 listener/idle 用例通过;故障诊断为 D7 |
|
|
25
|
+
| C19 两种取消语义 | 参数化 test_C19、调度前取消测试、test_C20_abort_mid_stream_finishes_the_turn_with_partial_content | 显式 abort:C19-abort-stream / C19-abort-tools,mapped;外部 Task 取消为 D4 |
|
|
26
|
+
| C20 已完成保留、取消不锁定、显式未知不重放 | test_C20_abort_running_tool_is_an_error_result_and_agent_stays_usable、test_C20_explicit_unknown_stops_current_run 和后置阶段取消测试 | 取消运行中工具:C19-abort-tools,mapped;显式未知为 D4 |
|
|
27
|
+
| C21 超时、清理和上限 | 六个 test_C21(含默认不设上限)、延迟成功不得覆盖超时测试 | intentional_difference,D3/D4 |
|
|
28
|
+
| C22 原始执行和整理失败 | 参数化 test_C22 | intentional_difference,D6/D7 |
|
|
29
|
+
| C23 配置隔离和环境 | test_C15_C23 / test_C23_no_implicit_environment_configuration | intentional_difference,D5;运行更新持续另在 C15 差分 |
|
|
30
|
+
| C24 损坏流和能力拒绝 | 参数化 test_C24、尾部异常测试、两组 Provider 中途失败测试 | 供应商中途出错:C24-provider-error,mapped;损坏流拒绝为 D7/D8 |
|
|
31
|
+
| C25 JSON、版本、导入 | 两个 test_C25、事件编解码 | Python 合同;没有持久化或导入后自动执行 |
|
|
32
|
+
| C26 release 候选 | test_C26_noop_duplicate_and_synthetic_upgrade 及参数化拒绝测试 | 合成接口演练;独立远端校验脚本另存实际记录 |
|
|
33
|
+
| C27 wheel 安装 | Linux 容器内断网安装、示例、全部 pytest | 实际组合见 linux-3.11/3.12/3.13.json |
|
|
34
|
+
|
|
35
|
+
## 有意差异与范围外行为
|
|
36
|
+
|
|
37
|
+
D1–D8 保持原设计的含义。D1 严格输入;D2 执行前钩子不能通过原地修改参数改变调用;D3 资源预算;D4 Python 取消及未知结果;D5 状态复制;D6 输出检查;D7 诊断、原始结果和完整流校验;D8 文本与工具子集。每项有独立 Python 断言,不以 skip 代替验收。
|
|
38
|
+
|
|
39
|
+
范围外项目:真实模型 SDK、图片/音频/专有推理、OAuth、MCP 客户端、TUI/CLI、持久化与崩溃恢复、子 agent 管理器、Slurm/PBS,以及真实 HPC/科研任务效果。模型侧不支持的内容显式拒绝。上游真实模型 e2e、代理和其他应用测试未运行;它们不计入通过数。
|
|
40
|
+
|
|
41
|
+
## 已知验收边界
|
|
42
|
+
|
|
43
|
+
共享对照是 25 个脚本输入(0.5 时为 21 个)。上游 97 项选定单元测试证明参照可运行;它们不等价于 97 个 Python 差分输入。完整上游 API 和未覆盖输入没有兼容保证。无待解释的共享 fixture 差异;后续增加行为时,应扩充 fixture 再扩大声明。
|
|
44
|
+
|
|
45
|
+
## 0.2 范围修订
|
|
46
|
+
|
|
47
|
+
上述“首期范围外”是 0.1 的历史边界。根据用户追加要求,0.2 已将图片、供应商推理、Claude/OpenAI Provider、OAuth、streamProxy、独立循环和便利 API 纳入实现,D8 相应扩大。D1–D7 保持。
|
|
48
|
+
|
|
49
|
+
新增 Python 合同见 `test_extended_core.py`、`test_providers.py`、`test_oauth.py`。8 个共享网络流输入在 `provider-fixtures/`,实际上游解析器输出和 Python 输出保存在 [provider-conformance.json](results/provider-conformance.json)。它们对比最终内容、签名和停止原因,不等价于所有供应商请求选项或真实账号端到端兼容。
|
|
50
|
+
|
|
51
|
+
当前边界与明确差异见 [PROVIDERS.md](../docs/PROVIDERS.md)。0.1 的 accepted baseline 保留为历史核心验收记录,新增能力单独记录,不修改固定上游提交。
|
|
52
|
+
|
|
53
|
+
## 0.3 范围修订
|
|
54
|
+
|
|
55
|
+
当前数据合同使用 schema 3,支持完整文本/推理/工具块事件、模型诊断与响应元数据、工具 details/usage/nested_calls、系统文本块和完整工具钩子上下文。新增测试见 `test_contract_v3.py`。D8 再次扩大;D1 严格校验、D5 状态副本、D4/D7 未知结果不重放继续保留,不能列为缺失功能。
|
|
56
|
+
|
|
57
|
+
Provider 差分从 8 组扩大到 22 组,增加完整请求体、语义请求头和事件顺序/载荷,包含 Codex、签名重放、图片、工具 schema、缓存与推理参数。`test_models.py` 验证能力表,`test_recovery.py` 验证重试边界、取消、握手回退、账号隔离、连接复用和重复响应头。真实联调及未覆盖项以 [当前实施报告](../docs/IMPLEMENTATION.md) 为准;上面的 0.1/0.2 范围描述仅作历史记录。
|
|
58
|
+
|
|
59
|
+
## 0.4 范围修订
|
|
60
|
+
|
|
61
|
+
请求转换改为逐项移植上游 `buildParams`、`convertMessages`、`convertResponsesMessages` 和 Codex 请求体构造,并按模型表能力原位发送会话中途的系统指令、工具增删和推理强度。新增 12 组 Provider 差分使用真实模型记录和上游 `streamSimple` 入口,旧 22 组保持通过;新增 2 组 WebSocket 多轮差分对照增量请求和一次性重试。Python 合同见 `test_session_changes.py` 与 `test_websocket_continuation.py`。上游 `anthropic-mid-conversation-effort` 与 `openai-codex-stream` 测试加入参照验证。
|
|
62
|
+
|
|
63
|
+
D1–D8 不变。本轮明确记录的差异:WebSocket 帧不带 `stream` 字段;请求发出后的 WebSocket 故障不回退 SSE;同一会话的并发请求排队而不是另开一次性连接;Claude 推理预算不足 1024 时报配置错误而不是发送 1024;直接 OpenAI API 的 WebSocket 不使用增量请求(上游无此路径)。
|
|
64
|
+
|
|
65
|
+
## 0.5 结构修订
|
|
66
|
+
|
|
67
|
+
0.5 不改变执行行为,只减少并存的写法:Provider 事件只保留与上游相同的一套(`done` 取代 `final`,工具参数增量按块位置),所有 Provider 的事件经同一个检查器;模型能力只来自 `ModelInfo`,表外模型名在真实 Provider 中报错。旧的 20 组 Provider 输入改走上游 `streamSimple` 入口并使用与运行器相同的 `test-model` 记录,与 Agent 的实际调用路径一致;两组重放输入的历史回答补上了上游必需的 `usage` 字段。`agent.py` 拆为会话(Agent)、一次运行(Run)和输入队列三部分。核心 21 组、Provider 34 组、WebSocket 2 组差分保持通过。
|
|
68
|
+
|
|
69
|
+
## 0.6 修订:失败与取消对齐 Pi
|
|
70
|
+
|
|
71
|
+
检查发现三处没有写进文档的偏差,现已按上游改正,并各补一组差分:
|
|
72
|
+
|
|
73
|
+
| 情况 | 改正前 | 现在(与上游相同) | 差分 |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| 模型流中途出错 | 换成一条空的失败消息,供应商和模型名是 `mock`,已流出的内容和用量丢失 | 提交供应商给的失败消息,保留部分内容、身份和错误文字;`message_start` 只发一次 | C24-provider-error |
|
|
76
|
+
| 模型流中途被取消 | 不调用 `finish_turn`、不发 `turn_end`、不留回答 | 记一条 aborted 回答,照常调用 `finish_turn` 并发出 `turn_end` | C19-abort-stream |
|
|
77
|
+
| `before_tool_call` 抛异常 | 整个运行失败 | 该调用得到错误结果,模型继续 | C09-before-error |
|
|
78
|
+
|
|
79
|
+
同时改了两项设计选择:
|
|
80
|
+
- 取消运行中的工具按 Pi 处理:工具得到 `Operation aborted` 错误结果,批次收尾后再记一条不发请求的 aborted 回答,Agent 仍可使用(差分 C19-abort-tools)。工具超时同样记为错误结果,运行继续。只有工具主动抛 `ToolOutcomeUnknownError` 才停止运行并锁定实例。
|
|
81
|
+
- `RunLimits` 的模型请求数、工具调用数和工具并发数默认都不设上限,由应用设置;同一批工具默认全部同时执行,与上游的 `Promise.all` 相同。
|
|
82
|
+
|
|
83
|
+
为此扩展了两个运行器:响应可以先流出文本再失败或等待取消,操作可以是 `abort`,工具可以等到取消,执行前钩子可以抛错,`finish_turn` 调用被记录。比较规则新增一条映射:流式回答开始时的 `message_start` 不比较结束原因(上游此时为 `stop`,Python 为 `pending`);流中的部分快照不比较,只比较提交的消息。旧的 21 组输入未改,只有两组带 `finish_turn` 的结果多记录了这个钩子。
|
|
84
|
+
|
|
85
|
+
仍保留的取消差异,都在 Python 边界上:
|
|
86
|
+
- 外部取消 `prompt` 的 Task 时立即退出并重新抛 `CancelledError`,不追加 aborted 回答。
|
|
87
|
+
- 取消送达后最多等清理期限(默认 1 秒);逾期仍在运行的工具得到 `not_stopped` 结果,运行立即停止,实例不可再用。上游会一直等待工具结束。
|
|
88
|
+
- 串行批次或准备阶段被取消时,上游不给尚未准备的调用产生结果;本库为每个调用都产生 `Operation aborted` 结果,保持历史中没有悬空调用。
|
|
89
|
+
- 被取消的工具不调用 `after_tool_call`;上游会带着错误结果调用它。
|
|
90
|
+
|
|
91
|
+
## 0.7 修订:易用性与通用性
|
|
92
|
+
|
|
93
|
+
这一轮的目标是好装、多版本可用、容易在上面搭完整的 agent。按与上游的关系分三类记录。
|
|
94
|
+
|
|
95
|
+
与上游一致,并有对照证据:
|
|
96
|
+
- **Chat Completions 接入**:逐项移植 `openai-completions.ts`,新增 16 组 Provider 差分(Provider 差分共 50 组),覆盖 Ollama、vLLM、llama.cpp、OpenRouter、DeepSeek 等兼容配置和全部 11 种推理参数格式。与上游的差异见 [PROVIDERS](../docs/PROVIDERS.md#本地模型与-openai-兼容服务)。
|
|
97
|
+
- **出错判断**:`is_context_overflow`、`is_retryable_error`、`is_recoverable_length` 移植自 `overflow.ts` 和 `retry.ts`,44 条共享样例与上游函数的实际输出一致(`scripts/recovery_conformance.py`)。另外认识本库自己的错误格式:Python 网络错误名,以及按 HTTP 状态码判断本库的 HTTP 错误;上游格式的文字仍按上游规则判断。
|
|
98
|
+
- **工具 schema**:不再只接受一个子集。与上游一样接受 draft-07 等标准 schema,并按 `format`、`pattern` 校验参数(已用上游校验器对同一 schema 实测);仍只允许指向 schema 内部的引用。D1 的"不转换类型"不变。
|
|
99
|
+
- **HTTP 错误正文**:与上游一样保留,最多 4000 字符;本库另外把请求所带的凭据替换为 `[redacted]`。
|
|
100
|
+
|
|
101
|
+
Python 新增,上游核心没有对应:
|
|
102
|
+
- `@tool` 从带类型标注的函数生成工具;普通函数在工作线程运行;工具返回值自动转换。
|
|
103
|
+
- `prompt_sync`、`continue_run_sync`、`run_sync`:共享后台事件循环的阻塞调用。
|
|
104
|
+
- 最后一条回答失败或被取消时,`continue_run()` 直接重试。上游核心在这种情况下拒绝继续,Pi 的应用层先删掉失败回答再继续;本库保留失败回答,重放时跳过它。
|
|
105
|
+
- MCP 适配 `pi_python.mcp`。上游把 MCP 客户端放在独立包 pi-mcp,包装成工具的做法写在示例里;本库作为可选依赖 `[mcp]` 提供,内容转换规则与上游示例相同。
|
|
106
|
+
- `abort()` 可在任何线程调用;超过清理期限仍在运行的工具结束后,实例自动恢复可用;没有配置 Provider 时直接报错。
|
|
107
|
+
|
|
108
|
+
已知差异:
|
|
109
|
+
- 准备钩子抛错时,事件里会出现一个没有对应 `turn_start` 的 `turn_end`。上游 `handleRunFailure` 也是这样,保持一致。
|
|
110
|
+
- Python 和 JavaScript 的正则方言有细微差别,个别 `pattern` 的判断可能不同。
|
|
111
|
+
|
|
112
|
+
验证(0.7.0 发布时):Python 测试 308 项;核心差分 25 组、Provider 差分 50 组、WebSocket 差分 2 组、出错判断 44 条,全部与上游一致。Docker 内 Python 3.11–3.14 断网安装 wheel,各 304 项通过(4 项 MCP 测试因锁文件不含 MCP SDK 而跳过);本机安装后 3.14t 308 项、PyPy 3.11 304 项通过。依赖取最低版本(jsonschema 4.18、httpx 0.27、websockets 14.2、PyJWT 2.8)和最新版本都通过;MCP 适配在 SDK 1.10(它要求 jsonschema 4.20 以上)和 2.3 上都测过。macOS 和 Windows 只写进了 CI 配置,还没有实际运行;本机也没有运行中的本地模型服务,Chat Completions 接入尚未连接真实服务器。
|
|
113
|
+
|
|
114
|
+
## 0.8.1 跨平台修复
|
|
115
|
+
|
|
116
|
+
CI 第一次在 GitHub 上运行,Linux 和 macOS 全部通过,另外发现两处只在特定平台出现的问题:
|
|
117
|
+
|
|
118
|
+
- **Windows 读错文本文件。** Windows 默认按 cp1252 读文本,含中文的测试数据被读坏。库、compat、测试和示例里的文本读写现在都明确使用 UTF-8;库读取内置模型表时也一样(该文件目前全是 ASCII,以前没有出错)。凭据文件 `0o600` 权限的检查只在 POSIX 上进行,Windows 没有这种权限位。
|
|
119
|
+
- **PyPy 在极深的 schema 上崩溃。** 以前靠 `RecursionError` 拒绝嵌套过深的工具 schema。CPython 上实际上限随 schema 写法变化(`anyOf` 嵌套 81 层,`items` 嵌套 122 层),PyPy 的 JIT 偶尔在报错之前就撑爆底层栈,进程段错误退出。现在注册时先用非递归方式计数,对象和数组嵌套超过 100 层就报 `ConfigurationError`,在所有解释器上相同。上游 Pi 没有这项限制,属于本库新增的差异。代价是:嵌套超过 100 层、以前在 CPython 上能通过的 schema 现在被拒绝。以前子 schema 的嵌套最多能到 197 层,`default`、`const` 等数据值里的嵌套能到约 1000 层。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Development-only upstream verification. Not imported by the runtime package."""
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"status": "accepted",
|
|
4
|
+
"scope": "core-text-tools-v1",
|
|
5
|
+
"repository": "https://github.com/earendil-works/pi",
|
|
6
|
+
"release": {
|
|
7
|
+
"tag": "v1.0.0",
|
|
8
|
+
"commit": "a13d35a742c6ef8462812a28fbe1d8c8b7431c32"
|
|
9
|
+
},
|
|
10
|
+
"python_package_version": "0.1.0",
|
|
11
|
+
"qualification": "Acceptance covers declared fixtures and Python contracts; not complete Pi API compatibility.",
|
|
12
|
+
"evidence": {
|
|
13
|
+
"source": "results/source-verification.json",
|
|
14
|
+
"conformance": "results/conformance.json",
|
|
15
|
+
"checks": "results/verification.json",
|
|
16
|
+
"linux": [
|
|
17
|
+
"results/linux-3.11.json",
|
|
18
|
+
"results/linux-3.12.json",
|
|
19
|
+
"results/linux-3.13.json"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"intentional_differences": [
|
|
23
|
+
"D1",
|
|
24
|
+
"D2",
|
|
25
|
+
"D3",
|
|
26
|
+
"D4",
|
|
27
|
+
"D5",
|
|
28
|
+
"D6",
|
|
29
|
+
"D7",
|
|
30
|
+
"D8"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"candidate_id": "2729621761edb139a0fe2a185cb05b7e524e20338d759a79cd1c4404d995b271",
|
|
4
|
+
"repository": "https://github.com/earendil-works/pi",
|
|
5
|
+
"detected_at": "2026-10-02T00:00:00Z",
|
|
6
|
+
"base": {
|
|
7
|
+
"tag": "v1.0.0",
|
|
8
|
+
"commit": "a13d35a742c6ef8462812a28fbe1d8c8b7431c32"
|
|
9
|
+
},
|
|
10
|
+
"target": {
|
|
11
|
+
"tag": "v1.0.0",
|
|
12
|
+
"commit": "a13d35a742c6ef8462812a28fbe1d8c8b7431c32",
|
|
13
|
+
"published_at": "2026-10-01T19:20:55Z",
|
|
14
|
+
"release_url": "https://github.com/earendil-works/pi/releases/tag/v1.0.0",
|
|
15
|
+
"draft": false,
|
|
16
|
+
"prerelease": false
|
|
17
|
+
},
|
|
18
|
+
"changed_files": [],
|
|
19
|
+
"affected_areas": [],
|
|
20
|
+
"producer": "接口形状示例;目标等于基线,接收后应判为无需操作"
|
|
21
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Pi release 候选接口",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": [
|
|
7
|
+
"schema_version",
|
|
8
|
+
"candidate_id",
|
|
9
|
+
"repository",
|
|
10
|
+
"detected_at",
|
|
11
|
+
"base",
|
|
12
|
+
"target",
|
|
13
|
+
"changed_files",
|
|
14
|
+
"affected_areas"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"schema_version": {
|
|
18
|
+
"const": 1
|
|
19
|
+
},
|
|
20
|
+
"candidate_id": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"const": "https://github.com/earendil-works/pi"
|
|
26
|
+
},
|
|
27
|
+
"detected_at": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"format": "date-time"
|
|
30
|
+
},
|
|
31
|
+
"base": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"required": [
|
|
35
|
+
"tag",
|
|
36
|
+
"commit"
|
|
37
|
+
],
|
|
38
|
+
"properties": {
|
|
39
|
+
"tag": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"minLength": 1
|
|
42
|
+
},
|
|
43
|
+
"commit": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"pattern": "^[0-9a-f]{40}$"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"target": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"required": [
|
|
53
|
+
"tag",
|
|
54
|
+
"commit",
|
|
55
|
+
"published_at",
|
|
56
|
+
"release_url",
|
|
57
|
+
"draft",
|
|
58
|
+
"prerelease"
|
|
59
|
+
],
|
|
60
|
+
"properties": {
|
|
61
|
+
"tag": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"minLength": 1
|
|
64
|
+
},
|
|
65
|
+
"commit": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"pattern": "^[0-9a-f]{40}$"
|
|
68
|
+
},
|
|
69
|
+
"published_at": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"format": "date-time"
|
|
72
|
+
},
|
|
73
|
+
"release_url": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"pattern": "^https://github\\.com/earendil-works/pi/releases/tag/[^/]+$"
|
|
76
|
+
},
|
|
77
|
+
"draft": {
|
|
78
|
+
"const": false
|
|
79
|
+
},
|
|
80
|
+
"prerelease": {
|
|
81
|
+
"const": false
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"changed_files": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"items": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"additionalProperties": false,
|
|
90
|
+
"required": [
|
|
91
|
+
"path",
|
|
92
|
+
"change",
|
|
93
|
+
"sha256_before",
|
|
94
|
+
"sha256_after"
|
|
95
|
+
],
|
|
96
|
+
"properties": {
|
|
97
|
+
"path": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"minLength": 1,
|
|
100
|
+
"pattern": "^(?!/)(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
|
|
101
|
+
},
|
|
102
|
+
"previous_path": {
|
|
103
|
+
"type": "string",
|
|
104
|
+
"minLength": 1,
|
|
105
|
+
"pattern": "^(?!/)(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
|
|
106
|
+
},
|
|
107
|
+
"change": {
|
|
108
|
+
"enum": [
|
|
109
|
+
"added",
|
|
110
|
+
"modified",
|
|
111
|
+
"deleted",
|
|
112
|
+
"renamed"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
"sha256_before": {
|
|
116
|
+
"anyOf": [
|
|
117
|
+
{
|
|
118
|
+
"type": "string",
|
|
119
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "null"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
"sha256_after": {
|
|
127
|
+
"anyOf": [
|
|
128
|
+
{
|
|
129
|
+
"type": "string",
|
|
130
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"type": "null"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"affected_areas": {
|
|
141
|
+
"type": "array",
|
|
142
|
+
"uniqueItems": true,
|
|
143
|
+
"items": {
|
|
144
|
+
"enum": [
|
|
145
|
+
"agent_core",
|
|
146
|
+
"message_types",
|
|
147
|
+
"transcript",
|
|
148
|
+
"validation",
|
|
149
|
+
"dependencies",
|
|
150
|
+
"out_of_scope",
|
|
151
|
+
"unknown"
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"release_notes": {
|
|
156
|
+
"type": "string"
|
|
157
|
+
},
|
|
158
|
+
"producer": {
|
|
159
|
+
"type": "string"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|