pi-ai-python 1.3.0__py3-none-any.whl
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_agent/__init__.py +127 -0
- pi_agent/agent.py +617 -0
- pi_agent/agent_loop.py +820 -0
- pi_agent/proxy.py +269 -0
- pi_agent/py.typed +0 -0
- pi_agent/stream_fn.py +27 -0
- pi_agent/tools.py +327 -0
- pi_agent/types.py +394 -0
- pi_ai/__init__.py +263 -0
- pi_ai/abort.py +315 -0
- pi_ai/api/__init__.py +1 -0
- pi_ai/api/anthropic_messages.py +1782 -0
- pi_ai/api/azure_openai_config.py +138 -0
- pi_ai/api/azure_openai_responses.py +245 -0
- pi_ai/api/bedrock_converse_stream.py +1598 -0
- pi_ai/api/classifier_shared.py +211 -0
- pi_ai/api/cloudflare.py +36 -0
- pi_ai/api/cloudflare_workers_ai_system_one.py +80 -0
- pi_ai/api/constrained_sampling.py +279 -0
- pi_ai/api/github_copilot_headers.py +30 -0
- pi_ai/api/google_generative_ai.py +138 -0
- pi_ai/api/google_shared.py +927 -0
- pi_ai/api/google_vertex.py +234 -0
- pi_ai/api/lazy.py +156 -0
- pi_ai/api/llama_cpp_classify.py +449 -0
- pi_ai/api/mistral_conversations.py +756 -0
- pi_ai/api/openai_codex_responses.py +1545 -0
- pi_ai/api/openai_completions.py +1594 -0
- pi_ai/api/openai_decisions.py +210 -0
- pi_ai/api/openai_prompt_cache.py +19 -0
- pi_ai/api/openai_responses.py +418 -0
- pi_ai/api/openai_responses_shared.py +840 -0
- pi_ai/api/openai_sdk.py +204 -0
- pi_ai/api/openrouter_images.py +153 -0
- pi_ai/api/pi_messages.py +449 -0
- pi_ai/api/registry.py +103 -0
- pi_ai/api/simple_options.py +119 -0
- pi_ai/api/system_one_shared.py +148 -0
- pi_ai/api/transform_messages.py +211 -0
- pi_ai/api/typesafe_system_one.py +43 -0
- pi_ai/auth/__init__.py +1 -0
- pi_ai/auth/context.py +47 -0
- pi_ai/auth/credential_store.py +208 -0
- pi_ai/auth/helpers.py +123 -0
- pi_ai/auth/oauth/__init__.py +5 -0
- pi_ai/auth/oauth/_common.py +454 -0
- pi_ai/auth/oauth/anthropic.py +283 -0
- pi_ai/auth/oauth/callback_server.py +339 -0
- pi_ai/auth/oauth/device_code.py +127 -0
- pi_ai/auth/oauth/github_copilot.py +508 -0
- pi_ai/auth/oauth/kimi_coding.py +283 -0
- pi_ai/auth/oauth/load.py +64 -0
- pi_ai/auth/oauth/meta.py +238 -0
- pi_ai/auth/oauth/openai_chatgpt.py +321 -0
- pi_ai/auth/oauth/openai_codex.py +391 -0
- pi_ai/auth/oauth/openrouter.py +173 -0
- pi_ai/auth/oauth/pkce.py +23 -0
- pi_ai/auth/oauth/radius.py +311 -0
- pi_ai/auth/oauth/xai.py +220 -0
- pi_ai/auth/resolve.py +190 -0
- pi_ai/auth/types.py +292 -0
- pi_ai/cli.py +265 -0
- pi_ai/compat.py +651 -0
- pi_ai/env_api_keys.py +137 -0
- pi_ai/event_stream.py +329 -0
- pi_ai/models.py +1191 -0
- pi_ai/models_store.py +121 -0
- pi_ai/oauth.py +90 -0
- pi_ai/providers/__init__.py +1 -0
- pi_ai/providers/all.py +154 -0
- pi_ai/providers/amazon_bedrock.py +116 -0
- pi_ai/providers/ant_ling.py +23 -0
- pi_ai/providers/anthropic.py +105 -0
- pi_ai/providers/azure.py +103 -0
- pi_ai/providers/baseten.py +23 -0
- pi_ai/providers/catalog.py +167 -0
- pi_ai/providers/cerebras.py +23 -0
- pi_ai/providers/cloudflare_ai_gateway.py +30 -0
- pi_ai/providers/cloudflare_auth.py +112 -0
- pi_ai/providers/cloudflare_stream.py +84 -0
- pi_ai/providers/cloudflare_workers_ai.py +26 -0
- pi_ai/providers/data/amazon-bedrock.json +1 -0
- pi_ai/providers/data/ant-ling.json +1 -0
- pi_ai/providers/data/anthropic.json +1 -0
- pi_ai/providers/data/azure.json +1 -0
- pi_ai/providers/data/baseten.json +1 -0
- pi_ai/providers/data/cerebras.json +1 -0
- pi_ai/providers/data/cloudflare-ai-gateway.json +1 -0
- pi_ai/providers/data/cloudflare-workers-ai.json +1 -0
- pi_ai/providers/data/deepseek.json +1 -0
- pi_ai/providers/data/fireworks.json +1 -0
- pi_ai/providers/data/github-copilot.json +1 -0
- pi_ai/providers/data/google-vertex.json +1 -0
- pi_ai/providers/data/google.json +1 -0
- pi_ai/providers/data/groq.json +1 -0
- pi_ai/providers/data/huggingface.json +1 -0
- pi_ai/providers/data/kimi-coding.json +1 -0
- pi_ai/providers/data/manifest.json +1 -0
- pi_ai/providers/data/meta.json +1 -0
- pi_ai/providers/data/minimax-cn.json +1 -0
- pi_ai/providers/data/minimax.json +1 -0
- pi_ai/providers/data/mistral.json +1 -0
- pi_ai/providers/data/moonshotai-cn.json +1 -0
- pi_ai/providers/data/moonshotai.json +1 -0
- pi_ai/providers/data/nvidia.json +1 -0
- pi_ai/providers/data/openai-codex.json +1 -0
- pi_ai/providers/data/openai.json +1 -0
- pi_ai/providers/data/opencode-go.json +1 -0
- pi_ai/providers/data/opencode.json +1 -0
- pi_ai/providers/data/openrouter.json +1 -0
- pi_ai/providers/data/qwen-token-plan-cn.json +1 -0
- pi_ai/providers/data/qwen-token-plan-individual.json +1 -0
- pi_ai/providers/data/qwen-token-plan.json +1 -0
- pi_ai/providers/data/radius.json +1 -0
- pi_ai/providers/data/together.json +1 -0
- pi_ai/providers/data/typesafe.json +1 -0
- pi_ai/providers/data/vercel-ai-gateway.json +1 -0
- pi_ai/providers/data/xai.json +1 -0
- pi_ai/providers/data/xiaomi-token-plan-ams.json +1 -0
- pi_ai/providers/data/xiaomi-token-plan-cn.json +1 -0
- pi_ai/providers/data/xiaomi-token-plan-sgp.json +1 -0
- pi_ai/providers/data/xiaomi.json +1 -0
- pi_ai/providers/data/zai-coding-cn.json +1 -0
- pi_ai/providers/data/zai.json +1 -0
- pi_ai/providers/deepseek.py +23 -0
- pi_ai/providers/faux.py +680 -0
- pi_ai/providers/fireworks.py +26 -0
- pi_ai/providers/github_copilot.py +46 -0
- pi_ai/providers/google.py +23 -0
- pi_ai/providers/google_vertex.py +131 -0
- pi_ai/providers/groq.py +23 -0
- pi_ai/providers/huggingface.py +23 -0
- pi_ai/providers/kimi_coding.py +32 -0
- pi_ai/providers/meta.py +32 -0
- pi_ai/providers/minimax.py +23 -0
- pi_ai/providers/minimax_cn.py +23 -0
- pi_ai/providers/mistral.py +23 -0
- pi_ai/providers/moonshotai.py +23 -0
- pi_ai/providers/moonshotai_cn.py +23 -0
- pi_ai/providers/nvidia.py +23 -0
- pi_ai/providers/openai.py +44 -0
- pi_ai/providers/openai_codex.py +26 -0
- pi_ai/providers/opencode.py +36 -0
- pi_ai/providers/opencode_go.py +33 -0
- pi_ai/providers/opencode_headers.py +60 -0
- pi_ai/providers/openrouter.py +145 -0
- pi_ai/providers/openrouter_api.py +122 -0
- pi_ai/providers/qwen_token_plan.py +23 -0
- pi_ai/providers/qwen_token_plan_cn.py +23 -0
- pi_ai/providers/qwen_token_plan_individual.py +23 -0
- pi_ai/providers/radius.py +146 -0
- pi_ai/providers/radius_config.py +136 -0
- pi_ai/providers/together.py +23 -0
- pi_ai/providers/typesafe.py +22 -0
- pi_ai/providers/vercel_ai_gateway.py +25 -0
- pi_ai/providers/xai.py +32 -0
- pi_ai/providers/xiaomi.py +23 -0
- pi_ai/providers/xiaomi_token_plan_ams.py +23 -0
- pi_ai/providers/xiaomi_token_plan_cn.py +23 -0
- pi_ai/providers/xiaomi_token_plan_sgp.py +23 -0
- pi_ai/providers/zai.py +23 -0
- pi_ai/providers/zai_coding_cn.py +23 -0
- pi_ai/py.typed +0 -0
- pi_ai/serialization.py +477 -0
- pi_ai/session_resources.py +33 -0
- pi_ai/types.py +1003 -0
- pi_ai/utils/__init__.py +1 -0
- pi_ai/utils/callbacks.py +15 -0
- pi_ai/utils/diagnostics.py +70 -0
- pi_ai/utils/error_body.py +89 -0
- pi_ai/utils/estimate.py +125 -0
- pi_ai/utils/fastjson.py +63 -0
- pi_ai/utils/http.py +409 -0
- pi_ai/utils/json_parse.py +424 -0
- pi_ai/utils/misc.py +193 -0
- pi_ai/utils/model_operations.py +73 -0
- pi_ai/utils/models_error.py +35 -0
- pi_ai/utils/oauth_page.py +121 -0
- pi_ai/utils/overflow.py +87 -0
- pi_ai/utils/retry.py +193 -0
- pi_ai/utils/schema.py +283 -0
- pi_ai/utils/text.py +65 -0
- pi_ai/utils/transcript.py +271 -0
- pi_ai/utils/validation.py +813 -0
- pi_ai_python-1.3.0.dist-info/METADATA +167 -0
- pi_ai_python-1.3.0.dist-info/RECORD +189 -0
- pi_ai_python-1.3.0.dist-info/WHEEL +4 -0
- pi_ai_python-1.3.0.dist-info/entry_points.txt +2 -0
- pi_ai_python-1.3.0.dist-info/licenses/LICENSE +22 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""GitHub Copilot provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
|
|
7
|
+
from ..api.registry import anthropic_messages_api, openai_completions_api, openai_responses_api
|
|
8
|
+
from ..auth.helpers import env_api_key_auth, lazy_oauth
|
|
9
|
+
from ..auth.oauth.load import load_github_copilot_oauth
|
|
10
|
+
from ..auth.types import Credential, ProviderAuth
|
|
11
|
+
from ..models import Provider, create_provider
|
|
12
|
+
from ..types import Model
|
|
13
|
+
from .catalog import catalog_models
|
|
14
|
+
|
|
15
|
+
__all__ = ["github_copilot_provider"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _filter_models(models: Sequence[Model], credential: Credential | None) -> Sequence[Model]:
|
|
19
|
+
# OAuth credentials record the models the Copilot plan enables.
|
|
20
|
+
if credential is None or credential.get("type") != "oauth":
|
|
21
|
+
return models
|
|
22
|
+
available_model_ids = credential.get("availableModelIds")
|
|
23
|
+
if not isinstance(available_model_ids, list) or not all(isinstance(item, str) for item in available_model_ids):
|
|
24
|
+
return models
|
|
25
|
+
available = set(available_model_ids)
|
|
26
|
+
return [model for model in models if model.id in available]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def github_copilot_provider() -> Provider:
|
|
30
|
+
"""GitHub Copilot: ``COPILOT_GITHUB_TOKEN`` or a GitHub Copilot login (Anthropic/OpenAI APIs)."""
|
|
31
|
+
return create_provider(
|
|
32
|
+
id="github-copilot",
|
|
33
|
+
name="GitHub Copilot",
|
|
34
|
+
base_url="https://api.individual.githubcopilot.com",
|
|
35
|
+
auth=ProviderAuth(
|
|
36
|
+
api_key=env_api_key_auth("GitHub Copilot token", ["COPILOT_GITHUB_TOKEN"]),
|
|
37
|
+
oauth=lazy_oauth("GitHub Copilot", load_github_copilot_oauth, is_subscription=True),
|
|
38
|
+
),
|
|
39
|
+
models=lambda: catalog_models("github-copilot"),
|
|
40
|
+
filter_models=_filter_models,
|
|
41
|
+
api={
|
|
42
|
+
"anthropic-messages": anthropic_messages_api(),
|
|
43
|
+
"openai-completions": openai_completions_api(),
|
|
44
|
+
"openai-responses": openai_responses_api(),
|
|
45
|
+
},
|
|
46
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Google provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import google_generative_ai_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["google_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def google_provider() -> Provider:
|
|
15
|
+
"""Google (Gemini API), authenticated with ``GEMINI_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="google",
|
|
18
|
+
name="Google",
|
|
19
|
+
base_url="https://generativelanguage.googleapis.com/v1beta",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("Gemini API key", ["GEMINI_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("google"),
|
|
22
|
+
api=google_generative_ai_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""Google Vertex AI provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..abort import AbortSignal
|
|
6
|
+
from ..api.registry import google_vertex_api
|
|
7
|
+
from ..auth.types import (
|
|
8
|
+
ApiKeyAuth,
|
|
9
|
+
AuthContext,
|
|
10
|
+
AuthEvent,
|
|
11
|
+
AuthInfoLink,
|
|
12
|
+
AuthPrompt,
|
|
13
|
+
AuthResult,
|
|
14
|
+
AuthSelectOption,
|
|
15
|
+
Credential,
|
|
16
|
+
ModelAuth,
|
|
17
|
+
ProviderAuth,
|
|
18
|
+
ProviderAuthInteraction,
|
|
19
|
+
)
|
|
20
|
+
from ..models import Provider, create_provider
|
|
21
|
+
from .catalog import catalog_models
|
|
22
|
+
|
|
23
|
+
__all__ = ["google_vertex_provider", "vertex_auth", "VERTEX_ADC_PATH"]
|
|
24
|
+
|
|
25
|
+
VERTEX_ADC_PATH = "~/.config/gcloud/application_default_credentials.json"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def _login(interaction: ProviderAuthInteraction) -> Credential:
|
|
29
|
+
interaction.signal.throw_if_aborted()
|
|
30
|
+
method = await interaction.prompt(
|
|
31
|
+
AuthPrompt(
|
|
32
|
+
type="select",
|
|
33
|
+
message="Select Google Vertex AI authentication method:",
|
|
34
|
+
options=[
|
|
35
|
+
AuthSelectOption(id="api-key", label="Google Cloud API key"),
|
|
36
|
+
AuthSelectOption(id="adc", label="Application Default Credentials"),
|
|
37
|
+
AuthSelectOption(id="service-account", label="Service account credentials file"),
|
|
38
|
+
],
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
interaction.signal.throw_if_aborted()
|
|
42
|
+
if method == "api-key":
|
|
43
|
+
return {
|
|
44
|
+
"type": "api_key",
|
|
45
|
+
"key": await interaction.prompt(AuthPrompt(type="secret", message="Enter Google Cloud API key")),
|
|
46
|
+
}
|
|
47
|
+
if method not in ("adc", "service-account"):
|
|
48
|
+
raise ValueError(f"Unknown Google Vertex AI auth method: {method}")
|
|
49
|
+
interaction.notify(
|
|
50
|
+
AuthEvent(
|
|
51
|
+
type="info",
|
|
52
|
+
message=(
|
|
53
|
+
"Run `gcloud auth application-default login`, then provide the project and location."
|
|
54
|
+
if method == "adc"
|
|
55
|
+
else "Provide a service account credentials file, project, and location."
|
|
56
|
+
),
|
|
57
|
+
links=[
|
|
58
|
+
AuthInfoLink(
|
|
59
|
+
label="Application Default Credentials",
|
|
60
|
+
url="https://cloud.google.com/docs/authentication/provide-credentials-adc",
|
|
61
|
+
)
|
|
62
|
+
],
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
project = await interaction.prompt(AuthPrompt(type="text", message="Enter Google Cloud project ID"))
|
|
66
|
+
location = await interaction.prompt(AuthPrompt(type="text", message="Enter Google Cloud location"))
|
|
67
|
+
credentials_path = (
|
|
68
|
+
await interaction.prompt(AuthPrompt(type="text", message="Enter service account credentials file path"))
|
|
69
|
+
if method == "service-account"
|
|
70
|
+
else None
|
|
71
|
+
)
|
|
72
|
+
env = {"GOOGLE_CLOUD_PROJECT": project, "GOOGLE_CLOUD_LOCATION": location}
|
|
73
|
+
if credentials_path:
|
|
74
|
+
env["GOOGLE_APPLICATION_CREDENTIALS"] = credentials_path
|
|
75
|
+
return {"type": "api_key", "env": env}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def _resolve(*, ctx: AuthContext, credential: Credential | None, signal: AbortSignal) -> AuthResult | None:
|
|
79
|
+
async def env(name: str) -> str | None:
|
|
80
|
+
signal.throw_if_aborted()
|
|
81
|
+
value = await ctx.env(name)
|
|
82
|
+
signal.throw_if_aborted()
|
|
83
|
+
return value
|
|
84
|
+
|
|
85
|
+
stored_key = credential.get("key") if credential else None
|
|
86
|
+
key = stored_key if stored_key is not None else await env("GOOGLE_CLOUD_API_KEY")
|
|
87
|
+
if key:
|
|
88
|
+
return AuthResult(ModelAuth(api_key=key), source="stored credential" if stored_key else "GOOGLE_CLOUD_API_KEY")
|
|
89
|
+
|
|
90
|
+
credential_env = (credential.get("env") if credential else None) or {}
|
|
91
|
+
adc_path = credential_env.get("GOOGLE_APPLICATION_CREDENTIALS")
|
|
92
|
+
if adc_path is None:
|
|
93
|
+
adc_path = await env("GOOGLE_APPLICATION_CREDENTIALS")
|
|
94
|
+
signal.throw_if_aborted()
|
|
95
|
+
has_credentials = await ctx.file_exists(adc_path if adc_path is not None else VERTEX_ADC_PATH)
|
|
96
|
+
signal.throw_if_aborted()
|
|
97
|
+
project = credential_env.get("GOOGLE_CLOUD_PROJECT")
|
|
98
|
+
if project is None:
|
|
99
|
+
project = await env("GOOGLE_CLOUD_PROJECT")
|
|
100
|
+
if project is None:
|
|
101
|
+
project = await env("GCLOUD_PROJECT")
|
|
102
|
+
location = credential_env.get("GOOGLE_CLOUD_LOCATION")
|
|
103
|
+
if location is None:
|
|
104
|
+
location = await env("GOOGLE_CLOUD_LOCATION")
|
|
105
|
+
if has_credentials and project and location:
|
|
106
|
+
return AuthResult(
|
|
107
|
+
ModelAuth(),
|
|
108
|
+
env=credential.get("env") if credential else None,
|
|
109
|
+
source="stored credential" if credential else "gcloud application default credentials",
|
|
110
|
+
)
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def vertex_auth() -> ApiKeyAuth:
|
|
115
|
+
"""Vertex accepts an explicit API key or Application Default Credentials.
|
|
116
|
+
|
|
117
|
+
ADC (``gcloud auth application-default login``) additionally requires project
|
|
118
|
+
and location env vars, which the API implementation reads itself.
|
|
119
|
+
"""
|
|
120
|
+
return ApiKeyAuth("Google Cloud credentials", _resolve, login=_login)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def google_vertex_provider() -> Provider:
|
|
124
|
+
"""Google Vertex AI with ``GOOGLE_CLOUD_API_KEY`` or Application Default Credentials."""
|
|
125
|
+
return create_provider(
|
|
126
|
+
id="google-vertex",
|
|
127
|
+
name="Google Vertex AI",
|
|
128
|
+
auth=ProviderAuth(api_key=vertex_auth()),
|
|
129
|
+
models=lambda: catalog_models("google-vertex"),
|
|
130
|
+
api=google_vertex_api(),
|
|
131
|
+
)
|
pi_ai/providers/groq.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Groq provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_completions_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["groq_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def groq_provider() -> Provider:
|
|
15
|
+
"""Groq (OpenAI-compatible Chat Completions), authenticated with ``GROQ_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="groq",
|
|
18
|
+
name="Groq",
|
|
19
|
+
base_url="https://api.groq.com/openai/v1",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("Groq API key", ["GROQ_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("groq"),
|
|
22
|
+
api=openai_completions_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Hugging Face provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_completions_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["huggingface_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def huggingface_provider() -> Provider:
|
|
15
|
+
"""Hugging Face (OpenAI-compatible Chat Completions), authenticated with ``HF_TOKEN``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="huggingface",
|
|
18
|
+
name="Hugging Face",
|
|
19
|
+
base_url="https://router.huggingface.co/v1",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("Hugging Face token", ["HF_TOKEN"])),
|
|
21
|
+
models=lambda: catalog_models("huggingface"),
|
|
22
|
+
api=openai_completions_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Kimi For Coding provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_completions_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth, lazy_oauth
|
|
7
|
+
from ..auth.oauth.load import load_kimi_coding_oauth
|
|
8
|
+
from ..auth.types import ProviderAuth
|
|
9
|
+
from ..models import Provider, create_provider
|
|
10
|
+
from .catalog import catalog_models
|
|
11
|
+
|
|
12
|
+
__all__ = ["kimi_coding_provider"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def kimi_coding_provider() -> Provider:
|
|
16
|
+
"""Kimi For Coding: ``KIMI_API_KEY`` or a Kimi Code subscription login."""
|
|
17
|
+
return create_provider(
|
|
18
|
+
id="kimi-coding",
|
|
19
|
+
name="Kimi For Coding",
|
|
20
|
+
base_url="https://api.kimi.com/coding/v1",
|
|
21
|
+
auth=ProviderAuth(
|
|
22
|
+
api_key=env_api_key_auth("Kimi API key", ["KIMI_API_KEY"]),
|
|
23
|
+
oauth=lazy_oauth(
|
|
24
|
+
"Kimi Code (subscription)",
|
|
25
|
+
load_kimi_coding_oauth,
|
|
26
|
+
is_subscription=True,
|
|
27
|
+
login_label="Sign in with Kimi Code",
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
models=lambda: catalog_models("kimi-coding"),
|
|
31
|
+
api=openai_completions_api(),
|
|
32
|
+
)
|
pi_ai/providers/meta.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Meta provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_responses_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth, lazy_oauth
|
|
7
|
+
from ..auth.oauth.load import load_meta_oauth
|
|
8
|
+
from ..auth.types import ProviderAuth
|
|
9
|
+
from ..models import Provider, create_provider
|
|
10
|
+
from .catalog import catalog_models
|
|
11
|
+
|
|
12
|
+
__all__ = ["meta_provider"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def meta_provider() -> Provider:
|
|
16
|
+
"""Meta (OpenAI Responses API): ``META_API_KEY`` or a Muse subscription login."""
|
|
17
|
+
return create_provider(
|
|
18
|
+
id="meta",
|
|
19
|
+
name="Meta",
|
|
20
|
+
base_url="https://api.meta.ai/v1",
|
|
21
|
+
auth=ProviderAuth(
|
|
22
|
+
api_key=env_api_key_auth("Meta Model API key", ["META_API_KEY"]),
|
|
23
|
+
oauth=lazy_oauth(
|
|
24
|
+
"Meta (Muse subscription)",
|
|
25
|
+
load_meta_oauth,
|
|
26
|
+
is_subscription=True,
|
|
27
|
+
login_label="Sign in with Meta",
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
models=lambda: catalog_models("meta"),
|
|
31
|
+
api=openai_responses_api(),
|
|
32
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""MiniMax provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import anthropic_messages_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["minimax_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def minimax_provider() -> Provider:
|
|
15
|
+
"""MiniMax (Anthropic Messages API), authenticated with ``MINIMAX_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="minimax",
|
|
18
|
+
name="MiniMax",
|
|
19
|
+
base_url="https://api.minimax.io/anthropic",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("MiniMax API key", ["MINIMAX_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("minimax"),
|
|
22
|
+
api=anthropic_messages_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""MiniMax CN provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import anthropic_messages_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["minimax_cn_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def minimax_cn_provider() -> Provider:
|
|
15
|
+
"""MiniMax CN (Anthropic Messages API), authenticated with ``MINIMAX_CN_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="minimax-cn",
|
|
18
|
+
name="MiniMax CN",
|
|
19
|
+
base_url="https://api.minimaxi.com/anthropic",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("MiniMax CN API key", ["MINIMAX_CN_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("minimax-cn"),
|
|
22
|
+
api=anthropic_messages_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Mistral provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import mistral_conversations_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["mistral_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def mistral_provider() -> Provider:
|
|
15
|
+
"""Mistral (Mistral Conversations API), authenticated with ``MISTRAL_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="mistral",
|
|
18
|
+
name="Mistral",
|
|
19
|
+
base_url="https://api.mistral.ai",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("Mistral API key", ["MISTRAL_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("mistral"),
|
|
22
|
+
api=mistral_conversations_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Moonshot AI provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_completions_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["moonshotai_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def moonshotai_provider() -> Provider:
|
|
15
|
+
"""Moonshot AI (OpenAI-compatible Chat Completions), authenticated with ``MOONSHOT_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="moonshotai",
|
|
18
|
+
name="Moonshot AI",
|
|
19
|
+
base_url="https://api.moonshot.ai/v1",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("Moonshot AI API key", ["MOONSHOT_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("moonshotai"),
|
|
22
|
+
api=openai_completions_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Moonshot AI CN provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_completions_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["moonshotai_cn_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def moonshotai_cn_provider() -> Provider:
|
|
15
|
+
"""Moonshot AI CN (OpenAI-compatible Chat Completions), authenticated with ``MOONSHOT_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="moonshotai-cn",
|
|
18
|
+
name="Moonshot AI CN",
|
|
19
|
+
base_url="https://api.moonshot.cn/v1",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("Moonshot AI API key", ["MOONSHOT_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("moonshotai-cn"),
|
|
22
|
+
api=openai_completions_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""NVIDIA provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_completions_api
|
|
6
|
+
from ..auth.helpers import env_api_key_auth
|
|
7
|
+
from ..auth.types import ProviderAuth
|
|
8
|
+
from ..models import Provider, create_provider
|
|
9
|
+
from .catalog import catalog_models
|
|
10
|
+
|
|
11
|
+
__all__ = ["nvidia_provider"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def nvidia_provider() -> Provider:
|
|
15
|
+
"""NVIDIA (OpenAI-compatible Chat Completions), authenticated with ``NVIDIA_API_KEY``."""
|
|
16
|
+
return create_provider(
|
|
17
|
+
id="nvidia",
|
|
18
|
+
name="NVIDIA",
|
|
19
|
+
base_url="https://integrate.api.nvidia.com/v1",
|
|
20
|
+
auth=ProviderAuth(api_key=env_api_key_auth("NVIDIA API key", ["NVIDIA_API_KEY"])),
|
|
21
|
+
models=lambda: catalog_models("nvidia"),
|
|
22
|
+
api=openai_completions_api(),
|
|
23
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""OpenAI provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
|
|
7
|
+
from ..api.registry import openai_decisions_api, openai_responses_api
|
|
8
|
+
from ..auth.helpers import env_api_key_auth, lazy_oauth
|
|
9
|
+
from ..auth.oauth.load import load_openai_chatgpt_oauth
|
|
10
|
+
from ..auth.types import Credential, ProviderAuth
|
|
11
|
+
from ..models import Provider, create_provider, is_model_type
|
|
12
|
+
from ..types import AnyModel
|
|
13
|
+
from .catalog import catalog_models
|
|
14
|
+
|
|
15
|
+
__all__ = ["openai_provider"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _filter_all_models(models: Sequence[AnyModel], credential: Credential | None) -> Sequence[AnyModel]:
|
|
19
|
+
# Sign in with ChatGPT tokens only reach the Responses API; the Decisions API rejects them.
|
|
20
|
+
if credential is not None and credential.get("type") == "oauth":
|
|
21
|
+
return [model for model in models if not is_model_type(model, "classifier")]
|
|
22
|
+
return models
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def openai_provider() -> Provider:
|
|
26
|
+
"""OpenAI (Responses API plus Decisions classifiers): ``OPENAI_API_KEY`` or Sign in with ChatGPT."""
|
|
27
|
+
return create_provider(
|
|
28
|
+
id="openai",
|
|
29
|
+
name="OpenAI",
|
|
30
|
+
base_url="https://api.openai.com/v1",
|
|
31
|
+
auth=ProviderAuth(
|
|
32
|
+
api_key=env_api_key_auth("OpenAI API key", ["OPENAI_API_KEY"]),
|
|
33
|
+
oauth=lazy_oauth(
|
|
34
|
+
"OpenAI (ChatGPT subscription)",
|
|
35
|
+
load_openai_chatgpt_oauth,
|
|
36
|
+
is_subscription=True,
|
|
37
|
+
login_label="Sign in with ChatGPT",
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
models=lambda: catalog_models("openai"),
|
|
41
|
+
filter_all_models=_filter_all_models,
|
|
42
|
+
api=openai_responses_api(),
|
|
43
|
+
classifiers={"openai-decisions": openai_decisions_api()},
|
|
44
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""OpenAI Codex (legacy ChatGPT backend) provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import openai_codex_responses_api
|
|
6
|
+
from ..auth.helpers import lazy_oauth
|
|
7
|
+
from ..auth.oauth.load import load_openai_codex_oauth
|
|
8
|
+
from ..auth.types import ProviderAuth
|
|
9
|
+
from ..models import Provider, create_provider
|
|
10
|
+
from .catalog import catalog_models
|
|
11
|
+
|
|
12
|
+
__all__ = ["openai_codex_provider"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def openai_codex_provider() -> Provider:
|
|
16
|
+
"""OpenAI Codex through the ChatGPT backend; OAuth (ChatGPT Plus/Pro) only."""
|
|
17
|
+
return create_provider(
|
|
18
|
+
id="openai-codex",
|
|
19
|
+
name="OpenAI Codex (legacy)",
|
|
20
|
+
base_url="https://chatgpt.com/backend-api",
|
|
21
|
+
auth=ProviderAuth(
|
|
22
|
+
oauth=lazy_oauth("OpenAI (ChatGPT Plus/Pro)", load_openai_codex_oauth, is_subscription=True),
|
|
23
|
+
),
|
|
24
|
+
models=lambda: catalog_models("openai-codex"),
|
|
25
|
+
api=openai_codex_responses_api(),
|
|
26
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""OpenCode Zen provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import (
|
|
6
|
+
anthropic_messages_api,
|
|
7
|
+
google_generative_ai_api,
|
|
8
|
+
openai_completions_api,
|
|
9
|
+
openai_responses_api,
|
|
10
|
+
typesafe_system_one_api,
|
|
11
|
+
)
|
|
12
|
+
from ..auth.helpers import env_api_key_auth
|
|
13
|
+
from ..auth.types import ProviderAuth
|
|
14
|
+
from ..models import Provider, create_provider
|
|
15
|
+
from .catalog import catalog_models
|
|
16
|
+
from .opencode_headers import with_opencode_session_header
|
|
17
|
+
|
|
18
|
+
__all__ = ["opencode_provider"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def opencode_provider() -> Provider:
|
|
22
|
+
"""OpenCode Zen (mixed APIs), authenticated with ``OPENCODE_API_KEY``."""
|
|
23
|
+
return create_provider(
|
|
24
|
+
id="opencode",
|
|
25
|
+
name="OpenCode Zen",
|
|
26
|
+
auth=ProviderAuth(api_key=env_api_key_auth("OpenCode API key", ["OPENCODE_API_KEY"])),
|
|
27
|
+
models=lambda: catalog_models("opencode"),
|
|
28
|
+
api={
|
|
29
|
+
"anthropic-messages": with_opencode_session_header(anthropic_messages_api()),
|
|
30
|
+
"google-generative-ai": with_opencode_session_header(google_generative_ai_api()),
|
|
31
|
+
"openai-completions": with_opencode_session_header(openai_completions_api()),
|
|
32
|
+
"openai-responses": with_opencode_session_header(openai_responses_api()),
|
|
33
|
+
},
|
|
34
|
+
# OpenCode Zen serves TypeSafe's System One protocol at /zen/v1/systemone.
|
|
35
|
+
classifiers={"typesafe-system-one": typesafe_system_one_api()},
|
|
36
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""OpenCode Go provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..api.registry import (
|
|
6
|
+
anthropic_messages_api,
|
|
7
|
+
google_generative_ai_api,
|
|
8
|
+
openai_completions_api,
|
|
9
|
+
openai_responses_api,
|
|
10
|
+
)
|
|
11
|
+
from ..auth.helpers import env_api_key_auth
|
|
12
|
+
from ..auth.types import ProviderAuth
|
|
13
|
+
from ..models import Provider, create_provider
|
|
14
|
+
from .catalog import catalog_models
|
|
15
|
+
from .opencode_headers import with_opencode_session_header
|
|
16
|
+
|
|
17
|
+
__all__ = ["opencode_go_provider"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def opencode_go_provider() -> Provider:
|
|
21
|
+
"""OpenCode Go (mixed APIs), authenticated with ``OPENCODE_API_KEY``."""
|
|
22
|
+
return create_provider(
|
|
23
|
+
id="opencode-go",
|
|
24
|
+
name="OpenCode Go",
|
|
25
|
+
auth=ProviderAuth(api_key=env_api_key_auth("OpenCode API key", ["OPENCODE_API_KEY"])),
|
|
26
|
+
models=lambda: catalog_models("opencode-go"),
|
|
27
|
+
api={
|
|
28
|
+
"anthropic-messages": with_opencode_session_header(anthropic_messages_api()),
|
|
29
|
+
"google-generative-ai": with_opencode_session_header(google_generative_ai_api()),
|
|
30
|
+
"openai-completions": with_opencode_session_header(openai_completions_api()),
|
|
31
|
+
"openai-responses": with_opencode_session_header(openai_responses_api()),
|
|
32
|
+
},
|
|
33
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""OpenCode's per-conversation routing header."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from ..event_stream import AssistantMessageEventStream
|
|
9
|
+
from ..types import Model, TranscriptContext
|
|
10
|
+
|
|
11
|
+
__all__ = ["OPENCODE_SESSION_HEADER", "with_opencode_session_header"]
|
|
12
|
+
|
|
13
|
+
OPENCODE_SESSION_HEADER = "x-opencode-session"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _has_header(headers: Mapping[str, Any] | None, name: str) -> bool:
|
|
17
|
+
# Any caller entry counts, including a ``None`` suppression marker.
|
|
18
|
+
expected = name.lower()
|
|
19
|
+
return any(key.lower() == expected for key in headers or {})
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _with_session_header(options: Mapping[str, Any] | None) -> Mapping[str, Any] | None:
|
|
23
|
+
if not options or not options.get("session_id") or _has_header(options.get("headers"), OPENCODE_SESSION_HEADER):
|
|
24
|
+
return options
|
|
25
|
+
return {
|
|
26
|
+
**options,
|
|
27
|
+
"headers": {**(options.get("headers") or {}), OPENCODE_SESSION_HEADER: options["session_id"]},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class _OpenCodeStreams:
|
|
32
|
+
"""Delegating ``ProviderStreams`` that keeps the wrapped deferred capabilities."""
|
|
33
|
+
|
|
34
|
+
__slots__ = ("_streams", "cancel_deferred", "fetch_deferred")
|
|
35
|
+
|
|
36
|
+
def __init__(self, streams: Any) -> None:
|
|
37
|
+
self._streams = streams
|
|
38
|
+
self.fetch_deferred = getattr(streams, "fetch_deferred", None)
|
|
39
|
+
self.cancel_deferred = getattr(streams, "cancel_deferred", None)
|
|
40
|
+
|
|
41
|
+
def stream(
|
|
42
|
+
self, model: Model, context: TranscriptContext, options: Mapping[str, Any] | None = None
|
|
43
|
+
) -> AssistantMessageEventStream:
|
|
44
|
+
return self._streams.stream(model, context, _with_session_header(options))
|
|
45
|
+
|
|
46
|
+
def stream_simple(
|
|
47
|
+
self, model: Model, context: TranscriptContext, options: Mapping[str, Any] | None = None
|
|
48
|
+
) -> AssistantMessageEventStream:
|
|
49
|
+
return self._streams.stream_simple(model, context, _with_session_header(options))
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
return f"with_opencode_session_header({self._streams!r})"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def with_opencode_session_header(streams: Any) -> Any:
|
|
56
|
+
"""Add OpenCode's required ``x-opencode-session`` header from ``session_id`` before API dispatch.
|
|
57
|
+
|
|
58
|
+
A caller-supplied header with the same name (any case, including ``None``) wins.
|
|
59
|
+
"""
|
|
60
|
+
return _OpenCodeStreams(streams)
|