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.
Files changed (189) hide show
  1. pi_agent/__init__.py +127 -0
  2. pi_agent/agent.py +617 -0
  3. pi_agent/agent_loop.py +820 -0
  4. pi_agent/proxy.py +269 -0
  5. pi_agent/py.typed +0 -0
  6. pi_agent/stream_fn.py +27 -0
  7. pi_agent/tools.py +327 -0
  8. pi_agent/types.py +394 -0
  9. pi_ai/__init__.py +263 -0
  10. pi_ai/abort.py +315 -0
  11. pi_ai/api/__init__.py +1 -0
  12. pi_ai/api/anthropic_messages.py +1782 -0
  13. pi_ai/api/azure_openai_config.py +138 -0
  14. pi_ai/api/azure_openai_responses.py +245 -0
  15. pi_ai/api/bedrock_converse_stream.py +1598 -0
  16. pi_ai/api/classifier_shared.py +211 -0
  17. pi_ai/api/cloudflare.py +36 -0
  18. pi_ai/api/cloudflare_workers_ai_system_one.py +80 -0
  19. pi_ai/api/constrained_sampling.py +279 -0
  20. pi_ai/api/github_copilot_headers.py +30 -0
  21. pi_ai/api/google_generative_ai.py +138 -0
  22. pi_ai/api/google_shared.py +927 -0
  23. pi_ai/api/google_vertex.py +234 -0
  24. pi_ai/api/lazy.py +156 -0
  25. pi_ai/api/llama_cpp_classify.py +449 -0
  26. pi_ai/api/mistral_conversations.py +756 -0
  27. pi_ai/api/openai_codex_responses.py +1545 -0
  28. pi_ai/api/openai_completions.py +1594 -0
  29. pi_ai/api/openai_decisions.py +210 -0
  30. pi_ai/api/openai_prompt_cache.py +19 -0
  31. pi_ai/api/openai_responses.py +418 -0
  32. pi_ai/api/openai_responses_shared.py +840 -0
  33. pi_ai/api/openai_sdk.py +204 -0
  34. pi_ai/api/openrouter_images.py +153 -0
  35. pi_ai/api/pi_messages.py +449 -0
  36. pi_ai/api/registry.py +103 -0
  37. pi_ai/api/simple_options.py +119 -0
  38. pi_ai/api/system_one_shared.py +148 -0
  39. pi_ai/api/transform_messages.py +211 -0
  40. pi_ai/api/typesafe_system_one.py +43 -0
  41. pi_ai/auth/__init__.py +1 -0
  42. pi_ai/auth/context.py +47 -0
  43. pi_ai/auth/credential_store.py +208 -0
  44. pi_ai/auth/helpers.py +123 -0
  45. pi_ai/auth/oauth/__init__.py +5 -0
  46. pi_ai/auth/oauth/_common.py +454 -0
  47. pi_ai/auth/oauth/anthropic.py +283 -0
  48. pi_ai/auth/oauth/callback_server.py +339 -0
  49. pi_ai/auth/oauth/device_code.py +127 -0
  50. pi_ai/auth/oauth/github_copilot.py +508 -0
  51. pi_ai/auth/oauth/kimi_coding.py +283 -0
  52. pi_ai/auth/oauth/load.py +64 -0
  53. pi_ai/auth/oauth/meta.py +238 -0
  54. pi_ai/auth/oauth/openai_chatgpt.py +321 -0
  55. pi_ai/auth/oauth/openai_codex.py +391 -0
  56. pi_ai/auth/oauth/openrouter.py +173 -0
  57. pi_ai/auth/oauth/pkce.py +23 -0
  58. pi_ai/auth/oauth/radius.py +311 -0
  59. pi_ai/auth/oauth/xai.py +220 -0
  60. pi_ai/auth/resolve.py +190 -0
  61. pi_ai/auth/types.py +292 -0
  62. pi_ai/cli.py +265 -0
  63. pi_ai/compat.py +651 -0
  64. pi_ai/env_api_keys.py +137 -0
  65. pi_ai/event_stream.py +329 -0
  66. pi_ai/models.py +1191 -0
  67. pi_ai/models_store.py +121 -0
  68. pi_ai/oauth.py +90 -0
  69. pi_ai/providers/__init__.py +1 -0
  70. pi_ai/providers/all.py +154 -0
  71. pi_ai/providers/amazon_bedrock.py +116 -0
  72. pi_ai/providers/ant_ling.py +23 -0
  73. pi_ai/providers/anthropic.py +105 -0
  74. pi_ai/providers/azure.py +103 -0
  75. pi_ai/providers/baseten.py +23 -0
  76. pi_ai/providers/catalog.py +167 -0
  77. pi_ai/providers/cerebras.py +23 -0
  78. pi_ai/providers/cloudflare_ai_gateway.py +30 -0
  79. pi_ai/providers/cloudflare_auth.py +112 -0
  80. pi_ai/providers/cloudflare_stream.py +84 -0
  81. pi_ai/providers/cloudflare_workers_ai.py +26 -0
  82. pi_ai/providers/data/amazon-bedrock.json +1 -0
  83. pi_ai/providers/data/ant-ling.json +1 -0
  84. pi_ai/providers/data/anthropic.json +1 -0
  85. pi_ai/providers/data/azure.json +1 -0
  86. pi_ai/providers/data/baseten.json +1 -0
  87. pi_ai/providers/data/cerebras.json +1 -0
  88. pi_ai/providers/data/cloudflare-ai-gateway.json +1 -0
  89. pi_ai/providers/data/cloudflare-workers-ai.json +1 -0
  90. pi_ai/providers/data/deepseek.json +1 -0
  91. pi_ai/providers/data/fireworks.json +1 -0
  92. pi_ai/providers/data/github-copilot.json +1 -0
  93. pi_ai/providers/data/google-vertex.json +1 -0
  94. pi_ai/providers/data/google.json +1 -0
  95. pi_ai/providers/data/groq.json +1 -0
  96. pi_ai/providers/data/huggingface.json +1 -0
  97. pi_ai/providers/data/kimi-coding.json +1 -0
  98. pi_ai/providers/data/manifest.json +1 -0
  99. pi_ai/providers/data/meta.json +1 -0
  100. pi_ai/providers/data/minimax-cn.json +1 -0
  101. pi_ai/providers/data/minimax.json +1 -0
  102. pi_ai/providers/data/mistral.json +1 -0
  103. pi_ai/providers/data/moonshotai-cn.json +1 -0
  104. pi_ai/providers/data/moonshotai.json +1 -0
  105. pi_ai/providers/data/nvidia.json +1 -0
  106. pi_ai/providers/data/openai-codex.json +1 -0
  107. pi_ai/providers/data/openai.json +1 -0
  108. pi_ai/providers/data/opencode-go.json +1 -0
  109. pi_ai/providers/data/opencode.json +1 -0
  110. pi_ai/providers/data/openrouter.json +1 -0
  111. pi_ai/providers/data/qwen-token-plan-cn.json +1 -0
  112. pi_ai/providers/data/qwen-token-plan-individual.json +1 -0
  113. pi_ai/providers/data/qwen-token-plan.json +1 -0
  114. pi_ai/providers/data/radius.json +1 -0
  115. pi_ai/providers/data/together.json +1 -0
  116. pi_ai/providers/data/typesafe.json +1 -0
  117. pi_ai/providers/data/vercel-ai-gateway.json +1 -0
  118. pi_ai/providers/data/xai.json +1 -0
  119. pi_ai/providers/data/xiaomi-token-plan-ams.json +1 -0
  120. pi_ai/providers/data/xiaomi-token-plan-cn.json +1 -0
  121. pi_ai/providers/data/xiaomi-token-plan-sgp.json +1 -0
  122. pi_ai/providers/data/xiaomi.json +1 -0
  123. pi_ai/providers/data/zai-coding-cn.json +1 -0
  124. pi_ai/providers/data/zai.json +1 -0
  125. pi_ai/providers/deepseek.py +23 -0
  126. pi_ai/providers/faux.py +680 -0
  127. pi_ai/providers/fireworks.py +26 -0
  128. pi_ai/providers/github_copilot.py +46 -0
  129. pi_ai/providers/google.py +23 -0
  130. pi_ai/providers/google_vertex.py +131 -0
  131. pi_ai/providers/groq.py +23 -0
  132. pi_ai/providers/huggingface.py +23 -0
  133. pi_ai/providers/kimi_coding.py +32 -0
  134. pi_ai/providers/meta.py +32 -0
  135. pi_ai/providers/minimax.py +23 -0
  136. pi_ai/providers/minimax_cn.py +23 -0
  137. pi_ai/providers/mistral.py +23 -0
  138. pi_ai/providers/moonshotai.py +23 -0
  139. pi_ai/providers/moonshotai_cn.py +23 -0
  140. pi_ai/providers/nvidia.py +23 -0
  141. pi_ai/providers/openai.py +44 -0
  142. pi_ai/providers/openai_codex.py +26 -0
  143. pi_ai/providers/opencode.py +36 -0
  144. pi_ai/providers/opencode_go.py +33 -0
  145. pi_ai/providers/opencode_headers.py +60 -0
  146. pi_ai/providers/openrouter.py +145 -0
  147. pi_ai/providers/openrouter_api.py +122 -0
  148. pi_ai/providers/qwen_token_plan.py +23 -0
  149. pi_ai/providers/qwen_token_plan_cn.py +23 -0
  150. pi_ai/providers/qwen_token_plan_individual.py +23 -0
  151. pi_ai/providers/radius.py +146 -0
  152. pi_ai/providers/radius_config.py +136 -0
  153. pi_ai/providers/together.py +23 -0
  154. pi_ai/providers/typesafe.py +22 -0
  155. pi_ai/providers/vercel_ai_gateway.py +25 -0
  156. pi_ai/providers/xai.py +32 -0
  157. pi_ai/providers/xiaomi.py +23 -0
  158. pi_ai/providers/xiaomi_token_plan_ams.py +23 -0
  159. pi_ai/providers/xiaomi_token_plan_cn.py +23 -0
  160. pi_ai/providers/xiaomi_token_plan_sgp.py +23 -0
  161. pi_ai/providers/zai.py +23 -0
  162. pi_ai/providers/zai_coding_cn.py +23 -0
  163. pi_ai/py.typed +0 -0
  164. pi_ai/serialization.py +477 -0
  165. pi_ai/session_resources.py +33 -0
  166. pi_ai/types.py +1003 -0
  167. pi_ai/utils/__init__.py +1 -0
  168. pi_ai/utils/callbacks.py +15 -0
  169. pi_ai/utils/diagnostics.py +70 -0
  170. pi_ai/utils/error_body.py +89 -0
  171. pi_ai/utils/estimate.py +125 -0
  172. pi_ai/utils/fastjson.py +63 -0
  173. pi_ai/utils/http.py +409 -0
  174. pi_ai/utils/json_parse.py +424 -0
  175. pi_ai/utils/misc.py +193 -0
  176. pi_ai/utils/model_operations.py +73 -0
  177. pi_ai/utils/models_error.py +35 -0
  178. pi_ai/utils/oauth_page.py +121 -0
  179. pi_ai/utils/overflow.py +87 -0
  180. pi_ai/utils/retry.py +193 -0
  181. pi_ai/utils/schema.py +283 -0
  182. pi_ai/utils/text.py +65 -0
  183. pi_ai/utils/transcript.py +271 -0
  184. pi_ai/utils/validation.py +813 -0
  185. pi_ai_python-1.3.0.dist-info/METADATA +167 -0
  186. pi_ai_python-1.3.0.dist-info/RECORD +189 -0
  187. pi_ai_python-1.3.0.dist-info/WHEEL +4 -0
  188. pi_ai_python-1.3.0.dist-info/entry_points.txt +2 -0
  189. pi_ai_python-1.3.0.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,138 @@
