daz-agent-sdk 0.1.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.
- daz_agent_sdk-0.1.0/PKG-INFO +289 -0
- daz_agent_sdk-0.1.0/README.md +274 -0
- daz_agent_sdk-0.1.0/pyproject.toml +37 -0
- daz_agent_sdk-0.1.0/setup.cfg +4 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/__init__.py +35 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/capabilities/__init__.py +0 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/capabilities/image.py +205 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/capabilities/image_test.py +273 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/capabilities/stt.py +131 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/capabilities/stt_test.py +74 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/capabilities/tts.py +150 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/capabilities/tts_test.py +115 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/config.py +356 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/config_test.py +407 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/conversation.py +261 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/conversation_test.py +382 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/core.py +264 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/fallback.py +217 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/fallback_test.py +394 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/logging_.py +101 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/logging_test.py +266 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/main.py +89 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/__init__.py +0 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/base.py +79 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/claude.py +339 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/claude_test.py +185 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/codex.py +267 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/codex_test.py +175 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/gemini.py +290 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/gemini_test.py +184 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/ollama.py +292 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/providers/ollama_test.py +314 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/registry.py +217 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/registry_test.py +256 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/types.py +183 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk/types_test.py +244 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk.egg-info/PKG-INFO +289 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk.egg-info/SOURCES.txt +40 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk.egg-info/dependency_links.txt +1 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk.egg-info/entry_points.txt +2 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk.egg-info/requires.txt +4 -0
- daz_agent_sdk-0.1.0/src/daz_agent_sdk.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: daz-agent-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Provider-agnostic AI library with tier-based routing and automatic fallback.
|
|
5
|
+
Author-email: Darren Oakey <darren@oakey.net>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Requires-Dist: pydantic>=2.0
|
|
13
|
+
Requires-Dist: aiohttp>=3.9
|
|
14
|
+
Requires-Dist: setproctitle>=1.3
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
# daz-agent-sdk
|
|
19
|
+
|
|
20
|
+
**One library for all your AI needs.** Text, images, speech — from any provider, with automatic fallback if one goes down.
|
|
21
|
+
|
|
22
|
+
Stop writing boilerplate. Stop worrying about rate limits. Just tell it what you need.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from daz_agent_sdk import agent
|
|
26
|
+
|
|
27
|
+
answer = await agent.ask("Explain quantum tunnelling in one paragraph")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That's it. Behind the scenes, daz-agent-sdk picks the best available model, handles errors, and falls back to another provider if anything goes wrong. You never write retry logic again.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Getting Started
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Clone and install
|
|
38
|
+
git clone <repo-url> && cd daz-agent-sdk
|
|
39
|
+
./run install
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This installs daz-agent-sdk as an editable package so you can `import daz_agent_sdk` from anywhere.
|
|
43
|
+
|
|
44
|
+
**Quick test from the command line:**
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
./run ask "What's the capital of France?"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Or in Python:**
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from daz_agent_sdk import agent
|
|
54
|
+
|
|
55
|
+
answer = await agent.ask("What's the capital of France?")
|
|
56
|
+
print(answer.text)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## What Can It Do?
|
|
62
|
+
|
|
63
|
+
### Ask Questions
|
|
64
|
+
|
|
65
|
+
The simplest thing — ask a question, get an answer.
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
answer = await agent.ask("Summarise this article", tier=Tier.LOW)
|
|
69
|
+
print(answer.text)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use **tiers** to balance quality vs. speed:
|
|
73
|
+
|
|
74
|
+
| Tier | What You Get | When to Use |
|
|
75
|
+
|------|-------------|-------------|
|
|
76
|
+
| `Tier.HIGH` | Best available model (default) | Important tasks, creative writing |
|
|
77
|
+
| `Tier.MEDIUM` | Balanced quality and speed | Most everyday tasks |
|
|
78
|
+
| `Tier.LOW` | Fast and cheap | Summaries, simple classification |
|
|
79
|
+
| `Tier.FREE_FAST` | Local models, zero cost | Bulk processing, prototyping |
|
|
80
|
+
| `Tier.FREE_THINKING` | Local models, deeper reasoning | Complex local analysis |
|
|
81
|
+
|
|
82
|
+
### Get Structured Data Back
|
|
83
|
+
|
|
84
|
+
Pass a Pydantic model and get validated, typed data — not just text.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from pydantic import BaseModel
|
|
88
|
+
|
|
89
|
+
class Sentiment(BaseModel):
|
|
90
|
+
label: str # positive, negative, neutral
|
|
91
|
+
confidence: float
|
|
92
|
+
|
|
93
|
+
result = await agent.ask(
|
|
94
|
+
"Classify: 'I love this product'",
|
|
95
|
+
schema=Sentiment,
|
|
96
|
+
tier=Tier.LOW,
|
|
97
|
+
)
|
|
98
|
+
print(result.parsed.label) # "positive"
|
|
99
|
+
print(result.parsed.confidence) # 0.95
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Have a Conversation
|
|
103
|
+
|
|
104
|
+
Multi-turn conversations that remember context.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
async with agent.conversation("writing-session") as chat:
|
|
108
|
+
outline = await chat.say("Write an outline for a thriller novel")
|
|
109
|
+
|
|
110
|
+
chapter = await chat.say("Now write chapter 1 based on that outline")
|
|
111
|
+
|
|
112
|
+
# Stream long responses chunk by chunk
|
|
113
|
+
async for chunk in chat.stream("Write chapter 2"):
|
|
114
|
+
print(chunk, end="", flush=True)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Conversations handle rate limits transparently — if your provider goes down mid-conversation, daz-agent-sdk backs off, summarises the conversation so far, and picks up seamlessly on another provider.
|
|
118
|
+
|
|
119
|
+
### Generate Images
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
result = await agent.image(
|
|
123
|
+
"A cyberpunk city at sunset",
|
|
124
|
+
width=1024,
|
|
125
|
+
height=1024,
|
|
126
|
+
output="city.jpg",
|
|
127
|
+
)
|
|
128
|
+
print(result.path)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Tier controls quality here too — `HIGH` gives you more detail, `LOW` gives you a quick draft in seconds.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
# Quick draft for previewing (~5 seconds)
|
|
135
|
+
draft = await agent.image("Robot logo", tier=Tier.LOW)
|
|
136
|
+
|
|
137
|
+
# Transparent background
|
|
138
|
+
logo = await agent.image("Company logo", transparent=True, output="logo.png")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Text-to-Speech
|
|
142
|
+
|
|
143
|
+
Turn text into spoken audio.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
audio = await agent.speak(
|
|
147
|
+
"Welcome to the show, folks.",
|
|
148
|
+
voice="gary",
|
|
149
|
+
output="intro.mp3",
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Speech-to-Text
|
|
154
|
+
|
|
155
|
+
Transcribe audio files.
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
text = await agent.transcribe("recording.wav")
|
|
159
|
+
print(text)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### See What's Available
|
|
163
|
+
|
|
164
|
+
List all models you can use right now.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
all_models = await agent.models()
|
|
168
|
+
|
|
169
|
+
# Filter by what you need
|
|
170
|
+
local_models = await agent.models(provider="ollama")
|
|
171
|
+
fast_text = await agent.models(tier=Tier.LOW, capability=Capability.TEXT)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Using the CLI
|
|
177
|
+
|
|
178
|
+
You don't need to write Python to use daz-agent-sdk.
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Ask a question
|
|
182
|
+
./run ask "What year was Python created?"
|
|
183
|
+
|
|
184
|
+
# Pick a tier
|
|
185
|
+
./run ask --tier low "Summarise this paragraph: ..."
|
|
186
|
+
|
|
187
|
+
# List available models
|
|
188
|
+
./run models
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Configuration
|
|
194
|
+
|
|
195
|
+
daz-agent-sdk works with **zero configuration** — it picks sensible defaults automatically.
|
|
196
|
+
|
|
197
|
+
If you want to customise things, create `~/.daz-agent-sdk/config.yaml`:
|
|
198
|
+
|
|
199
|
+
```yaml
|
|
200
|
+
# Map tiers to your preferred providers
|
|
201
|
+
tiers:
|
|
202
|
+
high:
|
|
203
|
+
- claude:claude-opus-4-6
|
|
204
|
+
- gemini:gemini-2.5-pro
|
|
205
|
+
medium:
|
|
206
|
+
- claude:claude-sonnet-4-6
|
|
207
|
+
- gemini:gemini-2.5-flash
|
|
208
|
+
low:
|
|
209
|
+
- claude:claude-haiku-4-5-20251001
|
|
210
|
+
- ollama:qwen3-8b
|
|
211
|
+
free_fast:
|
|
212
|
+
- ollama:qwen3-8b
|
|
213
|
+
|
|
214
|
+
# Provider settings
|
|
215
|
+
providers:
|
|
216
|
+
ollama:
|
|
217
|
+
base_url: http://localhost:11434
|
|
218
|
+
gemini:
|
|
219
|
+
api_key_env: GEMINI_API_KEY
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Each tier lists providers in order of preference. If the first one fails, it tries the next. You choose what "best" means for your setup.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Supported Providers
|
|
227
|
+
|
|
228
|
+
| Provider | What You Need |
|
|
229
|
+
|----------|--------------|
|
|
230
|
+
| **Claude** | Anthropic API access (or Claude Code auth) |
|
|
231
|
+
| **Codex** | OpenAI API key |
|
|
232
|
+
| **Gemini** | Google AI API key |
|
|
233
|
+
| **Ollama** | Ollama running locally (`ollama serve`) |
|
|
234
|
+
|
|
235
|
+
Don't have all of them? No problem. daz-agent-sdk skips any provider that isn't available and uses what you've got.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Automatic Fallback
|
|
240
|
+
|
|
241
|
+
This is the killer feature. You never write retry logic.
|
|
242
|
+
|
|
243
|
+
**For single questions:** If your preferred provider hits a rate limit, daz-agent-sdk immediately tries the next one. No delay, no waiting.
|
|
244
|
+
|
|
245
|
+
**For conversations:** It tries exponential backoff first (maybe the rate limit clears in a few seconds). If that doesn't work, it summarises the conversation and seamlessly continues on another provider. Your code never knows the switch happened.
|
|
246
|
+
|
|
247
|
+
**Auth errors** skip the provider entirely. **Bad requests** (your bug) raise immediately so you can fix them. Everything is logged so you can debug later.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Logging
|
|
252
|
+
|
|
253
|
+
Every conversation is automatically logged to `~/.daz-agent-sdk/logs/`. Each conversation gets its own folder with:
|
|
254
|
+
|
|
255
|
+
- What was said
|
|
256
|
+
- Which models were used
|
|
257
|
+
- Any fallbacks that happened
|
|
258
|
+
- Timing and token usage
|
|
259
|
+
|
|
260
|
+
Useful for debugging, cost tracking, or just seeing what happened.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Tips and Tricks
|
|
265
|
+
|
|
266
|
+
**Start with defaults.** Don't configure anything until you need to. `Tier.HIGH` and zero config will get you going immediately.
|
|
267
|
+
|
|
268
|
+
**Use tiers, not provider names.** Say `Tier.LOW` instead of hardcoding `ollama:qwen3-8b`. That way you can swap providers later without changing any code.
|
|
269
|
+
|
|
270
|
+
**Use structured output for anything machine-readable.** Instead of parsing text with regex, pass a Pydantic schema and get clean, validated data back.
|
|
271
|
+
|
|
272
|
+
**Stream long responses.** For anything that might take a while (long text generation, creative writing), use `chat.stream()` so the user sees progress immediately.
|
|
273
|
+
|
|
274
|
+
**Fork conversations to explore alternatives.** Working on something creative? Fork the conversation to try a different direction without losing where you were.
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
async with agent.conversation("brainstorm") as chat:
|
|
278
|
+
await chat.say("Give me three story ideas")
|
|
279
|
+
|
|
280
|
+
branch_a = chat.fork("dark-thriller")
|
|
281
|
+
branch_b = chat.fork("comedy")
|
|
282
|
+
|
|
283
|
+
await branch_a.say("Develop the first idea as a dark thriller")
|
|
284
|
+
await branch_b.say("Develop the first idea as a comedy")
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Use `FREE_FAST` for bulk work.** Processing hundreds of items? Local models cost nothing and won't rate-limit you.
|
|
288
|
+
|
|
289
|
+
**Let the fallback do its job.** Don't try to handle provider errors yourself. That's what daz-agent-sdk is for.
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# daz-agent-sdk
|
|
4
|
+
|
|
5
|
+
**One library for all your AI needs.** Text, images, speech — from any provider, with automatic fallback if one goes down.
|
|
6
|
+
|
|
7
|
+
Stop writing boilerplate. Stop worrying about rate limits. Just tell it what you need.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from daz_agent_sdk import agent
|
|
11
|
+
|
|
12
|
+
answer = await agent.ask("Explain quantum tunnelling in one paragraph")
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
That's it. Behind the scenes, daz-agent-sdk picks the best available model, handles errors, and falls back to another provider if anything goes wrong. You never write retry logic again.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Getting Started
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Clone and install
|
|
23
|
+
git clone <repo-url> && cd daz-agent-sdk
|
|
24
|
+
./run install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This installs daz-agent-sdk as an editable package so you can `import daz_agent_sdk` from anywhere.
|
|
28
|
+
|
|
29
|
+
**Quick test from the command line:**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
./run ask "What's the capital of France?"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Or in Python:**
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from daz_agent_sdk import agent
|
|
39
|
+
|
|
40
|
+
answer = await agent.ask("What's the capital of France?")
|
|
41
|
+
print(answer.text)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## What Can It Do?
|
|
47
|
+
|
|
48
|
+
### Ask Questions
|
|
49
|
+
|
|
50
|
+
The simplest thing — ask a question, get an answer.
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
answer = await agent.ask("Summarise this article", tier=Tier.LOW)
|
|
54
|
+
print(answer.text)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Use **tiers** to balance quality vs. speed:
|
|
58
|
+
|
|
59
|
+
| Tier | What You Get | When to Use |
|
|
60
|
+
|------|-------------|-------------|
|
|
61
|
+
| `Tier.HIGH` | Best available model (default) | Important tasks, creative writing |
|
|
62
|
+
| `Tier.MEDIUM` | Balanced quality and speed | Most everyday tasks |
|
|
63
|
+
| `Tier.LOW` | Fast and cheap | Summaries, simple classification |
|
|
64
|
+
| `Tier.FREE_FAST` | Local models, zero cost | Bulk processing, prototyping |
|
|
65
|
+
| `Tier.FREE_THINKING` | Local models, deeper reasoning | Complex local analysis |
|
|
66
|
+
|
|
67
|
+
### Get Structured Data Back
|
|
68
|
+
|
|
69
|
+
Pass a Pydantic model and get validated, typed data — not just text.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from pydantic import BaseModel
|
|
73
|
+
|
|
74
|
+
class Sentiment(BaseModel):
|
|
75
|
+
label: str # positive, negative, neutral
|
|
76
|
+
confidence: float
|
|
77
|
+
|
|
78
|
+
result = await agent.ask(
|
|
79
|
+
"Classify: 'I love this product'",
|
|
80
|
+
schema=Sentiment,
|
|
81
|
+
tier=Tier.LOW,
|
|
82
|
+
)
|
|
83
|
+
print(result.parsed.label) # "positive"
|
|
84
|
+
print(result.parsed.confidence) # 0.95
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Have a Conversation
|
|
88
|
+
|
|
89
|
+
Multi-turn conversations that remember context.
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
async with agent.conversation("writing-session") as chat:
|
|
93
|
+
outline = await chat.say("Write an outline for a thriller novel")
|
|
94
|
+
|
|
95
|
+
chapter = await chat.say("Now write chapter 1 based on that outline")
|
|
96
|
+
|
|
97
|
+
# Stream long responses chunk by chunk
|
|
98
|
+
async for chunk in chat.stream("Write chapter 2"):
|
|
99
|
+
print(chunk, end="", flush=True)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Conversations handle rate limits transparently — if your provider goes down mid-conversation, daz-agent-sdk backs off, summarises the conversation so far, and picks up seamlessly on another provider.
|
|
103
|
+
|
|
104
|
+
### Generate Images
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
result = await agent.image(
|
|
108
|
+
"A cyberpunk city at sunset",
|
|
109
|
+
width=1024,
|
|
110
|
+
height=1024,
|
|
111
|
+
output="city.jpg",
|
|
112
|
+
)
|
|
113
|
+
print(result.path)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Tier controls quality here too — `HIGH` gives you more detail, `LOW` gives you a quick draft in seconds.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Quick draft for previewing (~5 seconds)
|
|
120
|
+
draft = await agent.image("Robot logo", tier=Tier.LOW)
|
|
121
|
+
|
|
122
|
+
# Transparent background
|
|
123
|
+
logo = await agent.image("Company logo", transparent=True, output="logo.png")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Text-to-Speech
|
|
127
|
+
|
|
128
|
+
Turn text into spoken audio.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
audio = await agent.speak(
|
|
132
|
+
"Welcome to the show, folks.",
|
|
133
|
+
voice="gary",
|
|
134
|
+
output="intro.mp3",
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Speech-to-Text
|
|
139
|
+
|
|
140
|
+
Transcribe audio files.
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
text = await agent.transcribe("recording.wav")
|
|
144
|
+
print(text)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### See What's Available
|
|
148
|
+
|
|
149
|
+
List all models you can use right now.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
all_models = await agent.models()
|
|
153
|
+
|
|
154
|
+
# Filter by what you need
|
|
155
|
+
local_models = await agent.models(provider="ollama")
|
|
156
|
+
fast_text = await agent.models(tier=Tier.LOW, capability=Capability.TEXT)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Using the CLI
|
|
162
|
+
|
|
163
|
+
You don't need to write Python to use daz-agent-sdk.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Ask a question
|
|
167
|
+
./run ask "What year was Python created?"
|
|
168
|
+
|
|
169
|
+
# Pick a tier
|
|
170
|
+
./run ask --tier low "Summarise this paragraph: ..."
|
|
171
|
+
|
|
172
|
+
# List available models
|
|
173
|
+
./run models
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Configuration
|
|
179
|
+
|
|
180
|
+
daz-agent-sdk works with **zero configuration** — it picks sensible defaults automatically.
|
|
181
|
+
|
|
182
|
+
If you want to customise things, create `~/.daz-agent-sdk/config.yaml`:
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
# Map tiers to your preferred providers
|
|
186
|
+
tiers:
|
|
187
|
+
high:
|
|
188
|
+
- claude:claude-opus-4-6
|
|
189
|
+
- gemini:gemini-2.5-pro
|
|
190
|
+
medium:
|
|
191
|
+
- claude:claude-sonnet-4-6
|
|
192
|
+
- gemini:gemini-2.5-flash
|
|
193
|
+
low:
|
|
194
|
+
- claude:claude-haiku-4-5-20251001
|
|
195
|
+
- ollama:qwen3-8b
|
|
196
|
+
free_fast:
|
|
197
|
+
- ollama:qwen3-8b
|
|
198
|
+
|
|
199
|
+
# Provider settings
|
|
200
|
+
providers:
|
|
201
|
+
ollama:
|
|
202
|
+
base_url: http://localhost:11434
|
|
203
|
+
gemini:
|
|
204
|
+
api_key_env: GEMINI_API_KEY
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Each tier lists providers in order of preference. If the first one fails, it tries the next. You choose what "best" means for your setup.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Supported Providers
|
|
212
|
+
|
|
213
|
+
| Provider | What You Need |
|
|
214
|
+
|----------|--------------|
|
|
215
|
+
| **Claude** | Anthropic API access (or Claude Code auth) |
|
|
216
|
+
| **Codex** | OpenAI API key |
|
|
217
|
+
| **Gemini** | Google AI API key |
|
|
218
|
+
| **Ollama** | Ollama running locally (`ollama serve`) |
|
|
219
|
+
|
|
220
|
+
Don't have all of them? No problem. daz-agent-sdk skips any provider that isn't available and uses what you've got.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Automatic Fallback
|
|
225
|
+
|
|
226
|
+
This is the killer feature. You never write retry logic.
|
|
227
|
+
|
|
228
|
+
**For single questions:** If your preferred provider hits a rate limit, daz-agent-sdk immediately tries the next one. No delay, no waiting.
|
|
229
|
+
|
|
230
|
+
**For conversations:** It tries exponential backoff first (maybe the rate limit clears in a few seconds). If that doesn't work, it summarises the conversation and seamlessly continues on another provider. Your code never knows the switch happened.
|
|
231
|
+
|
|
232
|
+
**Auth errors** skip the provider entirely. **Bad requests** (your bug) raise immediately so you can fix them. Everything is logged so you can debug later.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Logging
|
|
237
|
+
|
|
238
|
+
Every conversation is automatically logged to `~/.daz-agent-sdk/logs/`. Each conversation gets its own folder with:
|
|
239
|
+
|
|
240
|
+
- What was said
|
|
241
|
+
- Which models were used
|
|
242
|
+
- Any fallbacks that happened
|
|
243
|
+
- Timing and token usage
|
|
244
|
+
|
|
245
|
+
Useful for debugging, cost tracking, or just seeing what happened.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Tips and Tricks
|
|
250
|
+
|
|
251
|
+
**Start with defaults.** Don't configure anything until you need to. `Tier.HIGH` and zero config will get you going immediately.
|
|
252
|
+
|
|
253
|
+
**Use tiers, not provider names.** Say `Tier.LOW` instead of hardcoding `ollama:qwen3-8b`. That way you can swap providers later without changing any code.
|
|
254
|
+
|
|
255
|
+
**Use structured output for anything machine-readable.** Instead of parsing text with regex, pass a Pydantic schema and get clean, validated data back.
|
|
256
|
+
|
|
257
|
+
**Stream long responses.** For anything that might take a while (long text generation, creative writing), use `chat.stream()` so the user sees progress immediately.
|
|
258
|
+
|
|
259
|
+
**Fork conversations to explore alternatives.** Working on something creative? Fork the conversation to try a different direction without losing where you were.
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
async with agent.conversation("brainstorm") as chat:
|
|
263
|
+
await chat.say("Give me three story ideas")
|
|
264
|
+
|
|
265
|
+
branch_a = chat.fork("dark-thriller")
|
|
266
|
+
branch_b = chat.fork("comedy")
|
|
267
|
+
|
|
268
|
+
await branch_a.say("Develop the first idea as a dark thriller")
|
|
269
|
+
await branch_b.say("Develop the first idea as a comedy")
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Use `FREE_FAST` for bulk work.** Processing hundreds of items? Local models cost nothing and won't rate-limit you.
|
|
273
|
+
|
|
274
|
+
**Let the fallback do its job.** Don't try to handle provider errors yourself. That's what daz-agent-sdk is for.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
[build-system]
|
|
3
|
+
requires = ["setuptools>=61.0"]
|
|
4
|
+
build-backend = "setuptools.build_meta"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "daz-agent-sdk"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
authors = [
|
|
10
|
+
{ name="Darren Oakey", email="darren@oakey.net" },
|
|
11
|
+
]
|
|
12
|
+
description = "Provider-agnostic AI library with tier-based routing and automatic fallback."
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
requires-python = ">=3.11"
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"pyyaml>=6.0",
|
|
22
|
+
"pydantic>=2.0",
|
|
23
|
+
"aiohttp>=3.9",
|
|
24
|
+
"setproctitle>=1.3",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
daz-agent-sdk = "daz_agent_sdk.main:main"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools]
|
|
31
|
+
package-dir = {"" = "src"}
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["src"]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.dynamic]
|
|
37
|
+
version = {attr = "daz_agent_sdk.__version__"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
2
|
+
|
|
3
|
+
from daz_agent_sdk.conversation import Conversation
|
|
4
|
+
from daz_agent_sdk.core import Agent
|
|
5
|
+
from daz_agent_sdk.types import (
|
|
6
|
+
AgentError,
|
|
7
|
+
AudioResult,
|
|
8
|
+
Capability,
|
|
9
|
+
ErrorKind,
|
|
10
|
+
ImageResult,
|
|
11
|
+
Message,
|
|
12
|
+
ModelInfo,
|
|
13
|
+
Response,
|
|
14
|
+
StructuredResponse,
|
|
15
|
+
Tier,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# module-level singleton — ready to use on import
|
|
19
|
+
agent = Agent()
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"Agent",
|
|
23
|
+
"AgentError",
|
|
24
|
+
"AudioResult",
|
|
25
|
+
"Capability",
|
|
26
|
+
"Conversation",
|
|
27
|
+
"ErrorKind",
|
|
28
|
+
"ImageResult",
|
|
29
|
+
"Message",
|
|
30
|
+
"ModelInfo",
|
|
31
|
+
"Response",
|
|
32
|
+
"StructuredResponse",
|
|
33
|
+
"Tier",
|
|
34
|
+
"agent",
|
|
35
|
+
]
|
|
File without changes
|