@just-every/ensemble 0.1.34 → 0.2.2

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 (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -190
  3. package/dist/config/tool_execution.d.ts +11 -0
  4. package/dist/config/tool_execution.d.ts.map +1 -0
  5. package/dist/config/tool_execution.js +31 -0
  6. package/dist/config/tool_execution.js.map +1 -0
  7. package/dist/core/ensemble_embed.d.ts +3 -0
  8. package/dist/core/ensemble_embed.d.ts.map +1 -0
  9. package/dist/core/ensemble_embed.js +24 -0
  10. package/dist/core/ensemble_embed.js.map +1 -0
  11. package/dist/core/ensemble_image.d.ts +3 -0
  12. package/dist/core/ensemble_image.d.ts.map +1 -0
  13. package/dist/core/ensemble_image.js +10 -0
  14. package/dist/core/ensemble_image.js.map +1 -0
  15. package/dist/core/ensemble_request.d.ts +4 -0
  16. package/dist/core/ensemble_request.d.ts.map +1 -0
  17. package/dist/core/ensemble_request.js +240 -0
  18. package/dist/core/ensemble_request.js.map +1 -0
  19. package/dist/{model_data.d.ts → data/model_data.d.ts} +2 -2
  20. package/dist/data/model_data.d.ts.map +1 -0
  21. package/dist/{model_data.js → data/model_data.js} +52 -3
  22. package/dist/data/model_data.js.map +1 -0
  23. package/dist/index.d.ts +18 -35
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +18 -56
  26. package/dist/index.js.map +1 -1
  27. package/dist/model_providers/base_provider.d.ts +3 -29
  28. package/dist/model_providers/base_provider.d.ts.map +1 -1
  29. package/dist/model_providers/base_provider.js +1 -114
  30. package/dist/model_providers/base_provider.js.map +1 -1
  31. package/dist/model_providers/claude.d.ts +2 -2
  32. package/dist/model_providers/claude.d.ts.map +1 -1
  33. package/dist/model_providers/claude.js +10 -4
  34. package/dist/model_providers/claude.js.map +1 -1
  35. package/dist/model_providers/deepseek.d.ts.map +1 -1
  36. package/dist/model_providers/deepseek.js.map +1 -1
  37. package/dist/model_providers/gemini.d.ts +4 -4
  38. package/dist/model_providers/gemini.d.ts.map +1 -1
  39. package/dist/model_providers/gemini.js +31 -32
  40. package/dist/model_providers/gemini.js.map +1 -1
  41. package/dist/model_providers/grok.d.ts.map +1 -1
  42. package/dist/model_providers/grok.js.map +1 -1
  43. package/dist/model_providers/model_provider.d.ts +3 -4
  44. package/dist/model_providers/model_provider.d.ts.map +1 -1
  45. package/dist/model_providers/model_provider.js +11 -5
  46. package/dist/model_providers/model_provider.js.map +1 -1
  47. package/dist/model_providers/openai.d.ts +4 -4
  48. package/dist/model_providers/openai.d.ts.map +1 -1
  49. package/dist/model_providers/openai.js +24 -26
  50. package/dist/model_providers/openai.js.map +1 -1
  51. package/dist/model_providers/openai_chat.d.ts +3 -3
  52. package/dist/model_providers/openai_chat.d.ts.map +1 -1
  53. package/dist/model_providers/openai_chat.js +2 -2
  54. package/dist/model_providers/openai_chat.js.map +1 -1
  55. package/dist/model_providers/openrouter.d.ts.map +1 -1
  56. package/dist/model_providers/openrouter.js +3 -3
  57. package/dist/model_providers/openrouter.js.map +1 -1
  58. package/dist/model_providers/test_provider.d.ts +3 -5
  59. package/dist/model_providers/test_provider.d.ts.map +1 -1
  60. package/dist/model_providers/test_provider.js +9 -17
  61. package/dist/model_providers/test_provider.js.map +1 -1
  62. package/dist/tsconfig.tsbuildinfo +1 -1
  63. package/dist/types/api_types.d.ts +1 -1
  64. package/dist/types/api_types.d.ts.map +1 -1
  65. package/dist/types/tool_types.d.ts +1 -99
  66. package/dist/types/tool_types.d.ts.map +1 -1
  67. package/dist/types/tool_types.js +1 -10
  68. package/dist/types/tool_types.js.map +1 -1
  69. package/dist/{types.d.ts → types/types.d.ts} +82 -32
  70. package/dist/types/types.d.ts.map +1 -0
  71. package/dist/types/types.js.map +1 -0
  72. package/dist/utils/agent.d.ts +41 -0
  73. package/dist/utils/agent.d.ts.map +1 -0
  74. package/dist/utils/agent.js +342 -0
  75. package/dist/utils/agent.js.map +1 -0
  76. package/dist/utils/communication.d.ts +0 -1
  77. package/dist/utils/communication.d.ts.map +1 -1
  78. package/dist/utils/communication.js +1 -4
  79. package/dist/utils/communication.js.map +1 -1
  80. package/dist/utils/cost_tracker.d.ts +1 -1
  81. package/dist/utils/cost_tracker.d.ts.map +1 -1
  82. package/dist/utils/cost_tracker.js +1 -1
  83. package/dist/utils/cost_tracker.js.map +1 -1
  84. package/dist/utils/create_tool_function.d.ts +1 -23
  85. package/dist/utils/create_tool_function.d.ts.map +1 -1
  86. package/dist/utils/create_tool_function.js +14 -3
  87. package/dist/utils/create_tool_function.js.map +1 -1
  88. package/dist/{external_models.d.ts → utils/external_models.d.ts} +1 -2
  89. package/dist/utils/external_models.d.ts.map +1 -0
  90. package/dist/{external_models.js → utils/external_models.js} +0 -3
  91. package/dist/utils/external_models.js.map +1 -0
  92. package/dist/utils/image_to_text.d.ts.map +1 -1
  93. package/dist/utils/image_to_text.js +3 -2
  94. package/dist/utils/image_to_text.js.map +1 -1
  95. package/dist/utils/image_utils.d.ts +1 -4
  96. package/dist/utils/image_utils.d.ts.map +1 -1
  97. package/dist/utils/image_utils.js +2 -10
  98. package/dist/utils/image_utils.js.map +1 -1
  99. package/dist/utils/llm_logger.d.ts +1 -1
  100. package/dist/utils/llm_logger.d.ts.map +1 -1
  101. package/dist/utils/llm_logger.js.map +1 -1
  102. package/dist/utils/message_history.d.ts +4 -4
  103. package/dist/utils/message_history.d.ts.map +1 -1
  104. package/dist/utils/message_history.js +18 -18
  105. package/dist/utils/message_history.js.map +1 -1
  106. package/dist/utils/quota_tracker.d.ts +1 -1
  107. package/dist/utils/quota_tracker.d.ts.map +1 -1
  108. package/dist/utils/quota_tracker.js +0 -1
  109. package/dist/utils/quota_tracker.js.map +1 -1
  110. package/dist/utils/running_tool_tracker.d.ts +42 -0
  111. package/dist/utils/running_tool_tracker.d.ts.map +1 -0
  112. package/dist/utils/running_tool_tracker.js +129 -0
  113. package/dist/utils/running_tool_tracker.js.map +1 -0
  114. package/dist/utils/sequential_queue.d.ts +13 -0
  115. package/dist/utils/sequential_queue.d.ts.map +1 -0
  116. package/dist/utils/sequential_queue.js +68 -0
  117. package/dist/utils/sequential_queue.js.map +1 -0
  118. package/dist/utils/state_manager.d.ts.map +1 -1
  119. package/dist/utils/state_manager.js.map +1 -1
  120. package/dist/utils/stream_converter.d.ts +2 -13
  121. package/dist/utils/stream_converter.d.ts.map +1 -1
  122. package/dist/utils/stream_converter.js +15 -37
  123. package/dist/utils/stream_converter.js.map +1 -1
  124. package/dist/utils/test_utils.d.ts +4 -4
  125. package/dist/utils/test_utils.d.ts.map +1 -1
  126. package/dist/utils/test_utils.js +17 -17
  127. package/dist/utils/test_utils.js.map +1 -1
  128. package/dist/utils/tool_execution_manager.d.ts +7 -0
  129. package/dist/utils/tool_execution_manager.d.ts.map +1 -0
  130. package/dist/utils/tool_execution_manager.js +145 -0
  131. package/dist/utils/tool_execution_manager.js.map +1 -0
  132. package/dist/utils/tool_parameter_utils.d.ts +2 -2
  133. package/dist/utils/tool_parameter_utils.d.ts.map +1 -1
  134. package/dist/utils/tool_parameter_utils.js +8 -4
  135. package/dist/utils/tool_parameter_utils.js.map +1 -1
  136. package/dist/utils/tool_result_processor.d.ts +6 -0
  137. package/dist/utils/tool_result_processor.d.ts.map +1 -0
  138. package/dist/utils/tool_result_processor.js +69 -0
  139. package/dist/utils/tool_result_processor.js.map +1 -0
  140. package/dist/utils/verification.d.ts +7 -0
  141. package/dist/utils/verification.d.ts.map +1 -0
  142. package/dist/utils/verification.js +43 -0
  143. package/dist/utils/verification.js.map +1 -0
  144. package/package.json +11 -10
  145. package/dist/cost_tracker.d.ts +0 -2
  146. package/dist/cost_tracker.d.ts.map +0 -1
  147. package/dist/cost_tracker.js +0 -2
  148. package/dist/cost_tracker.js.map +0 -1
  149. package/dist/errors.d.ts +0 -55
  150. package/dist/errors.d.ts.map +0 -1
  151. package/dist/errors.js +0 -134
  152. package/dist/errors.js.map +0 -1
  153. package/dist/external_models.d.ts.map +0 -1
  154. package/dist/external_models.js.map +0 -1
  155. package/dist/model_data.d.ts.map +0 -1
  156. package/dist/model_data.js.map +0 -1
  157. package/dist/model_providers/refactored_openai.d.ts +0 -22
  158. package/dist/model_providers/refactored_openai.d.ts.map +0 -1
  159. package/dist/model_providers/refactored_openai.js +0 -310
  160. package/dist/model_providers/refactored_openai.js.map +0 -1
  161. package/dist/openai-compat.d.ts +0 -79
  162. package/dist/openai-compat.d.ts.map +0 -1
  163. package/dist/openai-compat.js +0 -581
  164. package/dist/openai-compat.js.map +0 -1
  165. package/dist/test.d.ts +0 -5
  166. package/dist/test.d.ts.map +0 -1
  167. package/dist/test.js +0 -2
  168. package/dist/test.js.map +0 -1
  169. package/dist/types/extended_types.d.ts +0 -43
  170. package/dist/types/extended_types.d.ts.map +0 -1
  171. package/dist/types/extended_types.js +0 -2
  172. package/dist/types/extended_types.js.map +0 -1
  173. package/dist/types.d.ts.map +0 -1
  174. package/dist/types.js.map +0 -1
  175. package/dist/unified_request.d.ts +0 -19
  176. package/dist/unified_request.d.ts.map +0 -1
  177. package/dist/unified_request.js +0 -261
  178. package/dist/unified_request.js.map +0 -1
  179. package/dist/utils/async_queue.d.ts +0 -14
  180. package/dist/utils/async_queue.d.ts.map +0 -1
  181. package/dist/utils/async_queue.js +0 -68
  182. package/dist/utils/async_queue.js.map +0 -1
  183. package/dist/utils/cache.d.ts +0 -60
  184. package/dist/utils/cache.d.ts.map +0 -1
  185. package/dist/utils/cache.js +0 -205
  186. package/dist/utils/cache.js.map +0 -1
  187. package/dist/utils/error_handler.d.ts +0 -33
  188. package/dist/utils/error_handler.d.ts.map +0 -1
  189. package/dist/utils/error_handler.js +0 -84
  190. package/dist/utils/error_handler.js.map +0 -1
  191. package/dist/utils/tool_builder.d.ts +0 -51
  192. package/dist/utils/tool_builder.d.ts.map +0 -1
  193. package/dist/utils/tool_builder.js +0 -167
  194. package/dist/utils/tool_builder.js.map +0 -1
  195. package/dist/utils/tool_utils.d.ts +0 -13
  196. package/dist/utils/tool_utils.d.ts.map +0 -1
  197. package/dist/utils/tool_utils.js +0 -52
  198. package/dist/utils/tool_utils.js.map +0 -1
  199. package/dist/validation.d.ts +0 -1789
  200. package/dist/validation.d.ts.map +0 -1
  201. package/dist/validation.js +0 -289
  202. package/dist/validation.js.map +0 -1
  203. package/test.d.ts +0 -3
  204. package/test.js +0 -4
  205. /package/dist/{types.js → types/types.js} +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Context
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -5,6 +5,16 @@
5
5
 
6
6
  A unified interface for interacting with multiple LLM providers (OpenAI, Anthropic, Google, etc.) with streaming support, tool calling, and embeddings.
7
7
 
8
+ ## Features
9
+
10
+ - 🔄 **Unified Streaming Interface** - Consistent event-based streaming across all providers
11
+ - 🛠️ **Advanced Tool Calling** - Parallel/sequential execution, timeouts, and background tracking
12
+ - 📊 **Cost & Quota Tracking** - Built-in usage monitoring and cost calculation
13
+ - 🎯 **Smart Result Processing** - Automatic summarization and truncation for long outputs
14
+ - 🔌 **Multi-Provider Support** - OpenAI, Anthropic, Google, DeepSeek, xAI, OpenRouter
15
+ - 🖼️ **Multi-Modal** - Support for text, images, and embeddings
16
+ - 📝 **Message History** - Automatic conversation management with compaction
17
+
8
18
  ## Installation
9
19
 
10
20
  ```bash
@@ -14,215 +24,77 @@ npm install @just-every/ensemble
14
24
  ## Quick Start
15
25
 
16
26
  ```typescript
17
- import { request, embed, image } from '@just-every/ensemble';
18
-
19
- // Simple streaming request
20
- for await (const event of request('gpt-4o-mini', [
21
- { type: 'message', role: 'user', content: 'Hello!' }
22
- ])) {
23
- if (event.type === 'text_delta') {
24
- process.stdout.write(event.delta);
25
- }
26
- }
27
- ```
28
-
29
- ## Core Functions
27
+ import { ensembleRequest } from '@just-every/ensemble';
30
28
 
31
- ### `request(model, messages, options?)`
29
+ const messages = [
30
+ { type: 'message', role: 'user', content: 'Hello, how are you?' }
31
+ ];
32
32
 
33
- Make streaming LLM requests with automatic tool execution.
33
+ const agent = {
34
+ model: 'o3',
35
+ agent_id: 'assistant'
36
+ };
34
37
 
35
- ```typescript
36
- // Basic usage
37
- const stream = request('claude-3.5-sonnet', [
38
- { type: 'message', role: 'user', content: 'Explain quantum computing' }
39
- ]);
40
-
41
- for await (const event of stream) {
42
- if (event.type === 'text_delta') {
43
- process.stdout.write(event.delta);
44
- } else if (event.type === 'cost_update') {
45
- console.log(`Cost: $${event.usage.total_cost}`);
46
- }
47
- }
48
-
49
- // With tools
50
- const tools = [{
51
- function: async ({ city }) => `Weather in ${city}: Sunny, 72°F`,
52
- definition: {
53
- type: 'function',
54
- function: {
55
- name: 'get_weather',
56
- description: 'Get weather for a city',
57
- parameters: {
58
- type: 'object',
59
- properties: {
60
- city: { type: 'string' }
61
- },
62
- required: ['city']
63
- }
38
+ for await (const event of ensembleRequest(messages, agent)) {
39
+ if (event.type === 'message_delta') {
40
+ process.stdout.write(event.content);
64
41
  }
65
- }
66
- }];
67
-
68
- const stream = request('gpt-4o', [
69
- { type: 'message', role: 'user', content: 'What\'s the weather in Paris?' }
70
- ], { tools });
71
- ```
72
-
73
- ### `embed(text, options?)`
74
-
75
- Generate embeddings for semantic search and RAG applications.
76
-
77
- ```typescript
78
- // Simple embedding
79
- const embedding = await embed('Hello, world!');
80
- console.log(`Dimension: ${embedding.length}`); // e.g., 1536
81
-
82
- // With specific model
83
- const embedding = await embed('Search query', {
84
- model: 'text-embedding-3-large'
85
- });
86
-
87
- // Calculate similarity
88
- function cosineSimilarity(a: number[], b: number[]): number {
89
- const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
90
- const normA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
91
- const normB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
92
- return dotProduct / (normA * normB);
93
42
  }
94
-
95
- const similarity = cosineSimilarity(embedding1, embedding2);
96
43
  ```
97
44
 
98
- ### `image(prompt, options?)`
99
-
100
- Generate images from text prompts using DALL-E or Imagen models.
101
-
102
- ```typescript
103
- // Simple image generation
104
- const result = await image('A beautiful sunset over mountains');
105
- console.log(`Generated ${result.images.length} image(s)`);
106
-
107
- // With specific options
108
- const result = await image('A robot holding a skateboard', {
109
- model: 'dall-e-3',
110
- size: 'landscape',
111
- quality: 'hd',
112
- n: 2
113
- });
114
-
115
- // Image editing (DALL-E 2 only)
116
- const result = await image('Add a red hat to the person', {
117
- model: 'dall-e-2',
118
- source_images: 'data:image/png;base64,...' // or URL
119
- });
120
-
121
- // Inpainting with mask
122
- const result = await image('Replace with a golden retriever', {
123
- model: 'dall-e-2',
124
- source_images: originalImage,
125
- mask: maskImage // transparent areas will be edited
126
- });
127
-
128
- // Using Google Imagen
129
- const result = await image('A serene lake at dawn', {
130
- model: 'imagen-3.0-generate-002',
131
- size: 'portrait'
132
- });
133
- ```
134
-
135
- ### `chainRequests(messages, requests)`
136
-
137
- Chain multiple LLM calls, using the output of one as input to the next.
138
-
139
- ```typescript
140
- import { chainRequests } from '@just-every/ensemble';
141
-
142
- const result = await chainRequests(
143
- [{ type: 'message', role: 'user', content: 'Analyze this code for bugs: ...' }],
144
- [
145
- {
146
- model: 'gpt-4o',
147
- systemPrompt: 'You are a code reviewer. Find bugs and security issues.'
148
- },
149
- {
150
- model: 'claude-3.5-sonnet',
151
- systemPrompt: 'Prioritize the issues found and suggest fixes.'
152
- },
153
- {
154
- model: 'gpt-4o-mini',
155
- systemPrompt: 'Summarize the analysis in 3 bullet points.'
156
- }
157
- ]
158
- );
159
-
160
- console.log(result.fullResponse);
161
- ```
45
+ ## Documentation
162
46
 
163
- ## Supported Providers
47
+ - [Tool Execution Guide](docs/tool-execution.md) - Advanced tool calling features
48
+ - [Examples](examples/) - Complete working examples
49
+ - [API Reference](docs/api.md) - Full API documentation
164
50
 
165
- - **OpenAI**: GPT-4o, GPT-4o-mini, o1-preview, o1-mini
166
- - **Anthropic**: Claude 3.5 Sonnet, Claude 3.5 Haiku
167
- - **Google**: Gemini 2.0 Flash, Gemini 1.5 Pro
168
- - **DeepSeek**: DeepSeek Chat, DeepSeek Coder
169
- - **xAI**: Grok 2, Grok Beta
170
- - **OpenRouter**: Access to 100+ models
51
+ ## Core Concepts
171
52
 
172
- ## OpenAI SDK Compatibility
53
+ ### Tools
173
54
 
174
- Drop-in replacement for the OpenAI SDK:
55
+ Define tools that LLMs can call:
175
56
 
176
57
  ```typescript
177
- // Instead of: import OpenAI from 'openai';
178
- import OpenAIEnsemble from '@just-every/ensemble/openai-compat';
179
-
180
- const completion = await OpenAIEnsemble.chat.completions.create({
181
- model: 'claude-3.5-sonnet', // Use any supported model!
182
- messages: [{ role: 'user', content: 'Hello!' }],
183
- stream: true
184
- });
58
+ const agent = {
59
+ model: 'o3',
60
+ tools: [{
61
+ definition: {
62
+ type: 'function',
63
+ function: {
64
+ name: 'get_weather',
65
+ description: 'Get weather for a location',
66
+ parameters: {
67
+ type: 'object',
68
+ properties: {
69
+ location: { type: 'string' }
70
+ },
71
+ required: ['location']
72
+ }
73
+ }
74
+ },
75
+ function: async (location: string) => {
76
+ return `Weather in ${location}: Sunny, 72°F`;
77
+ }
78
+ }]
79
+ };
185
80
  ```
186
81
 
187
- ## Environment Variables
82
+ ### Streaming Events
188
83
 
189
- ```bash
190
- ANTHROPIC_API_KEY=your_key_here
191
- OPENAI_API_KEY=your_key_here
192
- GOOGLE_API_KEY=your_key_here
193
- DEEPSEEK_API_KEY=your_key_here
194
- XAI_API_KEY=your_key_here
195
- OPENROUTER_API_KEY=your_key_here
196
- ```
84
+ All providers emit standardized events:
197
85
 
198
- ## Key Features
86
+ - `message_start` / `message_delta` / `message_complete` - Message streaming
87
+ - `tool_start` / `tool_delta` / `tool_done` - Tool execution
88
+ - `cost_update` - Token usage and cost tracking
89
+ - `error` - Error handling
199
90
 
200
- - **Unified streaming API** across all LLM providers
201
- - **Automatic tool execution** with type-safe function calling
202
- - **Smart model rotation** based on availability and performance
203
- - **Built-in embeddings** with caching
204
- - **Image generation** with DALL-E and Imagen support
205
- - **OpenAI SDK compatibility** - drop-in replacement
206
- - **Cost tracking** and quota management
207
-
208
- ## Documentation
91
+ ### Advanced Features
209
92
 
210
- - [Model Selection & Management](./docs/models.md)
211
- - [Advanced Usage](./docs/advanced-usage.md) - Tools, structured output, images
212
- - [Image Generation](./docs/image-generation.md) - DALL-E and Imagen support
213
- - [Error Handling](./docs/error-handling.md)
214
- - [OpenAI Compatibility](./docs/openai-compatibility.md)
215
- - [Utility Functions](./docs/utilities.md)
216
- - [Test Utilities](./docs/test-utilities.md) - Testing helpers and mocks
217
-
218
- ## Examples
219
-
220
- See the [examples](./examples) directory for:
221
- - [Basic usage](./examples/basic-request.ts)
222
- - [Tool calling](./examples/tool-calling.ts)
223
- - [Embeddings & semantic search](./examples/embeddings.ts)
224
- - [Model rotation](./examples/model-rotation.ts)
225
- - [Stream conversion](./examples/stream-conversion.ts)
93
+ - **Parallel Tool Execution** - Tools run concurrently by default
94
+ - **Sequential Mode** - Enforce one-at-a-time execution
95
+ - **Timeout Handling** - Automatic timeout with background tracking
96
+ - **Result Summarization** - Long outputs are intelligently summarized
97
+ - **Abort Signals** - Graceful cancellation support
226
98
 
227
99
  ## License
228
100
 
@@ -0,0 +1,11 @@
1
+ export declare const FUNCTION_TIMEOUT_MS = 30000;
2
+ export declare const EXCLUDED_FROM_TIMEOUT_FUNCTIONS: Set<string>;
3
+ export declare const MAX_RESULT_LENGTH = 1000;
4
+ export declare const SKIP_SUMMARIZATION_TOOLS: Set<string>;
5
+ export interface ToolConfig {
6
+ skipSummarization?: boolean;
7
+ maxLength?: number;
8
+ truncationMessage?: string;
9
+ }
10
+ export declare const TOOL_CONFIGS: Record<string, ToolConfig>;
11
+ //# sourceMappingURL=tool_execution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool_execution.d.ts","sourceRoot":"","sources":["../../config/tool_execution.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAKzC,eAAO,MAAM,+BAA+B,aAM1C,CAAC;AAKH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAKtC,eAAO,MAAM,wBAAwB,aAKnC,CAAC;AAKH,MAAM,WAAW,UAAU;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAenD,CAAC"}
@@ -0,0 +1,31 @@
1
+ export const FUNCTION_TIMEOUT_MS = 30000;
2
+ export const EXCLUDED_FROM_TIMEOUT_FUNCTIONS = new Set([
3
+ 'wait_for_running_tool',
4
+ 'run_shell_command_with_output',
5
+ 'execute_code',
6
+ 'debug_code',
7
+ 'test_code',
8
+ ]);
9
+ export const MAX_RESULT_LENGTH = 1000;
10
+ export const SKIP_SUMMARIZATION_TOOLS = new Set([
11
+ 'read_source',
12
+ 'get_page_content',
13
+ 'read_file',
14
+ 'list_files',
15
+ ]);
16
+ export const TOOL_CONFIGS = {
17
+ read_source: {
18
+ skipSummarization: true,
19
+ maxLength: 1000,
20
+ truncationMessage: '\n\n[Full output truncated: Use write_source(summary_id, file_path) to write full output to a file.]',
21
+ },
22
+ get_page_content: {
23
+ skipSummarization: true,
24
+ maxLength: 1000,
25
+ },
26
+ read_file: {
27
+ skipSummarization: true,
28
+ maxLength: 1000,
29
+ },
30
+ };
31
+ //# sourceMappingURL=tool_execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool_execution.js","sourceRoot":"","sources":["../../config/tool_execution.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAKzC,MAAM,CAAC,MAAM,+BAA+B,GAAG,IAAI,GAAG,CAAC;IACnD,uBAAuB;IACvB,+BAA+B;IAC/B,cAAc;IACd,YAAY;IACZ,WAAW;CACd,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAKtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IAC5C,aAAa;IACb,kBAAkB;IAClB,WAAW;IACX,YAAY;CACf,CAAC,CAAC;AAWH,MAAM,CAAC,MAAM,YAAY,GAA+B;IACpD,WAAW,EAAE;QACT,iBAAiB,EAAE,IAAI;QACvB,SAAS,EAAE,IAAI;QACf,iBAAiB,EACb,sGAAsG;KAC7G;IACD,gBAAgB,EAAE;QACd,iBAAiB,EAAE,IAAI;QACvB,SAAS,EAAE,IAAI;KAClB;IACD,SAAS,EAAE;QACP,iBAAiB,EAAE,IAAI;QACvB,SAAS,EAAE,IAAI;KAClB;CACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AgentDefinition, EmbedOpts } from '../types/types.js';
2
+ export declare function ensembleEmbed(text: string, agent: AgentDefinition, options?: EmbedOpts): Promise<number[]>;
3
+ //# sourceMappingURL=ensemble_embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensemble_embed.d.ts","sourceRoot":"","sources":["../../core/ensemble_embed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAuCpE,wBAAsB,aAAa,CAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,SAAS,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAqCnB"}
@@ -0,0 +1,24 @@
1
+ import { getModelFromAgent, getModelProvider, } from '../model_providers/model_provider.js';
2
+ const embeddingCache = new Map();
3
+ export async function ensembleEmbed(text, agent, options) {
4
+ const cacheKey = `${agent.model || agent.modelClass}:${text}`;
5
+ if (embeddingCache.has(cacheKey)) {
6
+ const cached = embeddingCache.get(cacheKey);
7
+ return cached.embedding;
8
+ }
9
+ const model = await getModelFromAgent(agent, 'embedding');
10
+ const provider = getModelProvider(model);
11
+ if (!provider.createEmbedding) {
12
+ throw new Error(`Provider for model ${model} does not support embeddings`);
13
+ }
14
+ const result = await provider.createEmbedding(text, model, options);
15
+ const embedding = Array.isArray(result[0])
16
+ ? result[0]
17
+ : result;
18
+ embeddingCache.set(cacheKey, {
19
+ embedding,
20
+ timestamp: new Date(),
21
+ });
22
+ return embedding;
23
+ }
24
+ //# sourceMappingURL=ensemble_embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensemble_embed.js","sourceRoot":"","sources":["../../core/ensemble_embed.ts"],"names":[],"mappings":"AACA,OAAO,EACH,iBAAiB,EACjB,gBAAgB,GACnB,MAAM,sCAAsC,CAAC;AAG9C,MAAM,cAAc,GAAG,IAAI,GAAG,EAM3B,CAAC;AA0BJ,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,IAAY,EACZ,KAAsB,EACtB,OAAmB;IAGnB,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;IAG9D,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;QAC7C,OAAO,MAAM,CAAC,SAAS,CAAC;IAC5B,CAAC;IAGD,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAG1D,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEzC,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACX,sBAAsB,KAAK,8BAA8B,CAC5D,CAAC;IACN,CAAC;IAGD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAGpE,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACX,CAAC,CAAE,MAAmB,CAAC;IAG3B,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE;QACzB,SAAS;QACT,SAAS,EAAE,IAAI,IAAI,EAAE;KACxB,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC;AACrB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AgentDefinition, ImageGenerationOpts } from '../types/types.js';
2
+ export declare function ensembleImage(prompt: string, agent: AgentDefinition, options?: ImageGenerationOpts): Promise<string[]>;
3
+ //# sourceMappingURL=ensemble_image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensemble_image.d.ts","sourceRoot":"","sources":["../../core/ensemble_image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AA2B9E,wBAAsB,aAAa,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,eAAe,EACtB,OAAO,GAAE,mBAAwB,GAClC,OAAO,CAAC,MAAM,EAAE,CAAC,CAWnB"}
@@ -0,0 +1,10 @@
1
+ import { getModelFromAgent, getModelProvider, } from '../model_providers/model_provider.js';
2
+ export async function ensembleImage(prompt, agent, options = {}) {
3
+ const model = await getModelFromAgent(agent, 'image_generation');
4
+ const provider = getModelProvider(model);
5
+ if (!provider.createImage) {
6
+ throw new Error(`Provider for model ${model} does not support image generation`);
7
+ }
8
+ return provider.createImage(prompt, model, options);
9
+ }
10
+ //# sourceMappingURL=ensemble_image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensemble_image.js","sourceRoot":"","sources":["../../core/ensemble_image.ts"],"names":[],"mappings":"AACA,OAAO,EACH,iBAAiB,EACjB,gBAAgB,GACnB,MAAM,sCAAsC,CAAC;AAuB9C,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,MAAc,EACd,KAAsB,EACtB,UAA+B,EAAE;IAEjC,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEzC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACX,sBAAsB,KAAK,oCAAoC,CAClE,CAAC;IACN,CAAC;IAED,OAAO,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { ProviderStreamEvent, ResponseInput, AgentDefinition } from '../types/types.js';
2
+ export declare function ensembleRequest(messages: ResponseInput, agent: AgentDefinition): AsyncGenerator<ProviderStreamEvent>;
3
+ export declare function mergeHistoryThread(mainHistory: ResponseInput, thread: ResponseInput, startIndex: number): void;
4
+ //# sourceMappingURL=ensemble_request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensemble_request.d.ts","sourceRoot":"","sources":["../../core/ensemble_request.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,mBAAmB,EACnB,aAAa,EAGb,eAAe,EAGlB,MAAM,mBAAmB,CAAC;AAkB3B,wBAAuB,eAAe,CAClC,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,eAAe,GACvB,cAAc,CAAC,mBAAmB,CAAC,CAsGrC;AAwRD,wBAAgB,kBAAkB,CAC9B,WAAW,EAAE,aAAa,EAC1B,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,MAAM,GACnB,IAAI,CAGN"}
@@ -0,0 +1,240 @@
1
+ import { createRequestContext, ToolCallAction, } from '../types/tool_types.js';
2
+ import { getModelFromAgent, getModelProvider, } from '../model_providers/model_provider.js';
3
+ import { MessageHistory } from '../utils/message_history.js';
4
+ import { handleToolCall } from '../utils/tool_execution_manager.js';
5
+ import { processToolResult } from '../utils/tool_result_processor.js';
6
+ import { verifyOutput } from '../utils/verification.js';
7
+ export async function* ensembleRequest(messages, agent) {
8
+ const conversationHistory = agent?.historyThread || messages;
9
+ const history = new MessageHistory(conversationHistory, {
10
+ compactToolCalls: true,
11
+ preserveSystemMessages: true,
12
+ });
13
+ const context = createRequestContext({
14
+ messages: history.getMessages(),
15
+ });
16
+ try {
17
+ let totalToolCalls = 0;
18
+ let toolCallRounds = 0;
19
+ const maxToolCalls = agent?.maxToolCalls || 200;
20
+ const maxRounds = agent?.maxToolCallRoundsPerTurn || Infinity;
21
+ let hasToolCalls = true;
22
+ let lastMessageContent = '';
23
+ while (hasToolCalls && toolCallRounds < maxRounds && totalToolCalls < maxToolCalls) {
24
+ hasToolCalls = false;
25
+ const roundResult = await executeRound(agent, context, history, totalToolCalls, maxToolCalls);
26
+ for await (const event of roundResult.stream) {
27
+ yield event;
28
+ }
29
+ if (roundResult.toolCount > 0) {
30
+ hasToolCalls = true;
31
+ totalToolCalls += roundResult.toolCount;
32
+ toolCallRounds++;
33
+ }
34
+ if (roundResult.messageContent) {
35
+ lastMessageContent = roundResult.messageContent;
36
+ }
37
+ }
38
+ if (hasToolCalls && toolCallRounds >= maxRounds) {
39
+ yield {
40
+ type: 'message_delta',
41
+ content: '\n\n[Tool call rounds limit reached]',
42
+ };
43
+ }
44
+ else if (hasToolCalls && totalToolCalls >= maxToolCalls) {
45
+ yield {
46
+ type: 'message_delta',
47
+ content: '\n\n[Total tool calls limit reached]',
48
+ };
49
+ }
50
+ if (agent?.verifier && lastMessageContent) {
51
+ const verificationResult = await performVerification(agent, lastMessageContent, history.getMessages());
52
+ if (verificationResult) {
53
+ for await (const event of verificationResult) {
54
+ yield event;
55
+ }
56
+ }
57
+ }
58
+ }
59
+ catch (error) {
60
+ yield {
61
+ type: 'error',
62
+ error: error.message || 'Unknown error',
63
+ code: error.code,
64
+ details: error.details,
65
+ recoverable: error.recoverable,
66
+ timestamp: new Date().toISOString(),
67
+ };
68
+ }
69
+ finally {
70
+ yield {
71
+ type: 'stream_end',
72
+ timestamp: new Date().toISOString(),
73
+ };
74
+ }
75
+ }
76
+ async function executeRound(agent, context, history, currentToolCalls, maxToolCalls) {
77
+ const events = [];
78
+ let messageContent = '';
79
+ let toolCount = 0;
80
+ const messages = history.getMessages();
81
+ const model = await getModelFromAgent(agent);
82
+ const provider = await getModelProvider(model);
83
+ const stream = provider.createResponseStream(messages, model, agent);
84
+ const toolPromises = [];
85
+ for await (const event of stream) {
86
+ if (agent.allowedEvents && !agent.allowedEvents.includes(event.type)) {
87
+ continue;
88
+ }
89
+ events.push(event);
90
+ switch (event.type) {
91
+ case 'message_complete':
92
+ if ('content' in event) {
93
+ messageContent = event.content;
94
+ }
95
+ break;
96
+ case 'tool_start':
97
+ if ('tool_calls' in event && event.tool_calls) {
98
+ const remainingCalls = maxToolCalls - currentToolCalls;
99
+ if (remainingCalls <= 0) {
100
+ console.warn(`Tool call limit reached (${maxToolCalls}). Skipping tool calls.`);
101
+ break;
102
+ }
103
+ const toolCallsToProcess = event.tool_calls.slice(0, remainingCalls);
104
+ toolCount += toolCallsToProcess.length;
105
+ toolPromises.push(processToolCalls(toolCallsToProcess, agent, context));
106
+ }
107
+ break;
108
+ case 'error':
109
+ if (context) {
110
+ context.halt();
111
+ }
112
+ break;
113
+ }
114
+ }
115
+ const toolResults = (await Promise.all(toolPromises)).flat();
116
+ if (messageContent.length > 0 || toolResults.length > 0) {
117
+ history.addAssistantResponse(messageContent, toolResults);
118
+ }
119
+ if (context) {
120
+ context.messages = history.getMessages();
121
+ context.toolCallCount += toolResults.length;
122
+ }
123
+ async function* eventGenerator() {
124
+ for (const event of events) {
125
+ yield event;
126
+ }
127
+ }
128
+ return {
129
+ stream: eventGenerator(),
130
+ toolCount,
131
+ messageContent,
132
+ };
133
+ }
134
+ async function* performVerification(agent, output, messages, attempt = 0) {
135
+ if (!agent.verifier)
136
+ return;
137
+ const maxAttempts = agent.maxVerificationAttempts || 2;
138
+ const verification = await verifyOutput(agent.verifier, output, messages);
139
+ if (verification.status === 'pass') {
140
+ yield {
141
+ type: 'message_delta',
142
+ content: '\n\n✓ Output verified',
143
+ };
144
+ return;
145
+ }
146
+ if (attempt < maxAttempts - 1) {
147
+ yield {
148
+ type: 'message_delta',
149
+ content: `\n\n⚠️ Verification failed: ${verification.reason}\n\nRetrying...`,
150
+ };
151
+ const retryMessages = [
152
+ ...messages,
153
+ { type: 'message', role: 'assistant', content: output, status: 'completed' },
154
+ {
155
+ type: 'message',
156
+ role: 'developer',
157
+ content: `Verification failed: ${verification.reason}\n\nPlease correct your response.`
158
+ }
159
+ ];
160
+ const retryAgent = {
161
+ ...agent,
162
+ verifier: undefined,
163
+ historyThread: retryMessages,
164
+ };
165
+ const retryStream = ensembleRequest(retryMessages, retryAgent);
166
+ let retryOutput = '';
167
+ for await (const event of retryStream) {
168
+ yield event;
169
+ if (event.type === 'message_complete' && 'content' in event) {
170
+ retryOutput = event.content;
171
+ }
172
+ }
173
+ if (retryOutput) {
174
+ yield* performVerification(agent, retryOutput, messages, attempt + 1);
175
+ }
176
+ }
177
+ else {
178
+ yield {
179
+ type: 'message_delta',
180
+ content: `\n\n❌ Verification failed after ${maxAttempts} attempts: ${verification.reason}`,
181
+ };
182
+ }
183
+ }
184
+ async function processToolCalls(toolCalls, agent, context) {
185
+ const toolCallPromises = toolCalls.map(async (toolCall) => {
186
+ if (agent.onToolCall) {
187
+ const action = await agent.onToolCall(toolCall);
188
+ if (action && action === ToolCallAction.SKIP) {
189
+ return null;
190
+ }
191
+ if (action === ToolCallAction.HALT && context) {
192
+ context.halt();
193
+ return null;
194
+ }
195
+ }
196
+ try {
197
+ if (!agent.tools) {
198
+ throw new Error('No tools available for agent');
199
+ }
200
+ const tool = agent.tools.find(t => t.definition.function.name === toolCall.function.name);
201
+ if (!tool || !('function' in tool)) {
202
+ throw new Error(`Tool ${toolCall.function.name} not found`);
203
+ }
204
+ const rawResult = await handleToolCall(toolCall, tool, agent);
205
+ const processedResult = await processToolResult(toolCall, rawResult);
206
+ const toolCallResult = {
207
+ toolCall,
208
+ id: toolCall.id,
209
+ call_id: toolCall.call_id || toolCall.id,
210
+ output: processedResult,
211
+ };
212
+ if (agent.onToolResult) {
213
+ await agent.onToolResult(toolCallResult);
214
+ }
215
+ return toolCallResult;
216
+ }
217
+ catch (error) {
218
+ const errorOutput = error instanceof Error
219
+ ? `Tool execution failed: ${error.message}`
220
+ : `Tool execution failed: ${String(error)}`;
221
+ const toolCallResult = {
222
+ toolCall,
223
+ id: toolCall.id,
224
+ call_id: toolCall.call_id || toolCall.id,
225
+ output: errorOutput,
226
+ };
227
+ if (agent.onToolError) {
228
+ await agent.onToolError(toolCallResult);
229
+ }
230
+ return toolCallResult;
231
+ }
232
+ });
233
+ const results = await Promise.all(toolCallPromises);
234
+ return results.filter((result) => result !== null);
235
+ }
236
+ export function mergeHistoryThread(mainHistory, thread, startIndex) {
237
+ const newMessages = thread.slice(startIndex);
238
+ mainHistory.push(...newMessages);
239
+ }
240
+ //# sourceMappingURL=ensemble_request.js.map