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.
Files changed (37) hide show
  1. {stirrup-0.1.1 → stirrup-0.1.3}/PKG-INFO +36 -16
  2. {stirrup-0.1.1 → stirrup-0.1.3}/README.md +34 -14
  3. {stirrup-0.1.1 → stirrup-0.1.3}/pyproject.toml +2 -2
  4. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/__init__.py +2 -0
  5. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/chat_completions_client.py +0 -3
  6. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/litellm_client.py +20 -11
  7. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/utils.py +6 -1
  8. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/constants.py +6 -2
  9. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/agent.py +206 -57
  10. stirrup-0.1.3/src/stirrup/core/cache.py +479 -0
  11. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/models.py +53 -7
  12. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/base_system_prompt.txt +1 -1
  13. stirrup-0.1.3/src/stirrup/skills/__init__.py +24 -0
  14. stirrup-0.1.3/src/stirrup/skills/skills.py +145 -0
  15. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/__init__.py +2 -0
  16. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/calculator.py +1 -1
  17. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/base.py +7 -0
  18. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/docker.py +16 -4
  19. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/e2b.py +32 -13
  20. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/local.py +16 -4
  21. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/finish.py +1 -1
  22. stirrup-0.1.3/src/stirrup/tools/user_input.py +130 -0
  23. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/web.py +1 -0
  24. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/utils/logging.py +24 -0
  25. {stirrup-0.1.1 → stirrup-0.1.3}/LICENSE +0 -0
  26. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/clients/__init__.py +0 -0
  27. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/__init__.py +0 -0
  28. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/core/exceptions.py +0 -0
  29. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/__init__.py +0 -0
  30. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/message_summarizer.txt +0 -0
  31. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/prompts/message_summarizer_bridge.txt +0 -0
  32. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/py.typed +0 -0
  33. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/code_backends/__init__.py +0 -0
  34. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/mcp.py +0 -0
  35. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/tools/view_image.py +0 -0
  36. {stirrup-0.1.1 → stirrup-0.1.3}/src/stirrup/utils/__init__.py +0 -0
  37. {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.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.github.io/Stirrup
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>&nbsp;<!--
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>&nbsp;<!--
82
- --><a href="https://artificialanalysis.github.io/Stirrup"><img src="https://img.shields.io/badge/MkDocs-4F46E5?logo=materialformkdocs&logoColor=fff" alt="MkDocs" /></a>
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
- uv pip install stirrup # or: uv add stirrup
109
+ pip install stirrup # or: uv add stirrup
109
110
 
110
111
  # With all optional components
111
- uv pip install stirrup[all] # or: uv add stirrup[all]
112
+ pip install 'stirrup[all]' # or: uv add 'stirrup[all]'
112
113
 
113
114
  # Individual extras
114
- uv pip install stirrup[litellm] # or: uv add stirrup[litellm]
115
- uv pip install stirrup[docker] # or: uv add stirrup[docker]
116
- uv pip install stirrup[e2b] # or: uv add stirrup[e2b]
117
- uv pip install stirrup[mcp] # or: uv add stirrup[mcp]
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.github.io/Stirrup/examples/#litellm-multi-provider-support) or [Deepseek Example](https://artificialanalysis.github.io/Stirrup/examples/#openai-compatible-apis-deepseek-vllm-ollama) for complete examples.
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.github.io/Stirrup/getting-started/) - Installation and first agent tutorial
289
- - [Core Concepts](https://artificialanalysis.github.io/Stirrup/concepts/) - Understand Agent, Tools, and Sessions
290
- - [Examples](https://artificialanalysis.github.io/Stirrup/examples/) - Working examples for common patterns
291
- - [Creating Tools](https://artificialanalysis.github.io/Stirrup/guides/tools/) - Build your own tools
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.github.io/Stirrup)
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>&nbsp;<!--
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>&nbsp;<!--
16
- --><a href="https://artificialanalysis.github.io/Stirrup"><img src="https://img.shields.io/badge/MkDocs-4F46E5?logo=materialformkdocs&logoColor=fff" alt="MkDocs" /></a>
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
- uv pip install stirrup # or: uv add stirrup
43
+ pip install stirrup # or: uv add stirrup
43
44
 
44
45
  # With all optional components
45
- uv pip install stirrup[all] # or: uv add stirrup[all]
46
+ pip install 'stirrup[all]' # or: uv add 'stirrup[all]'
46
47
 
47
48
  # Individual extras
48
- uv pip install stirrup[litellm] # or: uv add stirrup[litellm]
49
- uv pip install stirrup[docker] # or: uv add stirrup[docker]
50
- uv pip install stirrup[e2b] # or: uv add stirrup[e2b]
51
- uv pip install stirrup[mcp] # or: uv add stirrup[mcp]
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.github.io/Stirrup/examples/#litellm-multi-provider-support) or [Deepseek Example](https://artificialanalysis.github.io/Stirrup/examples/#openai-compatible-apis-deepseek-vllm-ollama) for complete examples.
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.github.io/Stirrup/getting-started/) - Installation and first agent tutorial
223
- - [Core Concepts](https://artificialanalysis.github.io/Stirrup/concepts/) - Understand Agent, Tools, and Sessions
224
- - [Examples](https://artificialanalysis.github.io/Stirrup/examples/) - Working examples for common patterns
225
- - [Creating Tools](https://artificialanalysis.github.io/Stirrup/guides/tools/) - Build your own tools
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.github.io/Stirrup)
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.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.github.io/Stirrup"
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
- supports_audio_input: bool = False,
53
- reasoning_effort: str | None = None,
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
- reasoning = Reasoning(
112
- signature=msg.thinking_blocks[0]["signature"], content=msg.thinking_blocks[0]["content"]
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 None:
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
- SUBMISSION_SANDBOX_TIMEOUT = 60 * 10 # 10 minutes
16
+ SANDBOX_TIMEOUT = 60 * 10 # 10 minutes
17
+ SANDBOX_REQUEST_TIMEOUT = 60 * 3 # 3 minutes
14
18
  E2B_SANDBOX_TEMPLATE_ALIAS = "e2b-sandbox"