askai-python 0.4.0__tar.gz → 0.5.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.
Files changed (54) hide show
  1. {askai_python-0.4.0 → askai_python-0.5.0}/PKG-INFO +67 -6
  2. askai_python-0.5.0/README.md +371 -0
  3. askai_python-0.5.0/ask_ai/__init__.py +79 -0
  4. askai_python-0.5.0/ask_ai/base.py +706 -0
  5. askai_python-0.5.0/ask_ai/capabilities.py +17 -0
  6. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/cli.py +5 -19
  7. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/config.py +21 -11
  8. askai_python-0.5.0/ask_ai/events.py +41 -0
  9. askai_python-0.5.0/ask_ai/exceptions.py +113 -0
  10. askai_python-0.5.0/ask_ai/media.py +477 -0
  11. askai_python-0.5.0/ask_ai/media_security.py +105 -0
  12. askai_python-0.5.0/ask_ai/observability.py +53 -0
  13. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/providers/anthropic_provider.py +31 -16
  14. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/providers/azure_provider.py +4 -2
  15. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/providers/google_provider.py +27 -14
  16. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/providers/groq_provider.py +22 -14
  17. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/providers/openai_provider.py +80 -53
  18. askai_python-0.5.0/ask_ai/providers/openrouter_provider.py +142 -0
  19. askai_python-0.5.0/ask_ai/requirements.txt +6 -0
  20. askai_python-0.5.0/ask_ai/router.py +107 -0
  21. askai_python-0.5.0/ask_ai/session.py +114 -0
  22. askai_python-0.5.0/ask_ai/structured.py +88 -0
  23. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/utils.py +3 -4
  24. {askai_python-0.4.0 → askai_python-0.5.0}/askai_python.egg-info/PKG-INFO +67 -6
  25. {askai_python-0.4.0 → askai_python-0.5.0}/askai_python.egg-info/SOURCES.txt +18 -1
  26. {askai_python-0.4.0 → askai_python-0.5.0}/askai_python.egg-info/requires.txt +6 -0
  27. {askai_python-0.4.0 → askai_python-0.5.0}/docs/PYPI_README.md +61 -5
  28. {askai_python-0.4.0 → askai_python-0.5.0}/pyproject.toml +4 -1
  29. askai_python-0.5.0/tests/test_capabilities.py +17 -0
  30. askai_python-0.5.0/tests/test_core.py +266 -0
  31. askai_python-0.5.0/tests/test_gitignore.py +12 -0
  32. askai_python-0.5.0/tests/test_media_security.py +193 -0
  33. askai_python-0.5.0/tests/test_observability.py +74 -0
  34. askai_python-0.5.0/tests/test_openrouter_release.py +70 -0
  35. askai_python-0.5.0/tests/test_python39_compat.py +13 -0
  36. askai_python-0.5.0/tests/test_router.py +60 -0
  37. askai_python-0.5.0/tests/test_session.py +81 -0
  38. askai_python-0.5.0/tests/test_streaming_events.py +79 -0
  39. askai_python-0.5.0/tests/test_structured.py +91 -0
  40. askai_python-0.4.0/README.md +0 -164
  41. askai_python-0.4.0/ask_ai/__init__.py +0 -51
  42. askai_python-0.4.0/ask_ai/base.py +0 -302
  43. askai_python-0.4.0/ask_ai/exceptions.py +0 -42
  44. askai_python-0.4.0/ask_ai/media.py +0 -90
  45. askai_python-0.4.0/ask_ai/providers/openrouter_provider.py +0 -66
  46. askai_python-0.4.0/ask_ai/requirements.txt +0 -5
  47. askai_python-0.4.0/tests/test_core.py +0 -38
  48. {askai_python-0.4.0 → askai_python-0.5.0}/LICENSE +0 -0
  49. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/__main__.py +0 -0
  50. {askai_python-0.4.0 → askai_python-0.5.0}/ask_ai/providers/__init__.py +4 -4
  51. {askai_python-0.4.0 → askai_python-0.5.0}/askai_python.egg-info/dependency_links.txt +0 -0
  52. {askai_python-0.4.0 → askai_python-0.5.0}/askai_python.egg-info/entry_points.txt +0 -0
  53. {askai_python-0.4.0 → askai_python-0.5.0}/askai_python.egg-info/top_level.txt +0 -0
  54. {askai_python-0.4.0 → askai_python-0.5.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: askai-python
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: AI Made Stupid Simple. Unified API for OpenAI, Groq, Google, Anthropic, and more.
5
5
  Author-email: Hossein Ghorbani <hosseingh1068@gmail.com>
6
6
  License: MIT
@@ -36,6 +36,9 @@ Provides-Extra: media
36
36
  Requires-Dist: Pillow>=9.0.0; extra == "media"
37
37
  Provides-Extra: httpx
38
38
  Requires-Dist: httpx>=0.24.0; extra == "httpx"
39
+ Provides-Extra: structured
40
+ Requires-Dist: pydantic>=1.10; extra == "structured"
41
+ Requires-Dist: jsonschema>=4.0; extra == "structured"
39
42
  Provides-Extra: all
40
43
  Requires-Dist: openai>=1.0.0; extra == "all"
41
44
  Requires-Dist: anthropic>=0.20.0; extra == "all"
@@ -43,6 +46,8 @@ Requires-Dist: google-generativeai>=0.5.0; extra == "all"
43
46
  Requires-Dist: groq>=0.4.0; extra == "all"
44
47
  Requires-Dist: Pillow>=9.0.0; extra == "all"
45
48
  Requires-Dist: httpx>=0.24.0; extra == "all"
49
+ Requires-Dist: pydantic>=1.10; extra == "all"
50
+ Requires-Dist: jsonschema>=4.0; extra == "all"
46
51
  Dynamic: license-file
47
52
 
48
53
  # askai-python 🚀
@@ -143,6 +148,54 @@ response = ai.ask(
143
148
  )
144
149
  ```
145
150
 
151
+ ## 🎨 Media Generation (Image & Audio)
152
+
153
+ Generate images or speech with compatible providers:
154
+
155
+ ```python
156
+ from ask_ai import OpenAI
157
+
158
+ ai = OpenAI()
159
+
160
+ # Generate an Image (DALL-E)
161
+ img_response = ai.ask("A majestic lion in a neon city", output_type="image")
162
+ img_response.save("lion.png")
163
+
164
+ # Generate Speech (TTS)
165
+ audio_response = ai.ask("Hello, this is a voice.", output_type="audio")
166
+ audio_response.save("welcome.mp3")
167
+ ```
168
+
169
+ ## 🔗 Provider Fallback
170
+
171
+ Never experience downtime by supplying fallback providers:
172
+
173
+ ```python
174
+ from ask_ai import OpenAI, Groq
175
+
176
+ ai = OpenAI()
177
+ response = ai.ask("Explain quantum physics", providers=[ai, Groq])
178
+ print(response.text)
179
+ ```
180
+
181
+ ## 📋 Structured Output (Pydantic Support)
182
+
183
+ Force LLMs to strictly respond matching a Pydantic schema:
184
+
185
+ ```python
186
+ from pydantic import BaseModel
187
+ from ask_ai import OpenAI
188
+
189
+ class User(BaseModel):
190
+ name: str
191
+ age: int
192
+
193
+ ai = OpenAI()
194
+ response = ai.ask("Extract name: Alice is 30.", response_model=User)
195
+ user = response.pydantic
196
+ print(user.name) # "Alice"
197
+ ```
198
+
146
199
  ## 🔌 Supported Providers
147
200
 
148
201
  | Provider | Class | Capabilities |
@@ -158,11 +211,19 @@ response = ai.ask(
158
211
 
159
212
  ## 🗺️ Roadmap
160
213
 
161
- - [x] Baseline multiple providers
162
- - [x] Automated Retry & Timeout controls
163
- - [ ] Async API (`await ask_async`)
164
- - [ ] Provider Fallback (`fallback=[Groq()]`)
165
- - [ ] Structured Outputs (Pydantic Support)
214
+ ### 🚀 Roadmap 2.0 (Active)
215
+ - [x] Provider Fallback chaining & Pydantic Structured Output support
216
+ - [ ] Multi-Modal Vision input (image to text) for all key providers
217
+ - [ ] Native support for tools/function calling execution
218
+ - [ ] Memory buffer / session-based conversation management
219
+
220
+ ### 🏁 Roadmap 1.0 (Completed)
221
+ - ~~[x] Baseline multiple providers~~
222
+ - ~~[x] Automated Retry & Timeout controls~~
223
+ - ~~[x] Async API (`await ask_async`)~~
224
+ - ~~[x] Streaming Support (`ask_stream` / `ask_stream_async`)~~
225
+ - ~~[x] Provider Fallback (`fallback=[Groq()]`)~~
226
+ - ~~[x] Structured Outputs (Pydantic Support)~~
166
227
 
167
228
  ---
168
229
 
@@ -0,0 +1,371 @@
1
+ # ask-ai
2
+
3
+ <p align="center">
4
+ 🌍 <b>Readme:</b>
5
+ <a href="README.md"><img src="https://flagcdn.com/20x15/us.png" alt="English"> English</a> ·
6
+ <a href="docs/README_fa.md"><img src="https://flagcdn.com/20x15/ir.png" alt="Persian"> فارسی</a> ·
7
+ <a href="docs/README_zh.md"><img src="https://flagcdn.com/20x15/cn.png" alt="Chinese"> 中文</a> ·
8
+ <a href="docs/README_tr.md"><img src="https://flagcdn.com/20x15/tr.png" alt="Turkish"> Türkçe</a> ·
9
+ <a href="docs/README_ar.md"><img src="https://flagcdn.com/20x15/sa.png" alt="Arabic"> العربية</a> ·
10
+ <a href="docs/README_ru.md"><img src="https://flagcdn.com/20x15/ru.png" alt="Russian"> Русский</a> ·
11
+ <a href="docs/README_es.md"><img src="https://flagcdn.com/20x15/es.png" alt="Spanish"> Español</a> ·
12
+ <a href="docs/README_ja.md"><img src="https://flagcdn.com/20x15/jp.png" alt="Japanese"> 日本語</a>
13
+ </p>
14
+
15
+
16
+ <p align="center">
17
+ <img src="assets/banner.svg" alt="ask-ai animated banner" width="100%">
18
+ </p>
19
+
20
+ <p align="center">
21
+ <b>A minimal Python SDK to switch between LLM providers in one line.</b><br/>
22
+ No frameworks. No servers. No overengineering.
23
+ </p>
24
+
25
+
26
+ [![PyPI version](https://img.shields.io/pypi/v/askai-python.svg)](https://pypi.org/project/askai-python/)
27
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
28
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
29
+
30
+
31
+
32
+ ---
33
+
34
+ ## ⚡ Quick Start (5 seconds)
35
+
36
+ ```bash
37
+ pip install askai-python
38
+ ```
39
+
40
+ ```python
41
+ from ask_ai import OpenAI, Groq
42
+
43
+ # Auto-detects OPENAI_API_KEY from environment
44
+ OpenAI().ask("Explain black holes like I'm 5").text
45
+
46
+ # Switch provider effortlessly
47
+ Groq().ask("Explain black holes like I'm 5").text
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 🧐 Why ask-ai?
53
+
54
+ - **One function**: Just call `.ask()`
55
+ - **Multiple providers**: OpenAI, Anthropic, Google Gemini, Groq, Azure, OpenRouter
56
+ - **Zero config**: Keys are pulled from the environment automatically
57
+ - **SDK-first, not a framework**: It stays out of your way.
58
+
59
+ ## 🚫 What this project is NOT
60
+
61
+ > ❌ Not an AI framework
62
+ > ❌ Not an API gateway
63
+ > ❌ Not an agent memory system
64
+
65
+ It does one thing perfectly: **Simplifying the API call to LLMs.**
66
+
67
+ ---
68
+
69
+ ## 🛠️ Advanced Usage
70
+
71
+ ### 🧰 Developer QoL Utilities (Auto-Parsing)
72
+
73
+ <p align="center">
74
+ <img src="assets/features.svg" alt="ask-ai features parsing banner" width="100%">
75
+ </p>
76
+ Stop writing Regex to clean up model outputs! `ask-ai` comes with built-in text processing flags:
77
+
78
+ ```python
79
+ from ask_ai import OpenAI
80
+ ai = OpenAI()
81
+
82
+ # 1. Clean Markdown (Removes ```json and ``` tags)
83
+ # Perfect for extracting raw data from models that wrap everything in markdown
84
+ clean_text = ai.ask("Write JSON", clean=True).text
85
+
86
+ # 2. Extract Code (Returns ONLY the code block, ignores conversational filler)
87
+ # Great for automation pipelines
88
+ code = ai.ask("Write a python ping script", code=True).text
89
+
90
+ # 3. Strip Tags (Removes <think> blocks and HTML)
91
+ # Essential for reasoning models like DeepSeek-R1
92
+ answer_only = ai.ask("What is 1+1?", strip=True).text
93
+
94
+ # 4. Enforce & Parse JSON (Directly returns a Parsed Python Dictionary)
95
+ # Adds JSON instructions to the prompt and safely runs json.loads()
96
+ data_dict = ai.ask("Extract user info", json=True).json
97
+ print(data_dict['name'])
98
+ ```
99
+
100
+ ### 🔄 Built-in Retries & Timeout (Resiliency)
101
+
102
+ <p align="center">
103
+ <img src="assets/resiliency.svg" alt="ask-ai resiliency banner" width="100%">
104
+ </p>
105
+ Handle rate limits (`429`) and network drops automatically:
106
+
107
+ ```python
108
+ from ask_ai import OpenAI
109
+ ai = OpenAI()
110
+
111
+ # Will retry up to 3 times on RateLimit/Network errors, with generic timeout
112
+ response = ai.ask("Write a script", retry=3, timeout=10)
113
+ ```
114
+
115
+ ### System Configuration
116
+ Set system prompts and temperature directly:
117
+
118
+ ```python
119
+ ai.advanced(
120
+ temperature=0.7,
121
+ prompt="You are a senior DevOps engineer."
122
+ )
123
+
124
+ print(ai.ask("How do I optimize a Dockerfile?").text)
125
+ ```
126
+
127
+ ---
128
+
129
+ ### 🚀 Async Support (FastAPI / Aiogram)
130
+
131
+ `ask-ai` works perfectly in asynchronous environments:
132
+
133
+ ```python
134
+ import asyncio
135
+ from ask_ai import OpenAI
136
+
137
+ async def main():
138
+ ai = OpenAI()
139
+ # Runs non-blocking in your event loop
140
+ response = await ai.ask_async("What is the capital of France?")
141
+ print(response.text)
142
+
143
+ asyncio.run(main())
144
+ ```
145
+
146
+ ---
147
+
148
+ ### 🌊 Streaming Support (Sync & Async)
149
+
150
+ Stream responses token-by-token easily:
151
+
152
+ ```python
153
+ from ask_ai import OpenAI
154
+
155
+ ai = OpenAI()
156
+
157
+ # Sync Streaming
158
+ for chunk in ai.ask_stream("Write a short story about a blue dragon"):
159
+ print(chunk, end="", flush=True)
160
+
161
+ # Async Streaming
162
+ async def stream_example():
163
+ async for chunk in ai.ask_stream_async("Write a short story"):
164
+ print(chunk, end="", flush=True)
165
+ ```
166
+
167
+ ---
168
+
169
+ ### 🎨 Media Generation (Image & Audio)
170
+
171
+ Generate images or speech with compatible providers:
172
+
173
+ ```python
174
+ from ask_ai import OpenAI
175
+
176
+ ai = OpenAI()
177
+
178
+ # Generate an Image (DALL-E)
179
+ img_response = ai.ask("A majestic lion in a neon city", output_type="image")
180
+ img_response.save("lion.png")
181
+
182
+ # Generate Speech (TTS)
183
+ audio_response = ai.ask("Hello, this is a generated voice.", output_type="audio")
184
+ audio_response.save("welcome.mp3")
185
+ ```
186
+
187
+ ---
188
+
189
+ ### 🔗 Provider Fallback
190
+
191
+ Never experience downtime by supplying alternative fallback providers:
192
+
193
+ ```python
194
+ from ask_ai import OpenAI, Groq
195
+
196
+ ai = OpenAI()
197
+
198
+ # If OpenAI fails or rate-limits, it automatically switches to Groq
199
+ response = ai.ask("Explain quantum physics", providers=[ai, Groq])
200
+ print(response.text)
201
+ ```
202
+
203
+ ---
204
+
205
+ ### 📋 Structured Output (Pydantic Support)
206
+
207
+ Force LLMs to strictly respond matching a Pydantic schema:
208
+
209
+ ```python
210
+ from pydantic import BaseModel
211
+ from ask_ai import OpenAI
212
+
213
+ class User(BaseModel):
214
+ name: str
215
+ age: int
216
+
217
+ ai = OpenAI()
218
+ response = ai.ask("Extract name: Alice is 30 years old.", response_model=User)
219
+
220
+ user = response.pydantic
221
+ print(user.name) # "Alice"
222
+ print(user.age) # 30
223
+ ```
224
+
225
+ ### ✅ Validated Structured Responses
226
+
227
+ Structured responses support Pydantic models, dataclasses, `TypedDict`, and JSON
228
+ Schema dictionaries. The raw provider text remains available separately:
229
+
230
+ ```python
231
+ from dataclasses import dataclass
232
+ from ask_ai import OpenAI
233
+
234
+ @dataclass
235
+ class User:
236
+ name: str
237
+ age: int
238
+
239
+ response = OpenAI().ask(
240
+ "Extract: Alice is 30.",
241
+ response_model=User,
242
+ validation_retries=2,
243
+ )
244
+ print(response.raw)
245
+ print(response.parsed.name)
246
+ ```
247
+
248
+ ### Streaming Events
249
+
250
+ Use typed events for text, completion, and errors while keeping the legacy
251
+ `ask_stream()` API unchanged:
252
+
253
+ ```python
254
+ from ask_ai import Completed, OpenAI, TextDelta
255
+
256
+ for event in OpenAI().ask_stream_events("Tell me a story"):
257
+ if isinstance(event, TextDelta):
258
+ print(event.text, end="")
259
+ elif isinstance(event, Completed):
260
+ print("\nDone")
261
+ ```
262
+
263
+ ### 📊 Observability
264
+
265
+ Attach optional middleware to receive provider, model, latency, and retry
266
+ metadata. Provider usage extraction and failure-reason reporting are not
267
+ supported yet. Estimated cost is only calculated when a response already
268
+ contains usage data; the bundled provider adapters do not currently supply it:
269
+
270
+ ```python
271
+ from ask_ai import Observability, OpenAI
272
+
273
+ ai = OpenAI().use(Observability(on_event=print))
274
+ response = ai.ask("Explain tracing")
275
+ print(response.metadata.latency_ms)
276
+ ```
277
+
278
+ ### Provider Capabilities
279
+
280
+ Inspect advisory capability metadata before selecting a provider:
281
+
282
+ ```python
283
+ from ask_ai import OpenAI
284
+
285
+ capabilities = OpenAI().capabilities()
286
+ if capabilities.structured_output:
287
+ print("Structured output is available")
288
+ ```
289
+
290
+ ### Smart Router
291
+
292
+ Route requests across providers using deterministic `cheapest`, `fastest`, or
293
+ `most_reliable` policies. Supply static `profiles` for meaningful ordering:
294
+
295
+ ```python
296
+ from ask_ai import Groq, OpenAI, Router
297
+
298
+ openai = OpenAI() # Requires OPENAI_API_KEY
299
+ groq = Groq() # Requires GROQ_API_KEY
300
+ router = Router(
301
+ [openai, groq],
302
+ policy="fastest",
303
+ profiles={
304
+ "OpenAIProvider": {"latency_ms": 100},
305
+ "GroqProvider": {"latency_ms": 50},
306
+ },
307
+ )
308
+ response = router.ask("Explain routing")
309
+ ```
310
+
311
+ ### 🔒 Secure Media Downloads
312
+
313
+ Provider media downloads can be constrained by HTTPS, host, detected MIME, size,
314
+ and timeout policy. DNS results resolving to private, loopback, link-local, or
315
+ reserved IP addresses are rejected by default. `allowed_hosts` is optional;
316
+ set it for an explicit hostname allowlist. Only opt in to `allow_private=True`
317
+ when downloading from trusted private-network hosts. Redirects are rejected:
318
+
319
+ ```python
320
+ from ask_ai import MediaPolicy, download_media
321
+
322
+ data = download_media(
323
+ "https://example.com/image.png",
324
+ MediaPolicy(
325
+ max_bytes=10 * 1024 * 1024,
326
+ allowed_mime_types={"image/png"},
327
+ allowed_hosts={"example.com"},
328
+ ),
329
+ )
330
+ ```
331
+
332
+ ### Conversation Sessions
333
+
334
+ Create optional in-memory conversation state without changing the normal
335
+ provider API:
336
+
337
+ ```python
338
+ session = OpenAI().session(max_messages=20)
339
+ session.ask("My name is Ada.")
340
+ print(session.ask("What is my name?").text)
341
+ ```
342
+
343
+ Session requests do not support `response_model` validation yet.
344
+
345
+ ---
346
+
347
+ ## 🗺️ Roadmap
348
+
349
+ ### 🚀 Roadmap 2.0 (Active)
350
+ - [x] Provider Fallback chaining & Pydantic Structured Output support
351
+ - [x] Multi-Modal Vision input (image to text) for all key providers
352
+ - [ ] Native support for tools/function calling execution
353
+ - [x] Optional in-memory session-based conversation management
354
+
355
+ ### 🏁 Roadmap 1.0 (Completed)
356
+ - ~~[x] OpenAI, Groq, Gemini, Anthropic, Azure, OpenRouter support~~
357
+ - ~~[x] Text to Image (DALL-E) and Text to Audio~~
358
+ - ~~[x] Automated Retry & Timeout controls~~
359
+ - ~~[x] Async Support (`await ask_async`)~~
360
+ - ~~[x] Streaming Support (`ask_stream` / `ask_stream_async`)~~
361
+ - ~~[x] Provider Fallback (`ask(..., providers=[OpenAI, Groq])`)~~
362
+ - ~~[x] Structured Output (Pydantic Support)~~
363
+
364
+ ---
365
+
366
+ ## 🔗 Important Links
367
+
368
+ - **PyPI**: [askai-python](https://pypi.org/project/askai-python/)
369
+ - **GitHub Repository**: [Hosseinghorbani0/ask-ai](https://github.com/Hosseinghorbani0/ask-ai) (Star us! ⭐)
370
+ - **Official Website**: [hosseinghorbani0.ir](https://hosseinghorbani0.ir/)
371
+ - **Bug Tracker**: [Report an Issue](https://github.com/Hosseinghorbani0/ask-ai/issues)
@@ -0,0 +1,79 @@
1
+ """
2
+ ask-ai: A minimal Python SDK to switch between LLM providers in one line.
3
+ """
4
+
5
+ __version__ = "0.5.0"
6
+
7
+ from .base import Response
8
+ from .capabilities import Capabilities
9
+ from .config import AdvancedConfig
10
+ from .events import Completed, Error, TextDelta, ToolCall, UsageUpdate
11
+ from .exceptions import (
12
+ AskAIConfigError,
13
+ AskAIError,
14
+ AskAINetworkError,
15
+ AskAIParsingError,
16
+ AskAIRateLimitError,
17
+ MediaSecurityError,
18
+ MediaTypeNotSupportedError,
19
+ ProviderAuthError,
20
+ ProviderError,
21
+ ProviderInvalidRequestError,
22
+ ProviderRateLimitError,
23
+ ProviderTimeoutError,
24
+ ProviderUnavailableError,
25
+ StreamNotSupportedError,
26
+ StructuredValidationError,
27
+ )
28
+ from .media import AudioObject, ImageObject
29
+ from .media_security import MediaPolicy, download_media
30
+ from .observability import Observability, ResponseMetadata, Usage
31
+ from .providers import Anthropic, Azure, Google, Groq, OpenAI, OpenRouter
32
+ from .router import Router
33
+ from .session import ConversationSession
34
+ from .structured import parse_structured
35
+
36
+ __all__ = [
37
+ # Providers
38
+ "OpenAI",
39
+ "Anthropic",
40
+ "Google",
41
+ "Groq",
42
+ "Azure",
43
+ "OpenRouter",
44
+ # Core
45
+ "AdvancedConfig",
46
+ "Response",
47
+ "ImageObject",
48
+ "AudioObject",
49
+ # Exceptions
50
+ "AskAIError",
51
+ "AskAIConfigError",
52
+ "AskAINetworkError",
53
+ "AskAIRateLimitError",
54
+ "AskAIParsingError",
55
+ "ProviderError",
56
+ "ProviderAuthError",
57
+ "ProviderRateLimitError",
58
+ "ProviderTimeoutError",
59
+ "ProviderInvalidRequestError",
60
+ "ProviderUnavailableError",
61
+ "MediaTypeNotSupportedError",
62
+ "MediaSecurityError",
63
+ "StreamNotSupportedError",
64
+ "StructuredValidationError",
65
+ "parse_structured",
66
+ "TextDelta",
67
+ "ToolCall",
68
+ "UsageUpdate",
69
+ "Completed",
70
+ "Error",
71
+ "Observability",
72
+ "ResponseMetadata",
73
+ "Usage",
74
+ "Capabilities",
75
+ "Router",
76
+ "ConversationSession",
77
+ "MediaPolicy",
78
+ "download_media",
79
+ ]