stirrup 0.1.1__tar.gz → 0.1.3__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.
- {stirrup-0.1.1 → stirrup-0.1.3}/PKG-INFO +36 -16
- {stirrup-0.1.1 → stirrup-0.1.3}/README.md +34 -14
- {stirrup-0.1.1 → stirrup-0.1.3}/pyproject.toml +2 -2
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/__init__.py +2 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/chat_completions_client.py +0 -3
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/litellm_client.py +20 -11
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/utils.py +6 -1
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/constants.py +6 -2
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/agent.py +206 -57
- stirrup-0.1.3/src/stirrup/core/cache.py +479 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/models.py +53 -7
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/base_system_prompt.txt +1 -1
- stirrup-0.1.3/src/stirrup/skills/__init__.py +24 -0
- stirrup-0.1.3/src/stirrup/skills/skills.py +145 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/__init__.py +2 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/calculator.py +1 -1
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/base.py +7 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/docker.py +16 -4
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/e2b.py +32 -13
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/local.py +16 -4
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/finish.py +1 -1
- stirrup-0.1.3/src/stirrup/tools/user_input.py +130 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/web.py +1 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/utils/logging.py +24 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/LICENSE +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/__init__.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/__init__.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/exceptions.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/__init__.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/message_summarizer.txt +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/message_summarizer_bridge.txt +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/py.typed +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/__init__.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/mcp.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/view_image.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/utils/__init__.py +0 -0
- {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/utils/text.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: stirrup
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: The lightweight foundation for building agents
|
|
5
5
|
Keywords: ai,agent,llm,openai,anthropic,tools,framework
|
|
6
6
|
Author: Artificial Analysis, Inc.
|
|
@@ -54,7 +54,7 @@ Requires-Dist: e2b-code-interpreter>=2.3.0 ; extra == 'e2b'
|
|
|
54
54
|
Requires-Dist: litellm>=1.79.3 ; extra == 'litellm'
|
|
55
55
|
Requires-Dist: mcp>=1.9.0 ; extra == 'mcp'
|
|
56
56
|
Requires-Python: >=3.12
|
|
57
|
-
Project-URL: Documentation, https://artificialanalysis.
|
|
57
|
+
Project-URL: Documentation, https://stirrup.artificialanalysis.ai
|
|
58
58
|
Project-URL: Homepage, https://github.com/ArtificialAnalysis/Stirrup
|
|
59
59
|
Project-URL: Repository, https://github.com/ArtificialAnalysis/Stirrup
|
|
60
60
|
Provides-Extra: all
|
|
@@ -65,7 +65,7 @@ Provides-Extra: mcp
|
|
|
65
65
|
Description-Content-Type: text/markdown
|
|
66
66
|
|
|
67
67
|
<div align="center">
|
|
68
|
-
<a href="">
|
|
68
|
+
<a href="https://stirrup.artificialanalysis.ai">
|
|
69
69
|
<picture>
|
|
70
70
|
<img alt="Stirrup" src="https://github.com/ArtificialAnalysis/Stirrup/blob/048653717d8662b0b81d152a037995af1c926afc/assets/stirrup-banner.png?raw=true" width="700">
|
|
71
71
|
</picture>
|
|
@@ -79,7 +79,7 @@ Description-Content-Type: text/markdown
|
|
|
79
79
|
<p align="center">
|
|
80
80
|
<a href="https://pypi.python.org/pypi/stirrup"><img src="https://img.shields.io/pypi/v/stirrup" alt="PyPI version" /></a> <!--
|
|
81
81
|
--><a href="https://github.com/ArtificialAnalysis/Stirrup/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ArtificialAnalysis/Stirrup" alt="License" /></a> <!--
|
|
82
|
-
--><a href="https://artificialanalysis.
|
|
82
|
+
--><a href="https://stirrup.artificialanalysis.ai"><img src="https://img.shields.io/badge/MkDocs-4F46E5?logo=materialformkdocs&logoColor=fff" alt="MkDocs" /></a>
|
|
83
83
|
</p>
|
|
84
84
|
|
|
85
85
|
|
|
@@ -96,6 +96,7 @@ Stirrup is a lightweight framework, or starting point template, for building age
|
|
|
96
96
|
- Code execution (local, Docker container, E2B sandbox)
|
|
97
97
|
- MCP client
|
|
98
98
|
- Document input and output
|
|
99
|
+
- **Skills system:** Extend agent capabilities with modular, domain-specific instruction packages
|
|
99
100
|
- **Flexible tool execution:** A generic `Tool` class allows easy tool definition and extension
|
|
100
101
|
- **Context management:** Automatically summarizes conversation history when approaching context limits
|
|
101
102
|
- **Flexible provider support:** Pre-built support for OpenAI-compatible APIs and LiteLLM, or bring your own client
|
|
@@ -105,16 +106,16 @@ Stirrup is a lightweight framework, or starting point template, for building age
|
|
|
105
106
|
|
|
106
107
|
```bash
|
|
107
108
|
# Core framework
|
|
108
|
-
|
|
109
|
+
pip install stirrup # or: uv add stirrup
|
|
109
110
|
|
|
110
111
|
# With all optional components
|
|
111
|
-
|
|
112
|
+
pip install 'stirrup[all]' # or: uv add 'stirrup[all]'
|
|
112
113
|
|
|
113
114
|
# Individual extras
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
pip install 'stirrup[litellm]' # or: uv add 'stirrup[litellm]'
|
|
116
|
+
pip install 'stirrup[docker]' # or: uv add 'stirrup[docker]'
|
|
117
|
+
pip install 'stirrup[e2b]' # or: uv add 'stirrup[e2b]'
|
|
118
|
+
pip install 'stirrup[mcp]' # or: uv add 'stirrup[mcp]'
|
|
118
119
|
```
|
|
119
120
|
|
|
120
121
|
## Quick Start
|
|
@@ -160,6 +161,24 @@ if __name__ == "__main__":
|
|
|
160
161
|
|
|
161
162
|
> **Note:** This example uses OpenRouter. Set `OPENROUTER_API_KEY` in your environment before running. Web search requires a `BRAVE_API_KEY`. The agent will still work without it, but web search will be unavailable.
|
|
162
163
|
|
|
164
|
+
## Full Customization
|
|
165
|
+
|
|
166
|
+
For using Stirrup as a foundation for your own fully customized agent, you can clone and import Stirrup locally:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Clone the repository
|
|
170
|
+
git clone https://github.com/ArtificialAnalysis/Stirrup.git
|
|
171
|
+
cd stirrup
|
|
172
|
+
|
|
173
|
+
# Install in editable mode
|
|
174
|
+
pip install -e . # or: uv venv && uv pip install -e .
|
|
175
|
+
|
|
176
|
+
# Or with all optional dependencies
|
|
177
|
+
pip install -e '.[all]' # or: uv venv && uv pip install -e '.[all]'
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
See the [Full Customization guide](https://stirrup.artificialanalysis.ai/extending/full-customization/) for more details.
|
|
181
|
+
|
|
163
182
|
## How It Works
|
|
164
183
|
|
|
165
184
|
- **`Agent`** - Configures and runs the agent loop until a finish tool is called or max turns reached
|
|
@@ -188,6 +207,7 @@ agent = Agent(client=client, name="deepseek_agent")
|
|
|
188
207
|
### LiteLLM (Anthropic, Google, etc.)
|
|
189
208
|
|
|
190
209
|
```python
|
|
210
|
+
# Ensure LiteLLM is added with: pip install 'stirrup[litellm]' # or: uv add 'stirrup[litellm]'
|
|
191
211
|
# Create LiteLLM client for Anthropic Claude
|
|
192
212
|
# See https://docs.litellm.ai/docs/providers for all supported providers
|
|
193
213
|
client = LiteLLMClient(
|
|
@@ -202,7 +222,7 @@ agent = Agent(
|
|
|
202
222
|
)
|
|
203
223
|
```
|
|
204
224
|
|
|
205
|
-
See [LiteLLM Example](https://artificialanalysis.
|
|
225
|
+
See [LiteLLM Example](https://stirrup.artificialanalysis.ai/examples/#litellm-multi-provider-support) or [Deepseek Example](https://stirrup.artificialanalysis.ai/examples/#openai-compatible-apis-deepseek-vllm-ollama) for complete examples.
|
|
206
226
|
|
|
207
227
|
## Default Tools
|
|
208
228
|
|
|
@@ -285,14 +305,14 @@ agent = Agent(
|
|
|
285
305
|
|
|
286
306
|
## Next Steps
|
|
287
307
|
|
|
288
|
-
- [Getting Started](https://artificialanalysis.
|
|
289
|
-
- [Core Concepts](https://artificialanalysis.
|
|
290
|
-
- [Examples](https://artificialanalysis.
|
|
291
|
-
- [Creating Tools](https://artificialanalysis.
|
|
308
|
+
- [Getting Started](https://stirrup.artificialanalysis.ai/getting-started/) - Installation and first agent tutorial
|
|
309
|
+
- [Core Concepts](https://stirrup.artificialanalysis.ai/concepts/) - Understand Agent, Tools, and Sessions
|
|
310
|
+
- [Examples](https://stirrup.artificialanalysis.ai/examples/) - Working examples for common patterns
|
|
311
|
+
- [Creating Tools](https://stirrup.artificialanalysis.ai/guides/tools/) - Build your own tools
|
|
292
312
|
|
|
293
313
|
## Documentation
|
|
294
314
|
|
|
295
|
-
Full documentation: [artificialanalysis.github.io/Stirrup](https://artificialanalysis.
|
|
315
|
+
Full documentation: [artificialanalysis.github.io/Stirrup](https://stirrup.artificialanalysis.ai)
|
|
296
316
|
|
|
297
317
|
Build and serve locally:
|
|
298
318
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<a href="">
|
|
2
|
+
<a href="https://stirrup.artificialanalysis.ai">
|
|
3
3
|
<picture>
|
|
4
4
|
<img alt="Stirrup" src="https://github.com/ArtificialAnalysis/Stirrup/blob/048653717d8662b0b81d152a037995af1c926afc/assets/stirrup-banner.png?raw=true" width="700">
|
|
5
5
|
</picture>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<p align="center">
|
|
14
14
|
<a href="https://pypi.python.org/pypi/stirrup"><img src="https://img.shields.io/pypi/v/stirrup" alt="PyPI version" /></a> <!--
|
|
15
15
|
--><a href="https://github.com/ArtificialAnalysis/Stirrup/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ArtificialAnalysis/Stirrup" alt="License" /></a> <!--
|
|
16
|
-
--><a href="https://artificialanalysis.
|
|
16
|
+
--><a href="https://stirrup.artificialanalysis.ai"><img src="https://img.shields.io/badge/MkDocs-4F46E5?logo=materialformkdocs&logoColor=fff" alt="MkDocs" /></a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
19
|
|
|
@@ -30,6 +30,7 @@ Stirrup is a lightweight framework, or starting point template, for building age
|
|
|
30
30
|
- Code execution (local, Docker container, E2B sandbox)
|
|
31
31
|
- MCP client
|
|
32
32
|
- Document input and output
|
|
33
|
+
- **Skills system:** Extend agent capabilities with modular, domain-specific instruction packages
|
|
33
34
|
- **Flexible tool execution:** A generic `Tool` class allows easy tool definition and extension
|
|
34
35
|
- **Context management:** Automatically summarizes conversation history when approaching context limits
|
|
35
36
|
- **Flexible provider support:** Pre-built support for OpenAI-compatible APIs and LiteLLM, or bring your own client
|
|
@@ -39,16 +40,16 @@ Stirrup is a lightweight framework, or starting point template, for building age
|
|
|
39
40
|
|
|
40
41
|
```bash
|
|
41
42
|
# Core framework
|
|
42
|
-
|
|
43
|
+
pip install stirrup # or: uv add stirrup
|
|
43
44
|
|
|
44
45
|
# With all optional components
|
|
45
|
-
|
|
46
|
+
pip install 'stirrup[all]' # or: uv add 'stirrup[all]'
|
|
46
47
|
|
|
47
48
|
# Individual extras
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
pip install 'stirrup[litellm]' # or: uv add 'stirrup[litellm]'
|
|
50
|
+
pip install 'stirrup[docker]' # or: uv add 'stirrup[docker]'
|
|
51
|
+
pip install 'stirrup[e2b]' # or: uv add 'stirrup[e2b]'
|
|
52
|
+
pip install 'stirrup[mcp]' # or: uv add 'stirrup[mcp]'
|
|
52
53
|
```
|
|
53
54
|
|
|
54
55
|
## Quick Start
|
|
@@ -94,6 +95,24 @@ if __name__ == "__main__":
|
|
|
94
95
|
|
|
95
96
|
> **Note:** This example uses OpenRouter. Set `OPENROUTER_API_KEY` in your environment before running. Web search requires a `BRAVE_API_KEY`. The agent will still work without it, but web search will be unavailable.
|
|
96
97
|
|
|
98
|
+
## Full Customization
|
|
99
|
+
|
|
100
|
+
For using Stirrup as a foundation for your own fully customized agent, you can clone and import Stirrup locally:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Clone the repository
|
|
104
|
+
git clone https://github.com/ArtificialAnalysis/Stirrup.git
|
|
105
|
+
cd stirrup
|
|
106
|
+
|
|
107
|
+
# Install in editable mode
|
|
108
|
+
pip install -e . # or: uv venv && uv pip install -e .
|
|
109
|
+
|
|
110
|
+
# Or with all optional dependencies
|
|
111
|
+
pip install -e '.[all]' # or: uv venv && uv pip install -e '.[all]'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
See the [Full Customization guide](https://stirrup.artificialanalysis.ai/extending/full-customization/) for more details.
|
|
115
|
+
|
|
97
116
|
## How It Works
|
|
98
117
|
|
|
99
118
|
- **`Agent`** - Configures and runs the agent loop until a finish tool is called or max turns reached
|
|
@@ -122,6 +141,7 @@ agent = Agent(client=client, name="deepseek_agent")
|
|
|
122
141
|
### LiteLLM (Anthropic, Google, etc.)
|
|
123
142
|
|
|
124
143
|
```python
|
|
144
|
+
# Ensure LiteLLM is added with: pip install 'stirrup[litellm]' # or: uv add 'stirrup[litellm]'
|
|
125
145
|
# Create LiteLLM client for Anthropic Claude
|
|
126
146
|
# See https://docs.litellm.ai/docs/providers for all supported providers
|
|
127
147
|
client = LiteLLMClient(
|
|
@@ -136,7 +156,7 @@ agent = Agent(
|
|
|
136
156
|
)
|
|
137
157
|
```
|
|
138
158
|
|
|
139
|
-
See [LiteLLM Example](https://artificialanalysis.
|
|
159
|
+
See [LiteLLM Example](https://stirrup.artificialanalysis.ai/examples/#litellm-multi-provider-support) or [Deepseek Example](https://stirrup.artificialanalysis.ai/examples/#openai-compatible-apis-deepseek-vllm-ollama) for complete examples.
|
|
140
160
|
|
|
141
161
|
## Default Tools
|
|
142
162
|
|
|
@@ -219,14 +239,14 @@ agent = Agent(
|
|
|
219
239
|
|
|
220
240
|
## Next Steps
|
|
221
241
|
|
|
222
|
-
- [Getting Started](https://artificialanalysis.
|
|
223
|
-
- [Core Concepts](https://artificialanalysis.
|
|
224
|
-
- [Examples](https://artificialanalysis.
|
|
225
|
-
- [Creating Tools](https://artificialanalysis.
|
|
242
|
+
- [Getting Started](https://stirrup.artificialanalysis.ai/getting-started/) - Installation and first agent tutorial
|
|
243
|
+
- [Core Concepts](https://stirrup.artificialanalysis.ai/concepts/) - Understand Agent, Tools, and Sessions
|
|
244
|
+
- [Examples](https://stirrup.artificialanalysis.ai/examples/) - Working examples for common patterns
|
|
245
|
+
- [Creating Tools](https://stirrup.artificialanalysis.ai/guides/tools/) - Build your own tools
|
|
226
246
|
|
|
227
247
|
## Documentation
|
|
228
248
|
|
|
229
|
-
Full documentation: [artificialanalysis.github.io/Stirrup](https://artificialanalysis.
|
|
249
|
+
Full documentation: [artificialanalysis.github.io/Stirrup](https://stirrup.artificialanalysis.ai)
|
|
230
250
|
|
|
231
251
|
Build and serve locally:
|
|
232
252
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "stirrup"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.3"
|
|
4
4
|
description = "The lightweight foundation for building agents"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { file = "LICENSE" }
|
|
@@ -45,7 +45,7 @@ all = ["stirrup[litellm,e2b,docker,mcp]"]
|
|
|
45
45
|
|
|
46
46
|
[project.urls]
|
|
47
47
|
Homepage = "https://github.com/ArtificialAnalysis/Stirrup"
|
|
48
|
-
Documentation = "https://artificialanalysis.
|
|
48
|
+
Documentation = "https://stirrup.artificialanalysis.ai"
|
|
49
49
|
Repository = "https://github.com/ArtificialAnalysis/Stirrup"
|
|
50
50
|
|
|
51
51
|
[build-system]
|
|
@@ -35,6 +35,7 @@ from stirrup.core.models import (
|
|
|
35
35
|
AssistantMessage,
|
|
36
36
|
AudioContentBlock,
|
|
37
37
|
ChatMessage,
|
|
38
|
+
EmptyParams,
|
|
38
39
|
ImageContentBlock,
|
|
39
40
|
LLMClient,
|
|
40
41
|
SubAgentMetadata,
|
|
@@ -58,6 +59,7 @@ __all__ = [
|
|
|
58
59
|
"AudioContentBlock",
|
|
59
60
|
"ChatMessage",
|
|
60
61
|
"ContextOverflowError",
|
|
62
|
+
"EmptyParams",
|
|
61
63
|
"ImageContentBlock",
|
|
62
64
|
"LLMClient",
|
|
63
65
|
"SubAgentMetadata",
|
|
@@ -67,7 +67,6 @@ class ChatCompletionsClient(LLMClient):
|
|
|
67
67
|
*,
|
|
68
68
|
base_url: str | None = None,
|
|
69
69
|
api_key: str | None = None,
|
|
70
|
-
supports_audio_input: bool = False,
|
|
71
70
|
reasoning_effort: str | None = None,
|
|
72
71
|
timeout: float | None = None,
|
|
73
72
|
max_retries: int = 2,
|
|
@@ -82,7 +81,6 @@ class ChatCompletionsClient(LLMClient):
|
|
|
82
81
|
Use for OpenAI-compatible providers (e.g., 'http://localhost:8000/v1').
|
|
83
82
|
api_key: API key for authentication. If None, reads from OPENROUTER_API_KEY
|
|
84
83
|
environment variable.
|
|
85
|
-
supports_audio_input: Whether the model supports audio inputs. Defaults to False.
|
|
86
84
|
reasoning_effort: Reasoning effort level for extended thinking models
|
|
87
85
|
(e.g., 'low', 'medium', 'high'). Only used with o1/o3 style models.
|
|
88
86
|
timeout: Request timeout in seconds. If None, uses OpenAI SDK default.
|
|
@@ -92,7 +90,6 @@ class ChatCompletionsClient(LLMClient):
|
|
|
92
90
|
"""
|
|
93
91
|
self._model = model
|
|
94
92
|
self._max_tokens = max_tokens
|
|
95
|
-
self._supports_audio_input = supports_audio_input
|
|
96
93
|
self._reasoning_effort = reasoning_effort
|
|
97
94
|
self._kwargs = kwargs or {}
|
|
98
95
|
|
|
@@ -7,7 +7,7 @@ Requires the litellm extra: `pip install stirrup[litellm]`
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
|
-
from typing import Any
|
|
10
|
+
from typing import Any, Literal
|
|
11
11
|
|
|
12
12
|
try:
|
|
13
13
|
from litellm import acompletion
|
|
@@ -38,6 +38,8 @@ __all__ = [
|
|
|
38
38
|
|
|
39
39
|
LOGGER = logging.getLogger(__name__)
|
|
40
40
|
|
|
41
|
+
type ReasoningEffort = Literal["none", "minimal", "low", "medium", "high", "xhigh", "default"]
|
|
42
|
+
|
|
41
43
|
|
|
42
44
|
class LiteLLMClient(LLMClient):
|
|
43
45
|
"""LiteLLM-based client supporting multiple LLM providers with unified interface.
|
|
@@ -49,8 +51,8 @@ class LiteLLMClient(LLMClient):
|
|
|
49
51
|
self,
|
|
50
52
|
model_slug: str,
|
|
51
53
|
max_tokens: int,
|
|
52
|
-
|
|
53
|
-
reasoning_effort:
|
|
54
|
+
api_key: str | None = None,
|
|
55
|
+
reasoning_effort: ReasoningEffort | None = None,
|
|
54
56
|
kwargs: dict[str, Any] | None = None,
|
|
55
57
|
) -> None:
|
|
56
58
|
"""Initialize LiteLLM client with model configuration and capabilities.
|
|
@@ -58,15 +60,13 @@ class LiteLLMClient(LLMClient):
|
|
|
58
60
|
Args:
|
|
59
61
|
model_slug: Model identifier for LiteLLM (e.g., 'anthropic/claude-3-5-sonnet-20241022')
|
|
60
62
|
max_tokens: Maximum context window size in tokens
|
|
61
|
-
supports_audio_input: Whether the model supports audio inputs
|
|
62
63
|
reasoning_effort: Reasoning effort level for extended thinking models (e.g., 'medium', 'high')
|
|
63
64
|
kwargs: Additional arguments to pass to LiteLLM completion calls
|
|
64
65
|
"""
|
|
65
66
|
self._model_slug = model_slug
|
|
66
|
-
self._supports_video_input = False
|
|
67
|
-
self._supports_audio_input = supports_audio_input
|
|
68
67
|
self._max_tokens = max_tokens
|
|
69
|
-
self._reasoning_effort = reasoning_effort
|
|
68
|
+
self._reasoning_effort: ReasoningEffort | None = reasoning_effort
|
|
69
|
+
self._api_key = api_key
|
|
70
70
|
self._kwargs = kwargs or {}
|
|
71
71
|
|
|
72
72
|
@property
|
|
@@ -92,6 +92,8 @@ class LiteLLMClient(LLMClient):
|
|
|
92
92
|
tools=to_openai_tools(tools) if tools else None,
|
|
93
93
|
tool_choice="auto" if tools else None,
|
|
94
94
|
max_tokens=self._max_tokens,
|
|
95
|
+
reasoning_effort=self._reasoning_effort,
|
|
96
|
+
api_key=self._api_key,
|
|
95
97
|
**self._kwargs,
|
|
96
98
|
)
|
|
97
99
|
|
|
@@ -103,14 +105,20 @@ class LiteLLMClient(LLMClient):
|
|
|
103
105
|
)
|
|
104
106
|
|
|
105
107
|
msg = choice["message"]
|
|
106
|
-
|
|
107
108
|
reasoning: Reasoning | None = None
|
|
108
109
|
if getattr(msg, "reasoning_content", None) is not None:
|
|
109
110
|
reasoning = Reasoning(content=msg.reasoning_content)
|
|
110
111
|
if getattr(msg, "thinking_blocks", None) is not None and len(msg.thinking_blocks) > 0:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
if len(msg.thinking_blocks) > 1:
|
|
113
|
+
raise ValueError("Found multiple thinking blocks in the response")
|
|
114
|
+
|
|
115
|
+
signature = msg.thinking_blocks[0].get("thinking_signature", None)
|
|
116
|
+
content = msg.thinking_blocks[0].get("thinking", None)
|
|
117
|
+
|
|
118
|
+
if signature is None and content is None:
|
|
119
|
+
raise ValueError("Signature and content not found in the thinking block response")
|
|
120
|
+
|
|
121
|
+
reasoning = Reasoning(signature=signature, content=content)
|
|
114
122
|
|
|
115
123
|
usage = r["usage"]
|
|
116
124
|
|
|
@@ -119,6 +127,7 @@ class LiteLLMClient(LLMClient):
|
|
|
119
127
|
tool_call_id=tc.get("id"),
|
|
120
128
|
name=tc["function"]["name"],
|
|
121
129
|
arguments=tc["function"].get("arguments", "") or "",
|
|
130
|
+
signature=tc.get("provider_specific_fields", {}).get("thought_signature", None),
|
|
122
131
|
)
|
|
123
132
|
for tc in (msg.get("tool_calls") or [])
|
|
124
133
|
]
|
|
@@ -12,6 +12,7 @@ from stirrup.core.models import (
|
|
|
12
12
|
AudioContentBlock,
|
|
13
13
|
ChatMessage,
|
|
14
14
|
Content,
|
|
15
|
+
EmptyParams,
|
|
15
16
|
ImageContentBlock,
|
|
16
17
|
SystemMessage,
|
|
17
18
|
Tool,
|
|
@@ -47,7 +48,7 @@ def to_openai_tools(tools: dict[str, Tool]) -> list[dict[str, Any]]:
|
|
|
47
48
|
"name": t.name,
|
|
48
49
|
"description": t.description,
|
|
49
50
|
}
|
|
50
|
-
if t.parameters is not
|
|
51
|
+
if t.parameters is not EmptyParams:
|
|
51
52
|
function["parameters"] = t.parameters.model_json_schema()
|
|
52
53
|
tool_payload: dict[str, Any] = {
|
|
53
54
|
"type": "function",
|
|
@@ -139,6 +140,10 @@ def to_openai_messages(msgs: list[ChatMessage]) -> list[dict[str, Any]]:
|
|
|
139
140
|
tool_dict = tool.model_dump()
|
|
140
141
|
tool_dict["id"] = tool.tool_call_id
|
|
141
142
|
tool_dict["type"] = "function"
|
|
143
|
+
if tool.signature is not None:
|
|
144
|
+
tool_dict["provider_specific_fields"] = {
|
|
145
|
+
"thought_signature": tool.signature,
|
|
146
|
+
}
|
|
142
147
|
tool_dict["function"] = {
|
|
143
148
|
"name": tool.name,
|
|
144
149
|
"arguments": tool.arguments,
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
1
3
|
# Tool naming
|
|
2
|
-
FINISH_TOOL_NAME = "finish"
|
|
4
|
+
FINISH_TOOL_NAME: Literal["finish"] = "finish"
|
|
3
5
|
|
|
4
6
|
# Agent execution limits
|
|
5
7
|
AGENT_MAX_TURNS = 30 # Maximum agent turns before forced termination
|
|
6
8
|
CONTEXT_SUMMARIZATION_CUTOFF = 0.7 # Context window usage threshold (0.0-1.0) that triggers message summarization
|
|
9
|
+
TURNS_REMAINING_WARNING_THRESHOLD = 20
|
|
7
10
|
|
|
8
11
|
# Media resolution limits
|
|
9
12
|
RESOLUTION_1MP = 1_000_000 # 1 megapixel - default max resolution for images
|
|
10
13
|
RESOLUTION_480P = 640 * 480 # 480p video resolution
|
|
11
14
|
|
|
12
15
|
# Code execution
|
|
13
|
-
|
|
16
|
+
SANDBOX_TIMEOUT = 60 * 10 # 10 minutes
|
|
17
|
+
SANDBOX_REQUEST_TIMEOUT = 60 * 3 # 3 minutes
|
|
14
18
|
E2B_SANDBOX_TEMPLATE_ALIAS = "e2b-sandbox"
|