mycode-sdk 0.11.2__tar.gz → 0.13.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.
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/PKG-INFO +71 -30
- mycode_sdk-0.13.0/README.md +213 -0
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/pyproject.toml +2 -1
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/__init__.py +10 -10
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/agent.py +420 -86
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/attachments.py +1 -1
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/compact.py +13 -4
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/hooks.py +2 -0
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/messages.py +49 -5
- mycode_sdk-0.13.0/src/mycode/models.py +276 -0
- mycode_sdk-0.13.0/src/mycode/models_catalog.json +11297 -0
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/providers/__init__.py +3 -0
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/providers/anthropic_like.py +75 -60
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/providers/base.py +146 -8
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/providers/gemini.py +75 -33
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/providers/openai_chat.py +155 -59
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/providers/openai_responses.py +85 -21
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/session.py +17 -6
- mycode_sdk-0.13.0/src/mycode/tools.py +370 -0
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/utils.py +2 -12
- mycode_sdk-0.11.2/README.md +0 -173
- mycode_sdk-0.11.2/src/mycode/models.py +0 -167
- mycode_sdk-0.11.2/src/mycode/models_catalog.json +0 -3464
- mycode_sdk-0.11.2/src/mycode/tools.py +0 -1098
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/.gitignore +0 -0
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/LICENSE +0 -0
- {mycode_sdk-0.11.2 → mycode_sdk-0.13.0}/src/mycode/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: mycode-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.0
|
|
4
4
|
Summary: Lightweight Python SDK for building AI agents.
|
|
5
5
|
Project-URL: Homepage, https://github.com/legibet/mycode
|
|
6
6
|
Project-URL: Repository, https://github.com/legibet/mycode
|
|
@@ -21,13 +21,14 @@ Requires-Python: >=3.12
|
|
|
21
21
|
Requires-Dist: anthropic>=0.116.0
|
|
22
22
|
Requires-Dist: google-genai>=2.11.0
|
|
23
23
|
Requires-Dist: griffelib>=2.1.0
|
|
24
|
+
Requires-Dist: httpx>=0.28.0
|
|
24
25
|
Requires-Dist: openai>=2.45.0
|
|
25
26
|
Requires-Dist: pydantic>=2.13.4
|
|
26
27
|
Description-Content-Type: text/markdown
|
|
27
28
|
|
|
28
29
|
# mycode-sdk
|
|
29
30
|
|
|
30
|
-
Lightweight Python SDK for building AI agents.
|
|
31
|
+
Lightweight Python SDK for building AI agents. Multi-turn conversations, tool calling, session persistence, and streaming events. Provider adapters for Anthropic, OpenAI, Google, and more.
|
|
31
32
|
|
|
32
33
|
## Install
|
|
33
34
|
|
|
@@ -41,15 +42,27 @@ pip install mycode-sdk
|
|
|
41
42
|
|
|
42
43
|
```python
|
|
43
44
|
import asyncio
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
|
|
47
|
+
from mycode import Agent, tool
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@tool
|
|
51
|
+
def read_file(path: str) -> str:
|
|
52
|
+
"""Read a UTF-8 text file.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
path: File path, relative to the working directory.
|
|
56
|
+
"""
|
|
44
57
|
|
|
45
|
-
|
|
58
|
+
return Path(path).read_text(encoding="utf-8")
|
|
46
59
|
|
|
47
60
|
|
|
48
61
|
async def main() -> None:
|
|
49
62
|
agent = Agent(
|
|
50
63
|
model="claude-sonnet-4-6",
|
|
51
64
|
api_key="YOUR_API_KEY",
|
|
52
|
-
tools=[
|
|
65
|
+
tools=[read_file],
|
|
53
66
|
)
|
|
54
67
|
|
|
55
68
|
async for event in agent.achat("Read pyproject.toml and tell me the project name."):
|
|
@@ -62,16 +75,36 @@ asyncio.run(main())
|
|
|
62
75
|
|
|
63
76
|
`Agent(...)` infers the provider from the model id. No tools are registered unless you pass `tools=[...]`.
|
|
64
77
|
|
|
65
|
-
For a
|
|
78
|
+
For a synchronous call, use `run()`:
|
|
66
79
|
|
|
67
80
|
```python
|
|
68
81
|
result = agent.run("Read pyproject.toml and tell me the project name.")
|
|
69
82
|
print(result.text)
|
|
70
83
|
```
|
|
71
84
|
|
|
85
|
+
## Providers
|
|
86
|
+
|
|
87
|
+
The SDK infers the provider from the model string (`claude-*` to Anthropic, `gpt-*` to OpenAI, etc.). API keys are auto-discovered from environment variables:
|
|
88
|
+
|
|
89
|
+
| Provider | id | Env var |
|
|
90
|
+
| --- | --- | --- |
|
|
91
|
+
| Anthropic | `anthropic` | `ANTHROPIC_API_KEY` |
|
|
92
|
+
| OpenAI | `openai` | `OPENAI_API_KEY` |
|
|
93
|
+
| Google Gemini | `google` | `GEMINI_API_KEY` |
|
|
94
|
+
| Moonshot | `moonshotai` | `MOONSHOT_API_KEY` |
|
|
95
|
+
| MiniMax | `minimax` | `MINIMAX_API_KEY` |
|
|
96
|
+
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` |
|
|
97
|
+
| Z.AI | `zai` | `ZAI_API_KEY` |
|
|
98
|
+
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
|
|
99
|
+
| Alibaba Cloud | `alibaba` | `DASHSCOPE_API_KEY` |
|
|
100
|
+
| xAI | `xai` | `XAI_API_KEY` |
|
|
101
|
+
| OpenAI-compatible | `openai_chat` | - |
|
|
102
|
+
|
|
103
|
+
Pass `api_key=` to override the env var, `api_base=` for a custom endpoint. Model metadata is bundled from [models.dev](https://models.dev); pass `context_window`, `supports_reasoning`, `supports_image_input`, or `supports_pdf_input` to override.
|
|
104
|
+
|
|
72
105
|
## Multi-turn conversations
|
|
73
106
|
|
|
74
|
-
Call `achat()` or `run()` again on the same `Agent` to continue
|
|
107
|
+
Call `achat()` or `run()` again on the same `Agent` to continue:
|
|
75
108
|
|
|
76
109
|
```python
|
|
77
110
|
agent = Agent(model="claude-sonnet-4-6", api_key="...")
|
|
@@ -80,6 +113,8 @@ agent.run("What is 2 + 2?")
|
|
|
80
113
|
agent.run("Now multiply that by 10.") # remembers the earlier answer
|
|
81
114
|
```
|
|
82
115
|
|
|
116
|
+
`agent.clear()` drops in-memory history. `agent.messages` accumulates across calls.
|
|
117
|
+
|
|
83
118
|
## Attachments
|
|
84
119
|
|
|
85
120
|
Pass `attachments` to `achat()` or `run()` to add files alongside the prompt:
|
|
@@ -89,7 +124,7 @@ from mycode import Attachment
|
|
|
89
124
|
|
|
90
125
|
agent.run("Describe these.", attachments=["diagram.png", "report.pdf", "notes.txt"])
|
|
91
126
|
|
|
92
|
-
# Or build them explicitly
|
|
127
|
+
# Or build them explicitly:
|
|
93
128
|
agent.run(
|
|
94
129
|
"Review.",
|
|
95
130
|
attachments=[
|
|
@@ -100,7 +135,7 @@ agent.run(
|
|
|
100
135
|
)
|
|
101
136
|
```
|
|
102
137
|
|
|
103
|
-
Images support `image/png`, `image/jpeg`, `image/gif`, `image/webp`; documents support `application/pdf`. Sending an image or PDF to a model
|
|
138
|
+
Images support `image/png`, `image/jpeg`, `image/gif`, `image/webp`; documents support `application/pdf`. Sending an image or PDF to a model without that capability yields an `error` event. A bad path or unsupported type raises `ValueError` before the provider is called.
|
|
104
139
|
|
|
105
140
|
## Saving sessions
|
|
106
141
|
|
|
@@ -119,15 +154,7 @@ agent = Agent(
|
|
|
119
154
|
|
|
120
155
|
Construct another `Agent` with the same `(session_dir, session_id)` to load the conversation history.
|
|
121
156
|
|
|
122
|
-
##
|
|
123
|
-
|
|
124
|
-
```python
|
|
125
|
-
from mycode import read_tool, write_tool, edit_tool, bash_tool
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Four tools for reading, writing, editing files, and running shell commands. Opt in by passing them to `tools=[...]`.
|
|
129
|
-
|
|
130
|
-
## Custom tools
|
|
157
|
+
## Tools
|
|
131
158
|
|
|
132
159
|
Decorate a typed function with `@tool`:
|
|
133
160
|
|
|
@@ -153,36 +180,48 @@ agent = Agent(
|
|
|
153
180
|
)
|
|
154
181
|
```
|
|
155
182
|
|
|
156
|
-
To call
|
|
183
|
+
To call another registered tool from inside a tool, type the first parameter as `ToolContext` and dispatch by name:
|
|
157
184
|
|
|
158
185
|
```python
|
|
159
186
|
from mycode import ToolContext, tool
|
|
160
187
|
|
|
161
188
|
|
|
162
189
|
@tool
|
|
163
|
-
def
|
|
164
|
-
"""
|
|
190
|
+
def greet_team(ctx: ToolContext, names: list[str]) -> str:
|
|
191
|
+
"""Greet several people at once."""
|
|
165
192
|
|
|
166
|
-
|
|
167
|
-
return result.output.splitlines()[0] if result.output else ""
|
|
193
|
+
return "\n".join(ctx.call("greet", {"name": name}).output for name in names)
|
|
168
194
|
```
|
|
169
195
|
|
|
170
|
-
Async tools use `await ctx.
|
|
196
|
+
Async tools use `await ctx.acall(name, args)` instead.
|
|
171
197
|
|
|
172
198
|
## Tool hooks
|
|
173
199
|
|
|
174
200
|
Inspect or replace tool calls before they run. Return `None` from `before_tool` to let the tool execute, or a `ToolExecutionResult` to skip it:
|
|
175
201
|
|
|
176
202
|
```python
|
|
177
|
-
|
|
203
|
+
import os
|
|
204
|
+
|
|
205
|
+
from mycode import Agent, Hooks, ToolExecutionResult, tool
|
|
178
206
|
|
|
179
207
|
hooks = Hooks()
|
|
180
208
|
|
|
181
209
|
|
|
210
|
+
@tool
|
|
211
|
+
def delete_file(path: str) -> str:
|
|
212
|
+
"""Delete a file.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
path: Path of the file to delete.
|
|
216
|
+
"""
|
|
217
|
+
|
|
218
|
+
os.remove(path)
|
|
219
|
+
return f"deleted {path}"
|
|
220
|
+
|
|
221
|
+
|
|
182
222
|
@hooks.before_tool
|
|
183
|
-
async def
|
|
184
|
-
|
|
185
|
-
if ctx.tool_name == "bash" and "rm -rf" in cmd:
|
|
223
|
+
async def protect_dotfiles(ctx):
|
|
224
|
+
if ctx.tool_name == "delete_file" and str(ctx.tool_input.get("path") or "").startswith("."):
|
|
186
225
|
return ToolExecutionResult(output="error: blocked", is_error=True)
|
|
187
226
|
return None
|
|
188
227
|
|
|
@@ -190,11 +229,13 @@ async def block_rm(ctx):
|
|
|
190
229
|
agent = Agent(
|
|
191
230
|
model="claude-sonnet-4-6",
|
|
192
231
|
api_key="...",
|
|
193
|
-
tools=[
|
|
232
|
+
tools=[delete_file],
|
|
194
233
|
hooks=hooks,
|
|
195
234
|
)
|
|
196
235
|
```
|
|
197
236
|
|
|
198
237
|
`@hooks.after_tool` runs after the tool and can replace the result (audit, redact, etc.).
|
|
199
238
|
|
|
200
|
-
|
|
239
|
+
## Further reading
|
|
240
|
+
|
|
241
|
+
See [docs/sdk.md](https://github.com/legibet/mycode/blob/main/docs/sdk.md) for the streaming event API, cancellation, retries, compaction, session internals, and the full `Agent` / `@tool` reference.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# mycode-sdk
|
|
2
|
+
|
|
3
|
+
Lightweight Python SDK for building AI agents. Multi-turn conversations, tool calling, session persistence, and streaming events. Provider adapters for Anthropic, OpenAI, Google, and more.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv add mycode-sdk
|
|
9
|
+
# or
|
|
10
|
+
pip install mycode-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import asyncio
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from mycode import Agent, tool
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@tool
|
|
23
|
+
def read_file(path: str) -> str:
|
|
24
|
+
"""Read a UTF-8 text file.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
path: File path, relative to the working directory.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
return Path(path).read_text(encoding="utf-8")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def main() -> None:
|
|
34
|
+
agent = Agent(
|
|
35
|
+
model="claude-sonnet-4-6",
|
|
36
|
+
api_key="YOUR_API_KEY",
|
|
37
|
+
tools=[read_file],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
async for event in agent.achat("Read pyproject.toml and tell me the project name."):
|
|
41
|
+
if event.type == "text":
|
|
42
|
+
print(event.data["delta"], end="", flush=True)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
asyncio.run(main())
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`Agent(...)` infers the provider from the model id. No tools are registered unless you pass `tools=[...]`.
|
|
49
|
+
|
|
50
|
+
For a synchronous call, use `run()`:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
result = agent.run("Read pyproject.toml and tell me the project name.")
|
|
54
|
+
print(result.text)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Providers
|
|
58
|
+
|
|
59
|
+
The SDK infers the provider from the model string (`claude-*` to Anthropic, `gpt-*` to OpenAI, etc.). API keys are auto-discovered from environment variables:
|
|
60
|
+
|
|
61
|
+
| Provider | id | Env var |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| Anthropic | `anthropic` | `ANTHROPIC_API_KEY` |
|
|
64
|
+
| OpenAI | `openai` | `OPENAI_API_KEY` |
|
|
65
|
+
| Google Gemini | `google` | `GEMINI_API_KEY` |
|
|
66
|
+
| Moonshot | `moonshotai` | `MOONSHOT_API_KEY` |
|
|
67
|
+
| MiniMax | `minimax` | `MINIMAX_API_KEY` |
|
|
68
|
+
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` |
|
|
69
|
+
| Z.AI | `zai` | `ZAI_API_KEY` |
|
|
70
|
+
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
|
|
71
|
+
| Alibaba Cloud | `alibaba` | `DASHSCOPE_API_KEY` |
|
|
72
|
+
| xAI | `xai` | `XAI_API_KEY` |
|
|
73
|
+
| OpenAI-compatible | `openai_chat` | - |
|
|
74
|
+
|
|
75
|
+
Pass `api_key=` to override the env var, `api_base=` for a custom endpoint. Model metadata is bundled from [models.dev](https://models.dev); pass `context_window`, `supports_reasoning`, `supports_image_input`, or `supports_pdf_input` to override.
|
|
76
|
+
|
|
77
|
+
## Multi-turn conversations
|
|
78
|
+
|
|
79
|
+
Call `achat()` or `run()` again on the same `Agent` to continue:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
agent = Agent(model="claude-sonnet-4-6", api_key="...")
|
|
83
|
+
|
|
84
|
+
agent.run("What is 2 + 2?")
|
|
85
|
+
agent.run("Now multiply that by 10.") # remembers the earlier answer
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`agent.clear()` drops in-memory history. `agent.messages` accumulates across calls.
|
|
89
|
+
|
|
90
|
+
## Attachments
|
|
91
|
+
|
|
92
|
+
Pass `attachments` to `achat()` or `run()` to add files alongside the prompt:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from mycode import Attachment
|
|
96
|
+
|
|
97
|
+
agent.run("Describe these.", attachments=["diagram.png", "report.pdf", "notes.txt"])
|
|
98
|
+
|
|
99
|
+
# Or build them explicitly:
|
|
100
|
+
agent.run(
|
|
101
|
+
"Review.",
|
|
102
|
+
attachments=[
|
|
103
|
+
Attachment.path("diagram.png"),
|
|
104
|
+
Attachment.bytes(png_data, media_type="image/png"),
|
|
105
|
+
Attachment.text("TODO: ship it", name="note.md"),
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Images support `image/png`, `image/jpeg`, `image/gif`, `image/webp`; documents support `application/pdf`. Sending an image or PDF to a model without that capability yields an `error` event. A bad path or unsupported type raises `ValueError` before the provider is called.
|
|
111
|
+
|
|
112
|
+
## Saving sessions
|
|
113
|
+
|
|
114
|
+
Pass `session_dir` to persist the conversation to disk. Each session lives in a subdirectory named by `session_id`:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from pathlib import Path
|
|
118
|
+
|
|
119
|
+
agent = Agent(
|
|
120
|
+
model="claude-sonnet-4-6",
|
|
121
|
+
api_key="...",
|
|
122
|
+
session_dir=Path("./chats"),
|
|
123
|
+
session_id="my-chat",
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Construct another `Agent` with the same `(session_dir, session_id)` to load the conversation history.
|
|
128
|
+
|
|
129
|
+
## Tools
|
|
130
|
+
|
|
131
|
+
Decorate a typed function with `@tool`:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from mycode import Agent, tool
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@tool
|
|
138
|
+
def greet(name: str) -> str:
|
|
139
|
+
"""Return a friendly greeting.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
name: Person name.
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
return f"hello, {name}"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
agent = Agent(
|
|
149
|
+
model="claude-sonnet-4-6",
|
|
150
|
+
api_key="...",
|
|
151
|
+
tools=[greet],
|
|
152
|
+
)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
To call another registered tool from inside a tool, type the first parameter as `ToolContext` and dispatch by name:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from mycode import ToolContext, tool
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@tool
|
|
162
|
+
def greet_team(ctx: ToolContext, names: list[str]) -> str:
|
|
163
|
+
"""Greet several people at once."""
|
|
164
|
+
|
|
165
|
+
return "\n".join(ctx.call("greet", {"name": name}).output for name in names)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Async tools use `await ctx.acall(name, args)` instead.
|
|
169
|
+
|
|
170
|
+
## Tool hooks
|
|
171
|
+
|
|
172
|
+
Inspect or replace tool calls before they run. Return `None` from `before_tool` to let the tool execute, or a `ToolExecutionResult` to skip it:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
import os
|
|
176
|
+
|
|
177
|
+
from mycode import Agent, Hooks, ToolExecutionResult, tool
|
|
178
|
+
|
|
179
|
+
hooks = Hooks()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@tool
|
|
183
|
+
def delete_file(path: str) -> str:
|
|
184
|
+
"""Delete a file.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
path: Path of the file to delete.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
os.remove(path)
|
|
191
|
+
return f"deleted {path}"
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@hooks.before_tool
|
|
195
|
+
async def protect_dotfiles(ctx):
|
|
196
|
+
if ctx.tool_name == "delete_file" and str(ctx.tool_input.get("path") or "").startswith("."):
|
|
197
|
+
return ToolExecutionResult(output="error: blocked", is_error=True)
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
agent = Agent(
|
|
202
|
+
model="claude-sonnet-4-6",
|
|
203
|
+
api_key="...",
|
|
204
|
+
tools=[delete_file],
|
|
205
|
+
hooks=hooks,
|
|
206
|
+
)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`@hooks.after_tool` runs after the tool and can replace the result (audit, redact, etc.).
|
|
210
|
+
|
|
211
|
+
## Further reading
|
|
212
|
+
|
|
213
|
+
See [docs/sdk.md](https://github.com/legibet/mycode/blob/main/docs/sdk.md) for the streaming event API, cancellation, retries, compaction, session internals, and the full `Agent` / `@tool` reference.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mycode-sdk"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.13.0"
|
|
8
8
|
description = "Lightweight Python SDK for building AI agents."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -26,6 +26,7 @@ dependencies = [
|
|
|
26
26
|
"anthropic>=0.116.0",
|
|
27
27
|
"google-genai>=2.11.0",
|
|
28
28
|
"griffelib>=2.1.0",
|
|
29
|
+
"httpx>=0.28.0",
|
|
29
30
|
"openai>=2.45.0",
|
|
30
31
|
"pydantic>=2.13.4",
|
|
31
32
|
]
|
|
@@ -11,6 +11,7 @@ from mycode.messages import (
|
|
|
11
11
|
ConversationMessage,
|
|
12
12
|
assistant_message,
|
|
13
13
|
build_message,
|
|
14
|
+
build_usage,
|
|
14
15
|
document_block,
|
|
15
16
|
flatten_message_text,
|
|
16
17
|
image_block,
|
|
@@ -20,18 +21,15 @@ from mycode.messages import (
|
|
|
20
21
|
tool_use_block,
|
|
21
22
|
user_text_message,
|
|
22
23
|
)
|
|
24
|
+
from mycode.models import Cost, ModelMetadata, estimate_cost, resolve_model_metadata
|
|
25
|
+
from mycode.providers.base import ProviderError, StreamStartTimeoutError
|
|
23
26
|
from mycode.session import SessionStore
|
|
24
27
|
from mycode.tools import (
|
|
25
28
|
ToolContext,
|
|
26
29
|
ToolExecutionResult,
|
|
27
30
|
ToolExecutor,
|
|
28
31
|
ToolSpec,
|
|
29
|
-
bash_tool,
|
|
30
|
-
cancel_all_tools,
|
|
31
|
-
edit_tool,
|
|
32
|
-
read_tool,
|
|
33
32
|
tool,
|
|
34
|
-
write_tool,
|
|
35
33
|
)
|
|
36
34
|
|
|
37
35
|
__version__ = metadata.version("mycode-sdk")
|
|
@@ -41,15 +39,19 @@ __all__ = [
|
|
|
41
39
|
"Attachment",
|
|
42
40
|
"ContentBlock",
|
|
43
41
|
"ConversationMessage",
|
|
42
|
+
"Cost",
|
|
44
43
|
"Event",
|
|
45
44
|
"AfterToolHook",
|
|
46
45
|
"BeforeToolHook",
|
|
47
46
|
"HookResult",
|
|
48
47
|
"Hooks",
|
|
48
|
+
"ModelMetadata",
|
|
49
49
|
"NothingToCompactError",
|
|
50
50
|
"PersistCallback",
|
|
51
|
+
"ProviderError",
|
|
51
52
|
"RunResult",
|
|
52
53
|
"SessionStore",
|
|
54
|
+
"StreamStartTimeoutError",
|
|
53
55
|
"ToolContext",
|
|
54
56
|
"ToolExecutionResult",
|
|
55
57
|
"ToolExecutor",
|
|
@@ -57,19 +59,17 @@ __all__ = [
|
|
|
57
59
|
"ToolSpec",
|
|
58
60
|
"__version__",
|
|
59
61
|
"assistant_message",
|
|
60
|
-
"bash_tool",
|
|
61
62
|
"build_message",
|
|
62
|
-
"
|
|
63
|
+
"build_usage",
|
|
63
64
|
"document_block",
|
|
64
|
-
"
|
|
65
|
+
"estimate_cost",
|
|
65
66
|
"flatten_message_text",
|
|
66
67
|
"image_block",
|
|
67
|
-
"
|
|
68
|
+
"resolve_model_metadata",
|
|
68
69
|
"text_block",
|
|
69
70
|
"thinking_block",
|
|
70
71
|
"tool",
|
|
71
72
|
"tool_result_block",
|
|
72
73
|
"tool_use_block",
|
|
73
74
|
"user_text_message",
|
|
74
|
-
"write_tool",
|
|
75
75
|
]
|