1
+ """Google Generative AI (Gemini API) adapter.
2
+
3
+ Streams through the official ``google-genai`` SDK (``client.aio.models.generate_content_stream``),
4
+ as pi upstream does with ``@google/genai``.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Mapping
10
+ from typing import Any, Literal
11
+
12
+ from google.genai import Client
13
+ from google.genai import types as genai_types
14
+
15
+ from ..event_stream import AssistantMessageEventStream
16
+ from ..models import clamp_thinking_level
17
+ from ..types import Model, StreamOptions, TranscriptContext
18
+ from ..utils.http import get_http_client
19
+ from ..utils.misc import get_provider_env_value
20
+ from .google_shared import (
21
+ GoogleThinkingOptions,
22
+ ResolvedGoogleThinkingLevel,
23
+ get_google_client,
24
+ new_google_output,
25
+ resolve_google_thinking_level,
26
+ run_google_stream,
27
+ to_google_thinking_level,
28
+ uses_google_thinking_level,
29
+ )
30
+ from .simple_options import build_base_options
31
+
32
+ __all__ = ["GoogleOptions", "stream", "stream_simple", "get_google_budget"]
33
+
34
+ _DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/"
35
+
36
+
37
+ class GoogleOptions(StreamOptions, total=False):
38
+ tool_choice: Literal["auto", "none", "any"]
39
+ thinking: GoogleThinkingOptions
40
+
41
+
42
+ def stream(
43
+ model: Model, context: TranscriptContext, options: Mapping[str, Any] | None = None
44
+ ) -> AssistantMessageEventStream:
45
+ """Stream a Gemini API response."""
46
+ opts = dict(options or {})
47
+ out = AssistantMessageEventStream()
48
+ output = new_google_output(model)
49
+ out.start(
50
+ run_google_stream(
51
+ model,
52
+ context,
53
+ opts,
54
+ out,
55
+ output,
56
+ create_client=lambda: _create_client(model, opts),
57
+ missing_finish_reason_message="Google stream ended without a finish reason",
58
+ )
59
+ )
60
+ return out
61
+
62
+
63
+ def stream_simple(
64
+ model: Model, context: TranscriptContext, options: Mapping[str, Any] | None = None
65
+ ) -> AssistantMessageEventStream:
66
+ """Stream with provider-neutral options (``reasoning``, ``tool_choice``, ``thinking_budgets``)."""
67
+ options = options or {}
68
+ api_key = options.get("api_key")
69
+ if not api_key:
70
+ raise ValueError(f"No API key for provider: {model.provider}")
71
+
72
+ base: dict[str, Any] = build_base_options(model, context, options, api_key)
73
+ if options.get("tool_choice") is not None:
74
+ base["tool_choice"] = options["tool_choice"]
75
+ reasoning = options.get("reasoning")
76
+ if not reasoning:
77
+ return stream(model, context, {**base, "thinking": {"enabled": False}})
78
+
79
+ clamped = clamp_thinking_level(model, reasoning)
80
+ if clamped == "off":
81
+ return stream(model, context, {**base, "thinking": {"enabled": False}})
82
+ resolved = resolve_google_thinking_level(model, clamped)
83
+
84
+ if uses_google_thinking_level(model):
85
+ return stream(
86
+ model, context, {**base, "thinking": {"enabled": True, "level": to_google_thinking_level(resolved)}}
87
+ )
88
+ return stream(
89
+ model,
90
+ context,
91
+ {
92
+ **base,
93
+ "thinking": {
94
+ "enabled": True,
95
+ "budget_tokens": get_google_budget(model, resolved, options.get("thinking_budgets")),
96
+ },
97
+ },
98
+ )
99
+
100
+
101
+ async def _create_client(model: Model, options: Mapping[str, Any]) -> Client:
102
+ api_key = options.get("api_key")
103
+ if not api_key:
104
+ raise ValueError(f"No API key for provider: {model.provider}")
105
+
106
+ base_url: str | None
107
+ api_version: str | None = None
108
+ if model.base_url:
109
+ # The catalog baseUrl already includes the version path; don't append one.
110
+ base_url, api_version = model.base_url, ""
111
+ else:
112
+ # The SDK reads GOOGLE_GEMINI_BASE_URL from os.environ itself; this also honors the provider env.
113
+ base_url = (get_provider_env_value("GOOGLE_GEMINI_BASE_URL", options.get("env")) or "").strip() or None
114
+ http_client = get_http_client(base_url or _DEFAULT_BASE_URL, options)
115
+
116
+ async def factory() -> Client:
117
+ http_options = genai_types.HttpOptions(
118
+ base_url=base_url, api_version=api_version, httpx_async_client=http_client
119
+ )
120
+ return Client(vertexai=False, api_key=api_key, http_options=http_options)
121
+
122
+ # Headers are sent per request (see run_google_stream), so they are not part of the key.
123
+ return await get_google_client(http_client, ("gemini", api_key, base_url, api_version), factory)
124
+
125
+
126
+ def get_google_budget(
127
+ model: Model, level: ResolvedGoogleThinkingLevel, custom_budgets: Mapping[str, int] | None = None
128
+ ) -> int:
129
+ """Token budget for a thinking level on budget-based Gemini models (-1 = dynamic)."""
130
+ if custom_budgets and custom_budgets.get(level) is not None:
131
+ return custom_budgets[level]
132
+ if "2.5-pro" in model.id:
133
+ return {"minimal": 128, "low": 2048, "medium": 8192, "high": 32768}[level]
134
+ if "2.5-flash-lite" in model.id:
135
+ return {"minimal": 512, "low": 2048, "medium": 8192, "high": 24576}[level]
136
+ if "2.5-flash" in model.id:
137
+ return {"minimal": 128, "low": 2048, "medium": 8192, "high": 24576}[level]
138
+ return -1