pi-ai-python 1.3.0__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_ai_python-1.3.0/.gitignore +13 -0
- pi_ai_python-1.3.0/LICENSE +22 -0
- pi_ai_python-1.3.0/PKG-INFO +167 -0
- pi_ai_python-1.3.0/README.md +128 -0
- pi_ai_python-1.3.0/README.zh-CN.md +114 -0
- pi_ai_python-1.3.0/packages/agent/README.md +400 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/__init__.py +127 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/agent.py +617 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/agent_loop.py +820 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/proxy.py +269 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/py.typed +0 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/stream_fn.py +27 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/tools.py +327 -0
- pi_ai_python-1.3.0/packages/agent/src/pi_agent/types.py +394 -0
- pi_ai_python-1.3.0/packages/agent/tests/agent_helpers.py +251 -0
- pi_ai_python-1.3.0/packages/agent/tests/conftest.py +26 -0
- pi_ai_python-1.3.0/packages/agent/tests/test_agent.py +1113 -0
- pi_ai_python-1.3.0/packages/agent/tests/test_agent_loop.py +1522 -0
- pi_ai_python-1.3.0/packages/agent/tests/test_proxy.py +296 -0
- pi_ai_python-1.3.0/packages/agent/tests/test_tools.py +441 -0
- pi_ai_python-1.3.0/packages/ai/README.md +834 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/__init__.py +263 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/abort.py +315 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/__init__.py +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/anthropic_messages.py +1782 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/azure_openai_config.py +138 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/azure_openai_responses.py +245 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/bedrock_converse_stream.py +1598 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/classifier_shared.py +211 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/cloudflare.py +36 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/cloudflare_workers_ai_system_one.py +80 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/constrained_sampling.py +279 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/github_copilot_headers.py +30 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/google_generative_ai.py +138 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/google_shared.py +927 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/google_vertex.py +234 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/lazy.py +156 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/llama_cpp_classify.py +449 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/mistral_conversations.py +756 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openai_codex_responses.py +1545 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openai_completions.py +1594 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openai_decisions.py +210 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openai_prompt_cache.py +19 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openai_responses.py +418 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openai_responses_shared.py +840 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openai_sdk.py +204 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/openrouter_images.py +153 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/pi_messages.py +449 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/registry.py +103 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/simple_options.py +119 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/system_one_shared.py +148 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/transform_messages.py +211 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/api/typesafe_system_one.py +43 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/__init__.py +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/context.py +47 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/credential_store.py +208 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/helpers.py +123 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/__init__.py +5 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/_common.py +454 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/anthropic.py +283 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/callback_server.py +339 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/device_code.py +127 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/github_copilot.py +508 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/kimi_coding.py +283 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/load.py +64 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/meta.py +238 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/openai_chatgpt.py +321 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/openai_codex.py +391 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/openrouter.py +173 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/pkce.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/radius.py +311 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/oauth/xai.py +220 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/resolve.py +190 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/auth/types.py +292 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/cli.py +265 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/compat.py +651 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/env_api_keys.py +137 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/event_stream.py +329 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/models.py +1191 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/models_store.py +121 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/oauth.py +90 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/__init__.py +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/all.py +154 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/amazon_bedrock.py +116 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/ant_ling.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/anthropic.py +105 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/azure.py +103 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/baseten.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/catalog.py +167 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/cerebras.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/cloudflare_ai_gateway.py +30 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/cloudflare_auth.py +112 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/cloudflare_stream.py +84 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/cloudflare_workers_ai.py +26 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/amazon-bedrock.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/ant-ling.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/anthropic.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/azure.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/baseten.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/cerebras.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/cloudflare-ai-gateway.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/cloudflare-workers-ai.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/deepseek.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/fireworks.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/github-copilot.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/google-vertex.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/google.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/groq.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/huggingface.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/kimi-coding.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/manifest.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/meta.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/minimax-cn.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/minimax.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/mistral.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/moonshotai-cn.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/moonshotai.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/nvidia.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/openai-codex.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/openai.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/opencode-go.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/opencode.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/openrouter.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/qwen-token-plan-cn.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/qwen-token-plan-individual.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/qwen-token-plan.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/radius.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/together.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/typesafe.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/vercel-ai-gateway.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/xai.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/xiaomi-token-plan-ams.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/xiaomi-token-plan-cn.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/xiaomi-token-plan-sgp.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/xiaomi.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/zai-coding-cn.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/data/zai.json +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/deepseek.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/faux.py +680 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/fireworks.py +26 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/github_copilot.py +46 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/google.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/google_vertex.py +131 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/groq.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/huggingface.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/kimi_coding.py +32 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/meta.py +32 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/minimax.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/minimax_cn.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/mistral.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/moonshotai.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/moonshotai_cn.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/nvidia.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/openai.py +44 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/openai_codex.py +26 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/opencode.py +36 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/opencode_go.py +33 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/opencode_headers.py +60 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/openrouter.py +145 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/openrouter_api.py +122 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/qwen_token_plan.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/qwen_token_plan_cn.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/qwen_token_plan_individual.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/radius.py +146 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/radius_config.py +136 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/together.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/typesafe.py +22 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/vercel_ai_gateway.py +25 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/xai.py +32 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/xiaomi.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/xiaomi_token_plan_ams.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/xiaomi_token_plan_cn.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/xiaomi_token_plan_sgp.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/zai.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/providers/zai_coding_cn.py +23 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/py.typed +0 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/serialization.py +477 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/session_resources.py +33 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/types.py +1003 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/__init__.py +1 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/callbacks.py +15 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/diagnostics.py +70 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/error_body.py +89 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/estimate.py +125 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/fastjson.py +63 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/http.py +409 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/json_parse.py +424 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/misc.py +193 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/model_operations.py +73 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/models_error.py +35 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/oauth_page.py +121 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/overflow.py +87 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/retry.py +193 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/schema.py +283 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/text.py +65 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/transcript.py +271 -0
- pi_ai_python-1.3.0/packages/ai/src/pi_ai/utils/validation.py +813 -0
- pi_ai_python-1.3.0/packages/ai/tests/conftest.py +87 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_anthropic_client.py +610 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_anthropic_payload.py +1214 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_anthropic_sse_parsing.py +718 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_azure_openai_responses.py +248 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_bedrock_aws.py +746 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_bedrock_converse_stream.py +1247 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_cli.py +177 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_cloudflare_workers_ai_system_one.py +209 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_core_utils.py +611 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_event_stream.py +195 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_faux_provider.py +387 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_google_shared.py +799 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_google_streams.py +945 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_json_parse.py +129 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_llama_cpp_classify.py +439 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_mistral_conversations.py +705 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_models_runtime.py +1123 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_oauth.py +2234 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_openai_codex_responses.py +1196 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_openai_completions.py +1152 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_openai_decisions.py +264 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_openai_responses.py +1619 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_openrouter_images.py +235 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_pi_messages.py +529 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_providers.py +855 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_providers_auth.py +525 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_providers_streams.py +403 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_transcript.py +190 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_typesafe_system_one.py +337 -0
- pi_ai_python-1.3.0/packages/ai/tests/test_validation.py +194 -0
- pi_ai_python-1.3.0/pyproject.toml +123 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mario Zechner (pi, https://github.com/earendil-works/pi)
|
|
4
|
+
Copyright (c) 2026 nivalume (pi-py Python port)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pi-ai-python
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Python port of pi's AI libraries: a unified LLM API (pi_ai) and a stateful agent runtime (pi_agent)
|
|
5
|
+
Project-URL: Homepage, https://github.com/nivalume/pi-py
|
|
6
|
+
Project-URL: Source, https://github.com/nivalume/pi-py
|
|
7
|
+
Project-URL: Upstream, https://github.com/earendil-works/pi
|
|
8
|
+
Author: nivalume
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent,ai,anthropic,bedrock,gemini,llm,openai,streaming,tools
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Framework :: AsyncIO
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: anthropic>=1.15
|
|
22
|
+
Requires-Dist: google-genai>=2.31
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: openai>=3.35
|
|
25
|
+
Provides-Extra: all
|
|
26
|
+
Requires-Dist: boto3>=1.43; extra == 'all'
|
|
27
|
+
Requires-Dist: orjson>=3.10; extra == 'all'
|
|
28
|
+
Requires-Dist: pydantic>=2.6; extra == 'all'
|
|
29
|
+
Requires-Dist: websockets>=13; extra == 'all'
|
|
30
|
+
Provides-Extra: bedrock
|
|
31
|
+
Requires-Dist: boto3>=1.43; extra == 'bedrock'
|
|
32
|
+
Provides-Extra: fast
|
|
33
|
+
Requires-Dist: orjson>=3.10; extra == 'fast'
|
|
34
|
+
Provides-Extra: pydantic
|
|
35
|
+
Requires-Dist: pydantic>=2.6; extra == 'pydantic'
|
|
36
|
+
Provides-Extra: websocket
|
|
37
|
+
Requires-Dist: websockets>=13; extra == 'websocket'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# pi-py
|
|
41
|
+
|
|
42
|
+
Python port of [pi](https://github.com/earendil-works/pi)'s core libraries, published on
|
|
43
|
+
PyPI as one package, `pi-ai-python`, with two import packages:
|
|
44
|
+
|
|
45
|
+
| Import | Upstream | What it does |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| [`pi_ai`](https://github.com/nivalume/pi-py/blob/main/packages/ai/README.md) | `@earendil-works/pi-ai` | Unified LLM API: provider collections, auth resolution (API keys, OAuth), streaming events, token and cost tracking, tool calling, cross-provider context hand-off, image generation, classification |
|
|
48
|
+
| [`pi_agent`](https://github.com/nivalume/pi-py/blob/main/packages/agent/README.md) | `@earendil-works/pi-agent-core` | Stateful agent: tool execution (parallel or sequential), steering and follow-up queues, lifecycle events, hooks |
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install pi-ai-python # httpx + official SDKs: anthropic, openai, google-genai
|
|
52
|
+
pip install "pi-ai-python[bedrock]" # + boto3 for Amazon Bedrock
|
|
53
|
+
pip install "pi-ai-python[all]" # + orjson, websockets, pydantic, boto3
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
中文说明见 [README.zh-CN.md](https://github.com/nivalume/pi-py/blob/main/README.zh-CN.md)。
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
|
|
61
|
+
from pi_ai import Context, UserMessage
|
|
62
|
+
from pi_ai.providers.all import builtin_models
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
async def main() -> None:
|
|
66
|
+
models = builtin_models() # every built-in provider; auth comes from env vars such as ANTHROPIC_API_KEY
|
|
67
|
+
model = models.get_model("anthropic", "claude-sonnet-4-5")
|
|
68
|
+
stream = models.stream(model, Context(system_prompt="Be brief.", messages=[UserMessage("Hello!")]))
|
|
69
|
+
async for event in stream:
|
|
70
|
+
if event.type == "text_delta":
|
|
71
|
+
print(event.delta, end="", flush=True)
|
|
72
|
+
message = await stream.result()
|
|
73
|
+
print(f"\n{message.usage.input} in / {message.usage.output} out, ${message.usage.cost.total:.4f}")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
asyncio.run(main())
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from pi_agent import Agent, AgentInitialState, agent_tool
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@agent_tool
|
|
84
|
+
async def get_time(timezone: str = "UTC") -> str:
|
|
85
|
+
"""Get the current time.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
timezone: IANA timezone name.
|
|
89
|
+
"""
|
|
90
|
+
...
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
agent = Agent(
|
|
94
|
+
initial_state=AgentInitialState(system_prompt="You are helpful.", model=model, tools=[get_time]),
|
|
95
|
+
stream_fn=models.stream_simple,
|
|
96
|
+
)
|
|
97
|
+
async for event in agent.events("What time is it in Tokyo?"):
|
|
98
|
+
print(event.type)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Same API, Python conventions
|
|
102
|
+
|
|
103
|
+
The port keeps pi's architecture and semantics: the same `Models`/`Provider`
|
|
104
|
+
runtime, the same event protocol (`start` → `text_delta`… → `done`/`error`), the
|
|
105
|
+
same transcript model (system prompt and tools carried by system messages), the
|
|
106
|
+
same auth precedence rules, the same model catalog, and the same agent loop.
|
|
107
|
+
Names follow Python conventions:
|
|
108
|
+
|
|
109
|
+
| TypeScript | Python |
|
|
110
|
+
| --- | --- |
|
|
111
|
+
| `createModels()`, `models.streamSimple(...)` | `create_models()`, `models.stream_simple(...)` |
|
|
112
|
+
| `{ apiKey, sessionId, maxTokens }` options | `api_key=..., session_id=..., max_tokens=...` keyword arguments (or a dict) |
|
|
113
|
+
| `message.stopReason`, `usage.cacheRead` | `message.stop_reason`, `usage.cache_read` |
|
|
114
|
+
| `{ role: "user", content: "hi", timestamp }` | `UserMessage("hi")` (timestamp defaults to now) |
|
|
115
|
+
| `Type.Object({...})` (TypeBox) | `Type.Object({...})` (built in) or a Pydantic model |
|
|
116
|
+
| `AbortController` / `signal` | `pi_ai.AbortController` / `signal=` |
|
|
117
|
+
| `for await (const e of stream)` / `await stream.result()` | `async for e in stream` / `await stream.result()` |
|
|
118
|
+
| `agent.continue()` | `agent.continue_()` (alias `agent.resume()`) |
|
|
119
|
+
|
|
120
|
+
String values that appear on the wire or in persisted transcripts are unchanged
|
|
121
|
+
(`"toolUse"`, `"toolResult"`, `"text_delta"`, API ids, provider ids), and
|
|
122
|
+
`pi_ai.serialization` reads and writes pi's camelCase JSON, so sessions, model
|
|
123
|
+
definitions and `auth.json` credential files are interchangeable with TypeScript pi.
|
|
124
|
+
|
|
125
|
+
## Design notes
|
|
126
|
+
|
|
127
|
+
* **Official vendor SDKs.** As in pi, the Anthropic, OpenAI (Chat Completions,
|
|
128
|
+
Responses, Azure, OpenRouter images), Google (Gemini, Vertex) and Bedrock adapters use
|
|
129
|
+
the vendors' official SDKs: `anthropic`, `openai`, `google-genai` and `boto3`
|
|
130
|
+
(`pi-ai-python[bedrock]`). The SDK clients share one pooled `httpx.AsyncClient` per event loop.
|
|
131
|
+
APIs that pi calls without an SDK (Mistral, OpenAI Codex, pi-messages, classifiers)
|
|
132
|
+
use `httpx` directly.
|
|
133
|
+
* **Fast streaming path.** Slotted data classes, an allocation-light event queue,
|
|
134
|
+
zero-copy forwarding between wrapped streams, an incremental partial-JSON parser
|
|
135
|
+
for tool-call arguments (about 60x faster than re-parsing each delta on large
|
|
136
|
+
arguments), linear-time accumulation of streamed text, optional `orjson` decoding,
|
|
137
|
+
and compiled, cached tool-argument validators. On one core the anthropic-messages
|
|
138
|
+
adapter processes about 110,000 stream events per second and openai-completions about
|
|
139
|
+
70,000, where the openai SDK's SSE decoder is the limit (see `benchmarks/`).
|
|
140
|
+
* **Lazy everything.** Model catalogs load per provider on first use; API
|
|
141
|
+
implementations and OAuth flows import on first request.
|
|
142
|
+
* **Async-native cancellation.** `AbortSignal` aborts interrupt pending network reads
|
|
143
|
+
immediately (task cancellation scoped by `abort_scope`), and aborted requests end
|
|
144
|
+
their stream with `stop_reason == "aborted"` instead of raising.
|
|
145
|
+
* **Python-friendly additions.** Pydantic models as tool parameter schemas,
|
|
146
|
+
`@agent_tool` to build tools from typed functions, `Agent.events()` as an async
|
|
147
|
+
iterator, `FileCredentialStore` (pi's `auth.json` format with cross-process locking),
|
|
148
|
+
keyword-argument options, streams that can be created outside an event loop and
|
|
149
|
+
closed with `async with`.
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
uv sync # create .venv with the package (editable) and dev tools
|
|
155
|
+
uv run pytest # run all tests (offline; HTTP is mocked)
|
|
156
|
+
uv run ruff check . && uv run ruff format --check .
|
|
157
|
+
uv run pyright
|
|
158
|
+
uv run python benchmarks/bench_partial_json.py
|
|
159
|
+
uv run python benchmarks/bench_stream.py
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Model catalog data (`packages/ai/src/pi_ai/providers/data/*.json`) is the generated
|
|
163
|
+
catalog shipped with `@earendil-works/pi-ai` 1.3.0.
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT. Based on pi by Mario Zechner and contributors.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# pi-py
|
|
2
|
+
|
|
3
|
+
Python port of [pi](https://github.com/earendil-works/pi)'s core libraries, published on
|
|
4
|
+
PyPI as one package, `pi-ai-python`, with two import packages:
|
|
5
|
+
|
|
6
|
+
| Import | Upstream | What it does |
|
|
7
|
+
| --- | --- | --- |
|
|
8
|
+
| [`pi_ai`](https://github.com/nivalume/pi-py/blob/main/packages/ai/README.md) | `@earendil-works/pi-ai` | Unified LLM API: provider collections, auth resolution (API keys, OAuth), streaming events, token and cost tracking, tool calling, cross-provider context hand-off, image generation, classification |
|
|
9
|
+
| [`pi_agent`](https://github.com/nivalume/pi-py/blob/main/packages/agent/README.md) | `@earendil-works/pi-agent-core` | Stateful agent: tool execution (parallel or sequential), steering and follow-up queues, lifecycle events, hooks |
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install pi-ai-python # httpx + official SDKs: anthropic, openai, google-genai
|
|
13
|
+
pip install "pi-ai-python[bedrock]" # + boto3 for Amazon Bedrock
|
|
14
|
+
pip install "pi-ai-python[all]" # + orjson, websockets, pydantic, boto3
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
中文说明见 [README.zh-CN.md](https://github.com/nivalume/pi-py/blob/main/README.zh-CN.md)。
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
|
|
22
|
+
from pi_ai import Context, UserMessage
|
|
23
|
+
from pi_ai.providers.all import builtin_models
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def main() -> None:
|
|
27
|
+
models = builtin_models() # every built-in provider; auth comes from env vars such as ANTHROPIC_API_KEY
|
|
28
|
+
model = models.get_model("anthropic", "claude-sonnet-4-5")
|
|
29
|
+
stream = models.stream(model, Context(system_prompt="Be brief.", messages=[UserMessage("Hello!")]))
|
|
30
|
+
async for event in stream:
|
|
31
|
+
if event.type == "text_delta":
|
|
32
|
+
print(event.delta, end="", flush=True)
|
|
33
|
+
message = await stream.result()
|
|
34
|
+
print(f"\n{message.usage.input} in / {message.usage.output} out, ${message.usage.cost.total:.4f}")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
asyncio.run(main())
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from pi_agent import Agent, AgentInitialState, agent_tool
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@agent_tool
|
|
45
|
+
async def get_time(timezone: str = "UTC") -> str:
|
|
46
|
+
"""Get the current time.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
timezone: IANA timezone name.
|
|
50
|
+
"""
|
|
51
|
+
...
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
agent = Agent(
|
|
55
|
+
initial_state=AgentInitialState(system_prompt="You are helpful.", model=model, tools=[get_time]),
|
|
56
|
+
stream_fn=models.stream_simple,
|
|
57
|
+
)
|
|
58
|
+
async for event in agent.events("What time is it in Tokyo?"):
|
|
59
|
+
print(event.type)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Same API, Python conventions
|
|
63
|
+
|
|
64
|
+
The port keeps pi's architecture and semantics: the same `Models`/`Provider`
|
|
65
|
+
runtime, the same event protocol (`start` → `text_delta`… → `done`/`error`), the
|
|
66
|
+
same transcript model (system prompt and tools carried by system messages), the
|
|
67
|
+
same auth precedence rules, the same model catalog, and the same agent loop.
|
|
68
|
+
Names follow Python conventions:
|
|
69
|
+
|
|
70
|
+
| TypeScript | Python |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `createModels()`, `models.streamSimple(...)` | `create_models()`, `models.stream_simple(...)` |
|
|
73
|
+
| `{ apiKey, sessionId, maxTokens }` options | `api_key=..., session_id=..., max_tokens=...` keyword arguments (or a dict) |
|
|
74
|
+
| `message.stopReason`, `usage.cacheRead` | `message.stop_reason`, `usage.cache_read` |
|
|
75
|
+
| `{ role: "user", content: "hi", timestamp }` | `UserMessage("hi")` (timestamp defaults to now) |
|
|
76
|
+
| `Type.Object({...})` (TypeBox) | `Type.Object({...})` (built in) or a Pydantic model |
|
|
77
|
+
| `AbortController` / `signal` | `pi_ai.AbortController` / `signal=` |
|
|
78
|
+
| `for await (const e of stream)` / `await stream.result()` | `async for e in stream` / `await stream.result()` |
|
|
79
|
+
| `agent.continue()` | `agent.continue_()` (alias `agent.resume()`) |
|
|
80
|
+
|
|
81
|
+
String values that appear on the wire or in persisted transcripts are unchanged
|
|
82
|
+
(`"toolUse"`, `"toolResult"`, `"text_delta"`, API ids, provider ids), and
|
|
83
|
+
`pi_ai.serialization` reads and writes pi's camelCase JSON, so sessions, model
|
|
84
|
+
definitions and `auth.json` credential files are interchangeable with TypeScript pi.
|
|
85
|
+
|
|
86
|
+
## Design notes
|
|
87
|
+
|
|
88
|
+
* **Official vendor SDKs.** As in pi, the Anthropic, OpenAI (Chat Completions,
|
|
89
|
+
Responses, Azure, OpenRouter images), Google (Gemini, Vertex) and Bedrock adapters use
|
|
90
|
+
the vendors' official SDKs: `anthropic`, `openai`, `google-genai` and `boto3`
|
|
91
|
+
(`pi-ai-python[bedrock]`). The SDK clients share one pooled `httpx.AsyncClient` per event loop.
|
|
92
|
+
APIs that pi calls without an SDK (Mistral, OpenAI Codex, pi-messages, classifiers)
|
|
93
|
+
use `httpx` directly.
|
|
94
|
+
* **Fast streaming path.** Slotted data classes, an allocation-light event queue,
|
|
95
|
+
zero-copy forwarding between wrapped streams, an incremental partial-JSON parser
|
|
96
|
+
for tool-call arguments (about 60x faster than re-parsing each delta on large
|
|
97
|
+
arguments), linear-time accumulation of streamed text, optional `orjson` decoding,
|
|
98
|
+
and compiled, cached tool-argument validators. On one core the anthropic-messages
|
|
99
|
+
adapter processes about 110,000 stream events per second and openai-completions about
|
|
100
|
+
70,000, where the openai SDK's SSE decoder is the limit (see `benchmarks/`).
|
|
101
|
+
* **Lazy everything.** Model catalogs load per provider on first use; API
|
|
102
|
+
implementations and OAuth flows import on first request.
|
|
103
|
+
* **Async-native cancellation.** `AbortSignal` aborts interrupt pending network reads
|
|
104
|
+
immediately (task cancellation scoped by `abort_scope`), and aborted requests end
|
|
105
|
+
their stream with `stop_reason == "aborted"` instead of raising.
|
|
106
|
+
* **Python-friendly additions.** Pydantic models as tool parameter schemas,
|
|
107
|
+
`@agent_tool` to build tools from typed functions, `Agent.events()` as an async
|
|
108
|
+
iterator, `FileCredentialStore` (pi's `auth.json` format with cross-process locking),
|
|
109
|
+
keyword-argument options, streams that can be created outside an event loop and
|
|
110
|
+
closed with `async with`.
|
|
111
|
+
|
|
112
|
+
## Development
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
uv sync # create .venv with the package (editable) and dev tools
|
|
116
|
+
uv run pytest # run all tests (offline; HTTP is mocked)
|
|
117
|
+
uv run ruff check . && uv run ruff format --check .
|
|
118
|
+
uv run pyright
|
|
119
|
+
uv run python benchmarks/bench_partial_json.py
|
|
120
|
+
uv run python benchmarks/bench_stream.py
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Model catalog data (`packages/ai/src/pi_ai/providers/data/*.json`) is the generated
|
|
124
|
+
catalog shipped with `@earendil-works/pi-ai` 1.3.0.
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT. Based on pi by Mario Zechner and contributors.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# pi-py
|
|
2
|
+
|
|
3
|
+
[pi](https://github.com/earendil-works/pi) 核心库的 Python 实现,包含两个模块:
|
|
4
|
+
|
|
5
|
+
| Import 名 | 对应上游 | 作用 |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| [`pi_ai`](packages/ai/README.md) | `@earendil-works/pi-ai` | 统一的 LLM API:provider 集合、鉴权解析(API key / OAuth)、流式事件、token 与费用统计、工具调用、跨 provider 上下文切换、图像生成、分类 |
|
|
8
|
+
| [`pi_agent`](packages/agent/README.md) | `@earendil-works/pi-agent-core` | 有状态 Agent:工具执行(并行/串行)、steering 与 follow-up 队列、生命周期事件、钩子 |
|
|
9
|
+
|
|
10
|
+
两者在 PyPI 上作为同一个包 `pi-ai-python` 发布。
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install pi-ai-python # 依赖 httpx 和官方 SDK:anthropic、openai、google-genai
|
|
16
|
+
pip install "pi-ai-python[bedrock]" # 可选:boto3,用于 Amazon Bedrock
|
|
17
|
+
pip install "pi-ai-python[fast]" # 可选:orjson 加速 JSON 解码
|
|
18
|
+
pip install "pi-ai-python[all]" # 可选:orjson + websockets + pydantic + boto3
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
开发环境:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
uv sync
|
|
25
|
+
uv run pytest
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 快速开始
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import asyncio
|
|
32
|
+
|
|
33
|
+
from pi_ai import Context, UserMessage
|
|
34
|
+
from pi_ai.providers.all import builtin_models
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def main() -> None:
|
|
38
|
+
models = builtin_models() # 注册全部内置 provider,鉴权读取 ANTHROPIC_API_KEY 等环境变量
|
|
39
|
+
model = models.get_model("anthropic", "claude-sonnet-4-5")
|
|
40
|
+
stream = models.stream(model, Context(system_prompt="回答要简洁。", messages=[UserMessage("你好!")]))
|
|
41
|
+
async for event in stream:
|
|
42
|
+
if event.type == "text_delta":
|
|
43
|
+
print(event.delta, end="", flush=True)
|
|
44
|
+
message = await stream.result()
|
|
45
|
+
print(f"\n输入 {message.usage.input} / 输出 {message.usage.output} tokens,费用 ${message.usage.cost.total:.4f}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
asyncio.run(main())
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Agent:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from pi_agent import Agent, AgentInitialState, agent_tool
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@agent_tool
|
|
58
|
+
async def get_weather(city: str) -> str:
|
|
59
|
+
"""查询天气。
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
city: 城市名。
|
|
63
|
+
"""
|
|
64
|
+
return f"{city}:晴,25°C"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
agent = Agent(
|
|
68
|
+
initial_state=AgentInitialState(system_prompt="你是一个助手。", model=model, tools=[get_weather]),
|
|
69
|
+
stream_fn=models.stream_simple,
|
|
70
|
+
)
|
|
71
|
+
async for event in agent.events("北京天气怎么样?"):
|
|
72
|
+
if event.type == "message_update" and event.assistant_message_event.type == "text_delta":
|
|
73
|
+
print(event.assistant_message_event.delta, end="")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 与 pi 保持一致的 API
|
|
77
|
+
|
|
78
|
+
架构与语义与 TypeScript 版一致:同样的 `Models`/`Provider` 运行时、同样的事件协议
|
|
79
|
+
(`start` → `text_delta`… → `done`/`error`)、同样的 transcript 模型(系统提示词和工具由
|
|
80
|
+
system message 承载)、同样的鉴权优先级、同样的模型目录和 Agent 循环。命名遵循 Python 习惯:
|
|
81
|
+
|
|
82
|
+
| TypeScript | Python |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `createModels()`、`models.streamSimple(...)` | `create_models()`、`models.stream_simple(...)` |
|
|
85
|
+
| `{ apiKey, sessionId, maxTokens }` | 关键字参数 `api_key=..., session_id=..., max_tokens=...`(也可传 dict) |
|
|
86
|
+
| `message.stopReason`、`usage.cacheRead` | `message.stop_reason`、`usage.cache_read` |
|
|
87
|
+
| `{ role: "user", content: "hi", timestamp }` | `UserMessage("hi")`(timestamp 默认为当前时间) |
|
|
88
|
+
| TypeBox `Type.Object({...})` | 内置 `Type.Object({...})` 或 Pydantic 模型 |
|
|
89
|
+
| `AbortController` / `signal` | `pi_ai.AbortController` / `signal=` |
|
|
90
|
+
| `agent.continue()` | `agent.continue_()`(别名 `agent.resume()`) |
|
|
91
|
+
|
|
92
|
+
线上协议和持久化中出现的字符串值保持不变(`"toolUse"`、`"toolResult"`、`"text_delta"`、API id、
|
|
93
|
+
provider id)。`pi_ai.serialization` 读写 pi 的 camelCase JSON,会话记录、模型定义和
|
|
94
|
+
`auth.json` 凭据文件都可以与 TypeScript 版互通。
|
|
95
|
+
|
|
96
|
+
## 设计改进
|
|
97
|
+
|
|
98
|
+
* **使用厂商官方 SDK**:与 pi 一致,Anthropic、OpenAI(Chat Completions、Responses、Azure、OpenRouter 图片)、
|
|
99
|
+
Google(Gemini、Vertex)和 Bedrock 适配器分别使用官方 SDK `anthropic`、`openai`、`google-genai`、`boto3`
|
|
100
|
+
(`pi-ai-python[bedrock]`),各 SDK 客户端共用每个事件循环一个的 `httpx.AsyncClient` 连接池。
|
|
101
|
+
pi 本身不经 SDK 调用的 API(Mistral、OpenAI Codex、pi-messages、分类器)直接使用 `httpx`。
|
|
102
|
+
* **性能**:slots 数据类、低分配的事件队列、包装流之间零拷贝转发、增量式部分 JSON 解析
|
|
103
|
+
(大参数工具调用比逐 delta 全量重解析快约 60 倍)、流式文本线性时间累加、可选 orjson、编译并缓存的参数校验器。
|
|
104
|
+
单核每秒处理流事件:anthropic-messages 约 11 万,openai-completions 约 7 万(瓶颈在 openai SDK 的 SSE 解码,见 `benchmarks/`)。
|
|
105
|
+
* **全面懒加载**:模型目录按 provider 首次访问时加载;API 实现和 OAuth 流程在首次请求时导入。
|
|
106
|
+
* **原生异步取消**:`AbortSignal` 可立即中断挂起的网络读取,被中止的请求以 `stop_reason == "aborted"` 结束而不是抛异常。
|
|
107
|
+
* **Python 友好的扩展**:Pydantic 模型作为工具参数、`@agent_tool` 从类型注解生成工具、`Agent.events()` 异步迭代器、
|
|
108
|
+
`FileCredentialStore`(pi 的 `auth.json` 格式,带跨进程锁)、事件循环外创建的流、`async with` 关闭流。
|
|
109
|
+
|
|
110
|
+
详细文档:[pi_ai](packages/ai/README.md)、[pi_agent](packages/agent/README.md)。
|
|
111
|
+
|
|
112
|
+
## 许可证
|
|
113
|
+
|
|
114
|
+
MIT,基于 Mario Zechner 等人的 pi。
|