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
pi_agent/types.py ADDED
@@ -0,0 +1,394 @@
1
+ """Types for the agent runtime (mirrors ``@earendil-works/pi-agent-core`` ``src/types.ts``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Awaitable, Callable, Mapping
6
+ from dataclasses import KW_ONLY, dataclass, field
7
+ from typing import TYPE_CHECKING, Any, ClassVar, Literal, Protocol, TypeAlias
8
+
9
+ from pi_ai import (
10
+ AbortSignal,
11
+ AssistantMessage,
12
+ AssistantMessageEvent,
13
+ AssistantMessageEventStream,
14
+ ImageContent,
15
+ Message,
16
+ Model,
17
+ TextContent,
18
+ Tool,
19
+ ToolCall,
20
+ ToolResultMessage,
21
+ TranscriptContext,
22
+ Usage,
23
+ )
24
+
25
+ if TYPE_CHECKING:
26
+ pass
27
+
28
+ __all__ = [
29
+ "StreamFn",
30
+ "ToolExecutionMode",
31
+ "QueueMode",
32
+ "ThinkingLevel",
33
+ "AgentToolCall",
34
+ "AgentMessage",
35
+ "BeforeToolCallResult",
36
+ "AfterToolCallResult",
37
+ "BeforeToolCallContext",
38
+ "AfterToolCallContext",
39
+ "AgentTurnContext",
40
+ "AgentTurnDecision",
41
+ "FinishTurn",
42
+ "AgentLoopTurnUpdate",
43
+ "PrepareRequestContext",
44
+ "AgentRequestUpdate",
45
+ "PrepareRequest",
46
+ "PrepareNextTurnContext",
47
+ "AgentLoopConfig",
48
+ "AgentToolResult",
49
+ "AgentToolCallOutcome",
50
+ "AgentToolUpdateCallback",
51
+ "AgentTool",
52
+ "AgentContext",
53
+ "AgentStartEvent",
54
+ "AgentEndEvent",
55
+ "TurnStartEvent",
56
+ "TurnEndEvent",
57
+ "MessageStartEvent",
58
+ "MessageUpdateEvent",
59
+ "MessageEndEvent",
60
+ "ToolExecutionStartEvent",
61
+ "ToolExecutionUpdateEvent",
62
+ "ToolExecutionEndEvent",
63
+ "AgentEvent",
64
+ ]
65
+
66
+ #: Stream function used by the agent loop (``models.stream_simple`` satisfies it).
67
+ #:
68
+ #: It receives a normalized transcript (prompt and tools live in system messages) and
69
+ #: must encode failures in the returned stream instead of raising.
70
+ StreamFn: TypeAlias = Callable[
71
+ [Model, TranscriptContext, "Mapping[str, Any] | None"],
72
+ "AssistantMessageEventStream | Awaitable[AssistantMessageEventStream]",
73
+ ]
74
+
75
+ #: ``sequential``: each tool call is prepared, executed and finalized before the next starts.
76
+ #: ``parallel``: tool calls are prepared sequentially, then allowed tools execute concurrently.
77
+ ToolExecutionMode: TypeAlias = Literal["sequential", "parallel"]
78
+
79
+ #: How many queued messages are injected at a drain point: every message, or only the oldest.
80
+ QueueMode: TypeAlias = Literal["all", "one-at-a-time"]
81
+
82
+ ThinkingLevel: TypeAlias = Literal["off", "minimal", "low", "medium", "high", "xhigh", "max"]
83
+
84
+ AgentToolCall: TypeAlias = ToolCall
85
+
86
+ #: Any message in an agent transcript: the LLM messages plus app-defined custom
87
+ #: messages (any object with a ``role`` attribute, e.g. a dataclass).
88
+ AgentMessage: TypeAlias = Any
89
+
90
+
91
+ @dataclass(slots=True)
92
+ class BeforeToolCallResult:
93
+ """Returned from ``before_tool_call``. ``block=True`` prevents execution with an error result."""
94
+
95
+ block: bool = False
96
+ #: Text of the error result when blocked. Defaults to "Tool execution was blocked".
97
+ reason: str | None = None
98
+ #: Hint to stop after the current tool batch when blocked (only when every result in the batch terminates).
99
+ terminate: bool | None = None
100
+
101
+
102
+ @dataclass(slots=True)
103
+ class AfterToolCallResult:
104
+ """Partial override returned from ``after_tool_call``; omitted (``None``) fields keep their values.
105
+
106
+ ``content`` without ``structured_content`` drops the original structured content, because it
107
+ may no longer match. No deep merge is performed.
108
+ """
109
+
110
+ content: list[TextContent | ImageContent] | None = None
111
+ details: Any = None
112
+ structured_content: Any = None
113
+ is_error: bool | None = None
114
+ usage: Usage | None = None
115
+ terminate: bool | None = None
116
+
117
+
118
+ @dataclass(slots=True)
119
+ class BeforeToolCallContext:
120
+ assistant_message: AssistantMessage
121
+ tool_call: ToolCall
122
+ #: Validated tool arguments.
123
+ args: Any
124
+ context: AgentContext
125
+
126
+
127
+ @dataclass(slots=True)
128
+ class AfterToolCallContext:
129
+ assistant_message: AssistantMessage
130
+ tool_call: ToolCall
131
+ args: Any
132
+ #: The executed tool result before overrides are applied.
133
+ result: AgentToolResult
134
+ is_error: bool
135
+ context: AgentContext
136
+
137
+
138
+ @dataclass(slots=True)
139
+ class AgentTurnContext:
140
+ """Context passed to completed-turn callbacks."""
141
+
142
+ message: AssistantMessage
143
+ tool_results: list[ToolResultMessage]
144
+ #: Agent context after the turn's assistant message and tool results were appended.
145
+ context: AgentContext
146
+ #: Messages this loop invocation returns if it exits now.
147
+ new_messages: list[Any]
148
+
149
+
150
+ PrepareNextTurnContext = AgentTurnContext
151
+
152
+
153
+ @dataclass(slots=True)
154
+ class AgentTurnDecision:
155
+ """Decision returned by ``finish_turn``: ``"continue"`` or ``"end"``.
156
+
157
+ ``finish_turn`` may also return the plain strings or ``{"action": ...}`` dicts.
158
+ """
159
+
160
+ action: Literal["continue", "end"]
161
+
162
+
163
+ FinishTurn: TypeAlias = Callable[[AgentTurnContext, "AbortSignal | None"], Any]
164
+
165
+
166
+ @dataclass(slots=True)
167
+ class AgentLoopTurnUpdate:
168
+ """Replacement runtime state used before starting another provider request."""
169
+
170
+ context: AgentContext | None = None
171
+ #: Messages to append before the next provider request, with normal lifecycle events.
172
+ messages: list[Any] | None = None
173
+ model: Model | None = None
174
+ thinking_level: ThinkingLevel | None = None
175
+
176
+
177
+ @dataclass(slots=True)
178
+ class PrepareRequestContext:
179
+ context: AgentContext
180
+ model: Model
181
+ thinking_level: ThinkingLevel
182
+
183
+
184
+ @dataclass(slots=True)
185
+ class AgentRequestUpdate:
186
+ """Replacement runtime state for the provider request being prepared."""
187
+
188
+ context: AgentContext | None = None
189
+ model: Model | None = None
190
+ thinking_level: ThinkingLevel | None = None
191
+
192
+
193
+ PrepareRequest: TypeAlias = Callable[[PrepareRequestContext, "AbortSignal | None"], Any]
194
+
195
+
196
+ @dataclass(slots=True, kw_only=True)
197
+ class AgentLoopConfig:
198
+ """Configuration of the low-level agent loop.
199
+
200
+ ``stream_options`` holds the ``SimpleStreamOptions`` forwarded to the stream function
201
+ (``session_id``, ``transport``, ``thinking_budgets``, ``on_payload``, ``temperature``...).
202
+ """
203
+
204
+ model: Model
205
+ #: Convert agent messages to LLM messages before each call. Must not raise.
206
+ convert_to_llm: Callable[[list[Any]], list[Message] | Awaitable[list[Message]]]
207
+ #: Requested reasoning level (``None`` means off).
208
+ reasoning: ThinkingLevel | None = None
209
+ api_key: str | None = None
210
+ stream_options: dict[str, Any] = field(default_factory=dict)
211
+ #: Optional transform applied before ``convert_to_llm`` (pruning, context injection). Must not raise.
212
+ transform_context: Callable[[list[Any], AbortSignal | None], Awaitable[list[Any]]] | None = None
213
+ #: Resolve an API key per call (short-lived OAuth tokens). Must not raise.
214
+ get_api_key: Callable[[str], str | Awaitable[str | None] | None] | None = None
215
+ finish_turn: FinishTurn | None = None
216
+ prepare_request: PrepareRequest | None = None
217
+ prepare_next_turn: Callable[[AgentTurnContext], Any] | None = None
218
+ get_steering_messages: Callable[[], Awaitable[list[Any]]] | None = None
219
+ get_follow_up_messages: Callable[[], Awaitable[list[Any]]] | None = None
220
+ #: Default ``"parallel"``.
221
+ tool_execution: ToolExecutionMode = "parallel"
222
+ before_tool_call: (
223
+ Callable[[BeforeToolCallContext, AbortSignal | None], Awaitable[BeforeToolCallResult | None]] | None
224
+ ) = None
225
+ after_tool_call: (
226
+ Callable[[AfterToolCallContext, AbortSignal | None], Awaitable[AfterToolCallResult | None]] | None
227
+ ) = None
228
+
229
+
230
+ @dataclass(slots=True)
231
+ class AgentToolResult:
232
+ """Final or partial result produced by a tool."""
233
+
234
+ #: Text or image content returned to the model.
235
+ content: list[TextContent | ImageContent] = field(default_factory=list)
236
+ #: Arbitrary structured details for logs or UI rendering.
237
+ details: Any = None
238
+ _: KW_ONLY
239
+ #: Machine-readable result matching the tool's ``output_schema``; not sent to the model.
240
+ structured_content: Any = None
241
+ usage: Usage | None = None
242
+ #: Report a failure without raising; ``details``/``structured_content`` are kept.
243
+ is_error: bool | None = None
244
+ #: Hint to stop after the current tool batch (only when every result in the batch terminates).
245
+ terminate: bool | None = None
246
+
247
+
248
+ @dataclass(slots=True)
249
+ class AgentToolCallOutcome:
250
+ tool_call: ToolCall
251
+ result: AgentToolResult
252
+ is_error: bool
253
+ #: Milliseconds ``execute()`` took; ``None`` when the tool did not run.
254
+ duration_ms: int | None = None
255
+
256
+
257
+ AgentToolUpdateCallback: TypeAlias = Callable[[AgentToolResult], Any]
258
+
259
+
260
+ class _Execute(Protocol):
261
+ def __call__(
262
+ self,
263
+ tool_call_id: str,
264
+ params: Any,
265
+ signal: AbortSignal | None = None,
266
+ on_update: AgentToolUpdateCallback | None = None,
267
+ ) -> Awaitable[AgentToolResult]: ...
268
+
269
+
270
+ @dataclass(slots=True, kw_only=True)
271
+ class AgentTool(Tool):
272
+ """A tool the agent can execute.
273
+
274
+ ``execute(tool_call_id, params, signal, on_update)`` receives validated parameters
275
+ (a dict, or a model instance for Pydantic parameters). Raise on failure, or return a
276
+ result with ``is_error=True``; do not only describe the failure in ``content``.
277
+ """
278
+
279
+ execute: _Execute
280
+ #: Human-readable label for UI display (defaults to ``name``).
281
+ label: str = ""
282
+ #: Compatibility shim for raw arguments before schema validation.
283
+ prepare_arguments: Callable[[Any], Any] | None = None
284
+ #: JSON Schema of ``structured_content`` in successful results.
285
+ output_schema: Any = None
286
+ #: Recovery policy for an effect whose durable intent exists but whose outcome is unknown.
287
+ replay: Literal["never", "safe"] | None = None
288
+ #: Per-tool execution mode override; ``"sequential"`` forces the whole batch to run sequentially.
289
+ execution_mode: ToolExecutionMode | None = None
290
+
291
+ def __post_init__(self) -> None:
292
+ if not self.label:
293
+ self.label = self.name
294
+
295
+
296
+ @dataclass(slots=True)
297
+ class AgentContext:
298
+ """Context snapshot passed into the low-level agent loop."""
299
+
300
+ messages: list[Any] = field(default_factory=list)
301
+ tools: list[AgentTool] | None = None
302
+
303
+
304
+ # ---------------------------------------------------------------------------
305
+ # Events
306
+ # ---------------------------------------------------------------------------
307
+
308
+
309
+ @dataclass(slots=True)
310
+ class AgentStartEvent:
311
+ type: ClassVar[Literal["agent_start"]] = "agent_start"
312
+
313
+
314
+ @dataclass(slots=True)
315
+ class AgentEndEvent:
316
+ """Last event of a run. Awaited ``Agent.subscribe`` listeners still count toward settlement."""
317
+
318
+ type: ClassVar[Literal["agent_end"]] = "agent_end"
319
+ messages: list[Any]
320
+
321
+
322
+ @dataclass(slots=True)
323
+ class TurnStartEvent:
324
+ type: ClassVar[Literal["turn_start"]] = "turn_start"
325
+
326
+
327
+ @dataclass(slots=True)
328
+ class TurnEndEvent:
329
+ type: ClassVar[Literal["turn_end"]] = "turn_end"
330
+ message: Any
331
+ tool_results: list[ToolResultMessage]
332
+
333
+
334
+ @dataclass(slots=True)
335
+ class MessageStartEvent:
336
+ type: ClassVar[Literal["message_start"]] = "message_start"
337
+ message: Any
338
+
339
+
340
+ @dataclass(slots=True)
341
+ class MessageUpdateEvent:
342
+ """Only emitted for assistant messages during streaming."""
343
+
344
+ type: ClassVar[Literal["message_update"]] = "message_update"
345
+ message: Any
346
+ assistant_message_event: AssistantMessageEvent
347
+
348
+
349
+ @dataclass(slots=True)
350
+ class MessageEndEvent:
351
+ type: ClassVar[Literal["message_end"]] = "message_end"
352
+ message: Any
353
+
354
+
355
+ @dataclass(slots=True)
356
+ class ToolExecutionStartEvent:
357
+ type: ClassVar[Literal["tool_execution_start"]] = "tool_execution_start"
358
+ tool_call_id: str
359
+ tool_name: str
360
+ args: Any
361
+
362
+
363
+ @dataclass(slots=True)
364
+ class ToolExecutionUpdateEvent:
365
+ type: ClassVar[Literal["tool_execution_update"]] = "tool_execution_update"
366
+ tool_call_id: str
367
+ tool_name: str
368
+ args: Any
369
+ partial_result: Any
370
+
371
+
372
+ @dataclass(slots=True)
373
+ class ToolExecutionEndEvent:
374
+ type: ClassVar[Literal["tool_execution_end"]] = "tool_execution_end"
375
+ tool_call_id: str
376
+ tool_name: str
377
+ result: Any
378
+ is_error: bool
379
+ #: Milliseconds ``execute()`` took; ``None`` when the tool did not run.
380
+ duration_ms: int | None = None
381
+
382
+
383
+ AgentEvent: TypeAlias = (
384
+ AgentStartEvent
385
+ | AgentEndEvent
386
+ | TurnStartEvent
387
+ | TurnEndEvent
388
+ | MessageStartEvent
389
+ | MessageUpdateEvent
390
+ | MessageEndEvent
391
+ | ToolExecutionStartEvent
392
+ | ToolExecutionUpdateEvent
393
+ | ToolExecutionEndEvent
394
+ )
pi_ai/__init__.py ADDED
@@ -0,0 +1,263 @@
1
+ """pi-ai: unified LLM API with provider collections, auth resolution, streaming events,
2
+ token/cost tracking and cross-provider context hand-off.
3
+
4
+ Python port of ``@earendil-works/pi-ai``. The core entry point does not import
5
+ built-in catalogs or provider implementations; use :mod:`pi_ai.providers.all`
6
+ (``builtin_models()``) or individual provider factories such as
7
+ :func:`pi_ai.providers.anthropic.anthropic_provider`.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from .abort import AbortController, AbortError, AbortSignal, abort_scope
13
+ from .api.lazy import LazyApi, lazy_api, lazy_stream
14
+ from .auth.context import DefaultAuthContext, default_provider_auth_context
15
+ from .auth.credential_store import FileCredentialStore, InMemoryCredentialStore
16
+ from .auth.helpers import env_api_key_auth, keyless_auth, lazy_oauth
17
+ from .auth.resolve import AuthResolutionOverrides
18
+ from .auth.types import (
19
+ ApiKeyAuth,
20
+ ApiKeyCredential,
21
+ AuthCheck,
22
+ AuthContext,
23
+ AuthEvent,
24
+ AuthInfoLink,
25
+ AuthInteraction,
26
+ AuthPrompt,
27
+ AuthResult,
28
+ AuthSelectOption,
29
+ AuthType,
30
+ Credential,
31
+ CredentialInfo,
32
+ CredentialStore,
33
+ LoginOptions,
34
+ ModelAuth,
35
+ OAuthAuth,
36
+ OAuthCredential,
37
+ OAuthCredentials,
38
+ ProviderAuth,
39
+ ProviderAuthInteraction,
40
+ )
41
+ from .event_stream import AssistantMessageEventStream, EventStream, create_assistant_message_event_stream
42
+ from .models import (
43
+ UNCHANGED,
44
+ Models,
45
+ ModelsError,
46
+ ModelsErrorCode,
47
+ ModelsPublication,
48
+ ModelsRefreshResult,
49
+ MutableModels,
50
+ Provider,
51
+ RefreshModelsContext,
52
+ calculate_cost,
53
+ clamp_thinking_level,
54
+ create_models,
55
+ create_provider,
56
+ get_model_type,
57
+ get_supported_thinking_levels,
58
+ has_api,
59
+ is_model_type,
60
+ models_are_equal,
61
+ )
62
+ from .models_store import FileModelsStore, InMemoryModelsStore, ModelsStore, ModelsStoreEntry
63
+ from .providers.faux import (
64
+ FauxModelDefinition,
65
+ FauxProviderHandle,
66
+ FauxProviderState,
67
+ faux_assistant_message,
68
+ faux_provider,
69
+ faux_text,
70
+ faux_thinking,
71
+ faux_tool_call,
72
+ )
73
+ from .session_resources import cleanup_session_resources, register_session_resource_cleanup
74
+ from .types import * # noqa: F403
75
+ from .types import __all__ as _types_all
76
+ from .utils.diagnostics import (
77
+ AssistantMessageDiagnostic,
78
+ DiagnosticErrorInfo,
79
+ append_assistant_message_diagnostic,
80
+ create_assistant_message_diagnostic,
81
+ extract_diagnostic_error,
82
+ format_thrown_value,
83
+ )
84
+ from .utils.http import ProviderHttpError, aclose_http_clients
85
+ from .utils.json_parse import (
86
+ StreamingJsonParser,
87
+ parse_json_with_repair,
88
+ parse_streaming_json,
89
+ parse_tool_call_arguments,
90
+ repair_json,
91
+ )
92
+ from .utils.misc import uuidv7
93
+ from .utils.overflow import get_overflow_patterns, is_context_overflow, is_recoverable_length
94
+ from .utils.retry import (
95
+ DEFAULT_MAX_AGENT_RETRY_DELAY_MS,
96
+ RetryCallbacks,
97
+ RetryPolicy,
98
+ is_retryable_assistant_error,
99
+ retry_assistant_call,
100
+ retry_delay_ms,
101
+ )
102
+ from .utils.schema import StringEnum, TSchema, Type
103
+ from .utils.text import content_text, get_system_message_text, render_system_message_update
104
+ from .utils.transcript import (
105
+ ToolStateChanges,
106
+ TranscriptTools,
107
+ collapse_system_messages,
108
+ create_initial_system_message,
109
+ declarations_equal,
110
+ get_current_system_message,
111
+ get_current_system_prompt,
112
+ get_current_tools,
113
+ get_declared_tools,
114
+ get_initial_system_message,
115
+ get_tool_state_changes,
116
+ has_non_additive_tool_changes,
117
+ has_tool_redefinitions,
118
+ normalize_context,
119
+ resolve_transcript,
120
+ resolve_transcript_tools,
121
+ to_tool_declaration,
122
+ without_initial_system_message,
123
+ )
124
+ from .utils.validation import ToolValidationError, validate_tool_arguments, validate_tool_call
125
+
126
+ __version__ = "1.3.0"
127
+
128
+ __all__ = [
129
+ *_types_all,
130
+ "__version__",
131
+ # cancellation
132
+ "AbortController",
133
+ "AbortError",
134
+ "AbortSignal",
135
+ "abort_scope",
136
+ # streams
137
+ "EventStream",
138
+ "AssistantMessageEventStream",
139
+ "create_assistant_message_event_stream",
140
+ "lazy_stream",
141
+ "lazy_api",
142
+ "LazyApi",
143
+ # models runtime
144
+ "Models",
145
+ "MutableModels",
146
+ "Provider",
147
+ "ModelsError",
148
+ "ModelsErrorCode",
149
+ "ModelsPublication",
150
+ "ModelsRefreshResult",
151
+ "RefreshModelsContext",
152
+ "UNCHANGED",
153
+ "create_models",
154
+ "create_provider",
155
+ "has_api",
156
+ "get_model_type",
157
+ "is_model_type",
158
+ "calculate_cost",
159
+ "get_supported_thinking_levels",
160
+ "clamp_thinking_level",
161
+ "models_are_equal",
162
+ "ModelsStore",
163
+ "ModelsStoreEntry",
164
+ "InMemoryModelsStore",
165
+ "FileModelsStore",
166
+ # auth
167
+ "ApiKeyAuth",
168
+ "ApiKeyCredential",
169
+ "AuthCheck",
170
+ "AuthContext",
171
+ "AuthEvent",
172
+ "AuthInfoLink",
173
+ "AuthInteraction",
174
+ "AuthPrompt",
175
+ "AuthResult",
176
+ "AuthResolutionOverrides",
177
+ "AuthSelectOption",
178
+ "AuthType",
179
+ "Credential",
180
+ "CredentialInfo",
181
+ "CredentialStore",
182
+ "LoginOptions",
183
+ "ModelAuth",
184
+ "OAuthAuth",
185
+ "OAuthCredential",
186
+ "OAuthCredentials",
187
+ "ProviderAuth",
188
+ "ProviderAuthInteraction",
189
+ "DefaultAuthContext",
190
+ "default_provider_auth_context",
191
+ "InMemoryCredentialStore",
192
+ "FileCredentialStore",
193
+ "env_api_key_auth",
194
+ "keyless_auth",
195
+ "lazy_oauth",
196
+ # faux
197
+ "FauxModelDefinition",
198
+ "FauxProviderHandle",
199
+ "FauxProviderState",
200
+ "faux_provider",
201
+ "faux_assistant_message",
202
+ "faux_text",
203
+ "faux_thinking",
204
+ "faux_tool_call",
205
+ # tools & schemas
206
+ "Type",
207
+ "TSchema",
208
+ "StringEnum",
209
+ "validate_tool_call",
210
+ "validate_tool_arguments",
211
+ "ToolValidationError",
212
+ # json
213
+ "parse_streaming_json",
214
+ "parse_json_with_repair",
215
+ "parse_tool_call_arguments",
216
+ "repair_json",
217
+ "StreamingJsonParser",
218
+ # transcript
219
+ "normalize_context",
220
+ "create_initial_system_message",
221
+ "get_initial_system_message",
222
+ "without_initial_system_message",
223
+ "get_current_tools",
224
+ "get_current_system_message",
225
+ "get_current_system_prompt",
226
+ "collapse_system_messages",
227
+ "resolve_transcript",
228
+ "to_tool_declaration",
229
+ "declarations_equal",
230
+ "ToolStateChanges",
231
+ "get_tool_state_changes",
232
+ "get_declared_tools",
233
+ "has_tool_redefinitions",
234
+ "has_non_additive_tool_changes",
235
+ "TranscriptTools",
236
+ "resolve_transcript_tools",
237
+ "content_text",
238
+ "get_system_message_text",
239
+ "render_system_message_update",
240
+ # errors, retry, overflow
241
+ "ProviderHttpError",
242
+ "aclose_http_clients",
243
+ "is_context_overflow",
244
+ "is_recoverable_length",
245
+ "get_overflow_patterns",
246
+ "RetryPolicy",
247
+ "RetryCallbacks",
248
+ "DEFAULT_MAX_AGENT_RETRY_DELAY_MS",
249
+ "retry_delay_ms",
250
+ "retry_assistant_call",
251
+ "is_retryable_assistant_error",
252
+ # diagnostics
253
+ "AssistantMessageDiagnostic",
254
+ "DiagnosticErrorInfo",
255
+ "append_assistant_message_diagnostic",
256
+ "create_assistant_message_diagnostic",
257
+ "extract_diagnostic_error",
258
+ "format_thrown_value",
259
+ # misc
260
+ "uuidv7",
261
+ "cleanup_session_resources",
262
+ "register_session_resource_cleanup",
263
+ ]