@samrahimi/smol-js 0.6.5 → 0.7.1
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.
- package/README.md +407 -154
- package/dist/cli.js +830 -133
- package/dist/cli.js.map +1 -1
- package/dist/index.d.mts +326 -9
- package/dist/index.d.ts +326 -9
- package/dist/index.js +731 -123
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +726 -122
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/toolHarness.ts +73 -0
package/README.md
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
# smol-js
|
|
2
2
|
|
|
3
|
-
**A TypeScript
|
|
3
|
+
**A TypeScript agentic framework inspired by [smolagents](https://github.com/huggingface/smolagents).**
|
|
4
4
|
|
|
5
|
-
Build AI agents that solve tasks
|
|
5
|
+
Build AI agents that solve tasks autonomously using the ReAct (Reasoning + Acting) pattern. Agents can write and execute JavaScript code, call tools, delegate to other agents, and orchestrate complex workflows via YAML definitions.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@samrahimi/smol-js)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
- **
|
|
12
|
+
- **Two Agent Types**:
|
|
13
|
+
- `CodeAgent` - Writes JavaScript code to solve tasks
|
|
14
|
+
- `ToolUseAgent` - Uses native LLM function calling (OpenAI-style)
|
|
15
|
+
- **YAML Orchestration**: Define complex agent workflows declaratively
|
|
13
16
|
- **Sandboxed Execution**: JavaScript runs in Node's vm module with state persistence
|
|
14
|
-
- **Tool System**:
|
|
15
|
-
- **Nested Agents**:
|
|
17
|
+
- **Extensible Tool System**: Built-in tools + easy custom tool creation
|
|
18
|
+
- **Nested Agents**: Manager-worker patterns for hierarchical task delegation
|
|
19
|
+
- **Exa.ai Integration**: Semantic web search, content extraction, and research automation
|
|
16
20
|
- **Dynamic Imports**: Import npm packages on-the-fly via jsdelivr CDN
|
|
17
|
-
- **Built-in fetch()**: Agents can make HTTP requests directly in generated code
|
|
18
21
|
- **OpenAI-Compatible**: Works with OpenRouter, OpenAI, Azure, Anthropic, and local servers
|
|
19
22
|
- **Streaming**: Real-time output streaming from the LLM
|
|
23
|
+
- **Memory Management**: Context-aware with truncate/compact strategies
|
|
20
24
|
- **Color-Coded Logging**: Beautiful terminal output with session logging to disk
|
|
21
|
-
- **Error Recovery**: Agent can recover from errors and try different approaches
|
|
22
25
|
|
|
23
26
|
## Installation
|
|
24
27
|
|
|
@@ -28,6 +31,56 @@ npm install @samrahimi/smol-js
|
|
|
28
31
|
|
|
29
32
|
## Quick Start
|
|
30
33
|
|
|
34
|
+
### Via CLI (YAML Workflows)
|
|
35
|
+
|
|
36
|
+
The easiest way to get started is using YAML workflows:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Run directly with npx (no installation needed)
|
|
40
|
+
npx @samrahimi/smol-js workflow.yaml --task "Your task here"
|
|
41
|
+
|
|
42
|
+
# Or install globally and use the CLI
|
|
43
|
+
npm install -g @samrahimi/smol-js
|
|
44
|
+
smol-js workflow.yaml --task "Research quantum computing"
|
|
45
|
+
|
|
46
|
+
# Validate a workflow
|
|
47
|
+
npx @samrahimi/smol-js validate workflow.yaml
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Example workflow (`research-agent.yaml`):
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
name: "Research Agent"
|
|
54
|
+
description: "An agent that can search the web and write reports"
|
|
55
|
+
|
|
56
|
+
model:
|
|
57
|
+
modelId: "anthropic/claude-sonnet-4.5"
|
|
58
|
+
baseUrl: "https://openrouter.ai/api/v1"
|
|
59
|
+
maxTokens: 4000
|
|
60
|
+
|
|
61
|
+
tools:
|
|
62
|
+
search:
|
|
63
|
+
type: exa_search
|
|
64
|
+
config:
|
|
65
|
+
apiKey: "$EXA_API_KEY"
|
|
66
|
+
|
|
67
|
+
write:
|
|
68
|
+
type: write_file
|
|
69
|
+
|
|
70
|
+
agents:
|
|
71
|
+
researcher:
|
|
72
|
+
type: ToolUseAgent
|
|
73
|
+
tools:
|
|
74
|
+
- search
|
|
75
|
+
- write
|
|
76
|
+
maxSteps: 10
|
|
77
|
+
customInstructions: "You are a thorough researcher. Always cite sources."
|
|
78
|
+
|
|
79
|
+
entrypoint: researcher
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Programmatic Usage
|
|
83
|
+
|
|
31
84
|
```typescript
|
|
32
85
|
import 'dotenv/config';
|
|
33
86
|
import { CodeAgent, OpenAIModel } from '@samrahimi/smol-js';
|
|
@@ -48,16 +101,59 @@ const result = await agent.run('Calculate the first 10 prime numbers');
|
|
|
48
101
|
console.log(result.output); // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
|
49
102
|
```
|
|
50
103
|
|
|
104
|
+
## Agent Types
|
|
105
|
+
|
|
106
|
+
### CodeAgent
|
|
107
|
+
|
|
108
|
+
Generates and executes JavaScript code to solve tasks. The agent has access to tools as async functions in its execution environment.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { CodeAgent, OpenAIModel } from '@samrahimi/smol-js';
|
|
112
|
+
|
|
113
|
+
const agent = new CodeAgent({
|
|
114
|
+
model,
|
|
115
|
+
tools: [myTool],
|
|
116
|
+
maxSteps: 20,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await agent.run('Analyze the file data.csv and create a summary');
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**How it works:**
|
|
123
|
+
1. Agent generates thought + JavaScript code
|
|
124
|
+
2. Code executes in sandboxed VM
|
|
125
|
+
3. Results become observations
|
|
126
|
+
4. Repeats until `final_answer()` is called
|
|
127
|
+
|
|
128
|
+
### ToolUseAgent
|
|
129
|
+
|
|
130
|
+
Uses native LLM function calling (OpenAI-style tool calling). Better for LLMs with strong tool-calling capabilities.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { ToolUseAgent, OpenAIModel } from '@samrahimi/smol-js';
|
|
134
|
+
|
|
135
|
+
const agent = new ToolUseAgent({
|
|
136
|
+
model,
|
|
137
|
+
tools: [searchTool, readFileTool],
|
|
138
|
+
maxSteps: 15,
|
|
139
|
+
enableParallelToolCalls: true, // Execute independent tools in parallel
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await agent.run('Search for recent AI papers and summarize the top 3');
|
|
143
|
+
```
|
|
144
|
+
|
|
51
145
|
## Configuration
|
|
52
146
|
|
|
53
147
|
### Environment Variables
|
|
54
148
|
|
|
55
149
|
```bash
|
|
56
|
-
# API key for LLM provider
|
|
150
|
+
# API key for LLM provider
|
|
57
151
|
OPENAI_API_KEY=sk-or-v1-your-openrouter-key
|
|
152
|
+
# or
|
|
153
|
+
OPENROUTER_API_KEY=sk-or-v1-your-key
|
|
58
154
|
|
|
59
|
-
#
|
|
60
|
-
|
|
155
|
+
# For Exa.ai tools
|
|
156
|
+
EXA_API_KEY=your-exa-api-key
|
|
61
157
|
```
|
|
62
158
|
|
|
63
159
|
### Model Configuration
|
|
@@ -66,7 +162,7 @@ OPENAI_API_KEY=sk-your-openai-key
|
|
|
66
162
|
const model = new OpenAIModel({
|
|
67
163
|
modelId: 'anthropic/claude-sonnet-4.5', // Model identifier
|
|
68
164
|
apiKey: 'sk-...', // API key (or use env var)
|
|
69
|
-
baseUrl: 'https://openrouter.ai/api/v1', // API endpoint
|
|
165
|
+
baseUrl: 'https://openrouter.ai/api/v1', // API endpoint
|
|
70
166
|
maxTokens: 4096, // Max tokens to generate
|
|
71
167
|
temperature: 0.7, // Generation temperature
|
|
72
168
|
timeout: 120000, // Request timeout in ms
|
|
@@ -82,16 +178,29 @@ const agent = new CodeAgent({
|
|
|
82
178
|
maxSteps: 20, // Max iterations (default: 20)
|
|
83
179
|
codeExecutionDelay: 5000, // Safety delay before execution (default: 5000ms)
|
|
84
180
|
customInstructions: '...', // Additional system prompt instructions
|
|
85
|
-
verboseLevel: LogLevel.INFO, // Logging level
|
|
181
|
+
verboseLevel: LogLevel.INFO, // Logging level
|
|
86
182
|
streamOutputs: true, // Stream LLM output in real-time
|
|
87
|
-
|
|
88
|
-
|
|
183
|
+
persistent: false, // Retain memory between run() calls
|
|
184
|
+
maxContextLength: 100000, // Token limit for context
|
|
185
|
+
memoryStrategy: 'truncate', // 'truncate' or 'compact'
|
|
186
|
+
additionalAuthorizedImports: ['lodash'], // npm packages (CodeAgent only)
|
|
187
|
+
workingDirectory: '/path/to/dir', // Working dir for fs operations
|
|
89
188
|
});
|
|
90
189
|
```
|
|
91
190
|
|
|
92
|
-
##
|
|
191
|
+
## Built-in Tools
|
|
192
|
+
|
|
193
|
+
- **FinalAnswerTool**: Return the final result (always available)
|
|
194
|
+
- **UserInputTool**: Prompt for user input
|
|
195
|
+
- **ReadFileTool**: Read file contents
|
|
196
|
+
- **WriteFileTool**: Write to files
|
|
197
|
+
- **CurlTool**: Make HTTP requests
|
|
198
|
+
- **ExaSearchTool**: Semantic web search via Exa.ai
|
|
199
|
+
- **ExaGetContentsTool**: Fetch and extract webpage content
|
|
200
|
+
- **ExaResearchTool**: Multi-step research workflow
|
|
201
|
+
- **AgentTool**: Wrap agents as tools for nested architectures
|
|
93
202
|
|
|
94
|
-
|
|
203
|
+
## Creating Custom Tools
|
|
95
204
|
|
|
96
205
|
### Class-Based Tools
|
|
97
206
|
|
|
@@ -124,158 +233,310 @@ const agent = new CodeAgent({
|
|
|
124
233
|
});
|
|
125
234
|
```
|
|
126
235
|
|
|
127
|
-
###
|
|
236
|
+
### Registering Tools for YAML Workflows
|
|
128
237
|
|
|
129
238
|
```typescript
|
|
130
|
-
import {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
239
|
+
import { YAMLLoader, Orchestrator } from '@samrahimi/smol-js';
|
|
240
|
+
import { MyCustomTool } from './tools.js';
|
|
241
|
+
|
|
242
|
+
const loader = new YAMLLoader();
|
|
243
|
+
|
|
244
|
+
// Register custom tools by type name
|
|
245
|
+
loader.registerToolType('my_tool', MyCustomTool);
|
|
246
|
+
|
|
247
|
+
// Now use in YAML:
|
|
248
|
+
// tools:
|
|
249
|
+
// custom:
|
|
250
|
+
// type: my_tool
|
|
251
|
+
// config:
|
|
252
|
+
// apiKey: "$MY_API_KEY"
|
|
253
|
+
|
|
254
|
+
const workflow = loader.loadFromFile('./workflow.yaml');
|
|
255
|
+
const orchestrator = new Orchestrator();
|
|
256
|
+
await orchestrator.runWorkflow(workflow, 'Your task here');
|
|
143
257
|
```
|
|
144
258
|
|
|
145
|
-
##
|
|
259
|
+
## YAML Workflow System
|
|
260
|
+
|
|
261
|
+
Define complex agent architectures declaratively:
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
name: "Multi-Agent Research System"
|
|
265
|
+
description: "Manager-worker pattern with specialized agents"
|
|
266
|
+
|
|
267
|
+
model:
|
|
268
|
+
modelId: "anthropic/claude-sonnet-4.5"
|
|
269
|
+
baseUrl: "https://openrouter.ai/api/v1"
|
|
270
|
+
apiKey: "$OPENROUTER_API_KEY"
|
|
271
|
+
|
|
272
|
+
tools:
|
|
273
|
+
search:
|
|
274
|
+
type: exa_search
|
|
275
|
+
config:
|
|
276
|
+
apiKey: "$EXA_API_KEY"
|
|
277
|
+
|
|
278
|
+
read:
|
|
279
|
+
type: read_file
|
|
280
|
+
|
|
281
|
+
write:
|
|
282
|
+
type: write_file
|
|
283
|
+
|
|
284
|
+
agents:
|
|
285
|
+
# Worker agent: specialized in research
|
|
286
|
+
researcher:
|
|
287
|
+
type: ToolUseAgent
|
|
288
|
+
tools:
|
|
289
|
+
- search
|
|
290
|
+
- read
|
|
291
|
+
maxSteps: 8
|
|
292
|
+
temperature: 0.3
|
|
293
|
+
customInstructions: "You are a research specialist. Be thorough and cite sources."
|
|
294
|
+
|
|
295
|
+
# Worker agent: specialized in writing
|
|
296
|
+
writer:
|
|
297
|
+
type: CodeAgent
|
|
298
|
+
tools:
|
|
299
|
+
- write
|
|
300
|
+
maxSteps: 5
|
|
301
|
+
temperature: 0.7
|
|
302
|
+
customInstructions: "You are a skilled technical writer. Create clear, engaging content."
|
|
303
|
+
|
|
304
|
+
# Manager agent: delegates to workers
|
|
305
|
+
manager:
|
|
306
|
+
type: ToolUseAgent
|
|
307
|
+
agents:
|
|
308
|
+
- researcher # Available as a tool
|
|
309
|
+
- writer # Available as a tool
|
|
310
|
+
maxSteps: 10
|
|
311
|
+
customInstructions: "You coordinate research and writing tasks. Delegate appropriately."
|
|
312
|
+
|
|
313
|
+
entrypoint: manager
|
|
314
|
+
```
|
|
146
315
|
|
|
147
|
-
|
|
316
|
+
Run it:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
npx @samrahimi/smol-js research-workflow.yaml --task "Write a report on quantum computing"
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Nested Agents (Manager-Worker Pattern)
|
|
323
|
+
|
|
324
|
+
Use agents as tools for hierarchical task delegation:
|
|
148
325
|
|
|
149
326
|
```typescript
|
|
150
|
-
import { CodeAgent, OpenAIModel, AgentTool
|
|
327
|
+
import { CodeAgent, ToolUseAgent, OpenAIModel, AgentTool } from '@samrahimi/smol-js';
|
|
151
328
|
|
|
152
|
-
// Create
|
|
329
|
+
// Create specialized worker agents
|
|
153
330
|
const mathAgent = new CodeAgent({
|
|
154
331
|
model,
|
|
155
|
-
tools: [calculatorTool],
|
|
156
332
|
maxSteps: 5,
|
|
157
|
-
verboseLevel: LogLevel.OFF, // Quiet - manager
|
|
333
|
+
verboseLevel: LogLevel.OFF, // Quiet - manager handles output
|
|
158
334
|
});
|
|
159
335
|
|
|
160
|
-
|
|
336
|
+
const researchAgent = new ToolUseAgent({
|
|
337
|
+
model,
|
|
338
|
+
tools: [searchTool],
|
|
339
|
+
maxSteps: 8,
|
|
340
|
+
verboseLevel: LogLevel.OFF,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Wrap workers as tools
|
|
161
344
|
const mathExpert = new AgentTool({
|
|
162
345
|
agent: mathAgent,
|
|
163
346
|
name: 'math_expert',
|
|
164
|
-
description: 'Delegate math
|
|
347
|
+
description: 'Delegate math and calculation tasks to this agent',
|
|
165
348
|
});
|
|
166
349
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
name: '
|
|
170
|
-
description: 'Delegate
|
|
350
|
+
const researcher = new AgentTool({
|
|
351
|
+
agent: researchAgent,
|
|
352
|
+
name: 'researcher',
|
|
353
|
+
description: 'Delegate research and information gathering to this agent',
|
|
171
354
|
});
|
|
172
355
|
|
|
173
|
-
// Create manager that uses the
|
|
174
|
-
const manager = new
|
|
356
|
+
// Create manager that uses the workers
|
|
357
|
+
const manager = new ToolUseAgent({
|
|
175
358
|
model,
|
|
176
|
-
tools: [mathExpert,
|
|
359
|
+
tools: [mathExpert, researcher],
|
|
177
360
|
maxSteps: 10,
|
|
178
361
|
});
|
|
179
362
|
|
|
180
|
-
await manager.run('Research Tokyo population and calculate water consumption');
|
|
363
|
+
await manager.run('Research Tokyo population and calculate water consumption per capita');
|
|
181
364
|
```
|
|
182
365
|
|
|
183
|
-
##
|
|
366
|
+
## Exa.ai Integration
|
|
367
|
+
|
|
368
|
+
Three tools for web research powered by Exa.ai:
|
|
184
369
|
|
|
185
|
-
|
|
370
|
+
### ExaSearchTool
|
|
371
|
+
|
|
372
|
+
Semantic search with advanced filtering:
|
|
186
373
|
|
|
187
374
|
```typescript
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
375
|
+
import { ExaSearchTool } from '@samrahimi/smol-js';
|
|
376
|
+
|
|
377
|
+
const searchTool = new ExaSearchTool({
|
|
378
|
+
apiKey: process.env.EXA_API_KEY,
|
|
379
|
+
numResults: 10,
|
|
380
|
+
searchType: 'auto', // 'auto', 'neural', or 'keyword'
|
|
193
381
|
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### ExaGetContentsTool
|
|
385
|
+
|
|
386
|
+
Extract clean webpage content:
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
import { ExaGetContentsTool } from '@samrahimi/smol-js';
|
|
194
390
|
|
|
195
|
-
|
|
391
|
+
const contentTool = new ExaGetContentsTool({
|
|
392
|
+
apiKey: process.env.EXA_API_KEY,
|
|
393
|
+
textOnly: true,
|
|
394
|
+
});
|
|
196
395
|
```
|
|
197
396
|
|
|
198
|
-
|
|
397
|
+
### ExaResearchTool
|
|
199
398
|
|
|
200
|
-
|
|
399
|
+
Agentic web research that writes comprehensive reports:
|
|
201
400
|
|
|
202
401
|
```typescript
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
402
|
+
import { ExaResearchTool } from '@samrahimi/smol-js';
|
|
403
|
+
|
|
404
|
+
const researchTool = new ExaResearchTool({
|
|
405
|
+
apiKey: process.env.EXA_API_KEY,
|
|
406
|
+
model: 'exa-research', // or 'exa-research-fast', 'exa-research-pro'
|
|
206
407
|
});
|
|
207
408
|
|
|
208
|
-
// The
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
|
|
409
|
+
// The Exa Research API is an asynchronous research agent that:
|
|
410
|
+
// 1. Plans the research approach
|
|
411
|
+
// 2. Executes searches across the web
|
|
412
|
+
// 3. Extracts and analyzes facts from sources
|
|
413
|
+
// 4. Synthesizes findings into a markdown report with citations
|
|
414
|
+
// 5. Returns the complete report (typically 20-90 seconds)
|
|
212
415
|
|
|
213
|
-
|
|
416
|
+
// Usage in agent:
|
|
417
|
+
await agent.run('Use exa_research to write a comprehensive report on quantum computing breakthroughs in 2024');
|
|
418
|
+
```
|
|
214
419
|
|
|
215
|
-
## Built-in Capabilities
|
|
420
|
+
## Built-in Capabilities (CodeAgent)
|
|
216
421
|
|
|
217
|
-
The
|
|
422
|
+
The CodeAgent sandbox includes:
|
|
218
423
|
|
|
219
424
|
| Category | Available |
|
|
220
425
|
|----------|-----------|
|
|
221
426
|
| **Output** | `console.log()`, `console.error()`, `print()` |
|
|
222
427
|
| **HTTP** | `fetch()`, `URL`, `URLSearchParams` |
|
|
223
|
-
| **File System** | `fs
|
|
224
|
-
| **Path** | `path
|
|
428
|
+
| **File System** | `fs.*` (readFileSync, writeFileSync, etc.) |
|
|
429
|
+
| **Path** | `path.*` (join, resolve, dirname, etc.) |
|
|
225
430
|
| **Data** | `JSON`, `Buffer`, `TextEncoder`, `TextDecoder` |
|
|
226
431
|
| **Math** | `Math.*`, `parseInt()`, `parseFloat()` |
|
|
227
432
|
| **Types** | `Object`, `Array`, `Map`, `Set`, `Date`, `RegExp`, `Promise` |
|
|
228
433
|
| **Timers** | `setTimeout()`, `setInterval()` |
|
|
229
434
|
| **Final** | `final_answer(value)` - Return the result |
|
|
230
435
|
|
|
436
|
+
### Dynamic npm Imports
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
const agent = new CodeAgent({
|
|
440
|
+
model,
|
|
441
|
+
additionalAuthorizedImports: ['lodash', 'dayjs', 'uuid'],
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Agent can now write:
|
|
445
|
+
// const _ = await importPackage('lodash');
|
|
446
|
+
// const result = _.uniq([1, 2, 2, 3]);
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Packages are fetched from [jsdelivr CDN](https://www.jsdelivr.com/) and cached in `~/.smol-js/packages/`.
|
|
450
|
+
|
|
231
451
|
## Examples
|
|
232
452
|
|
|
233
|
-
|
|
453
|
+
See the `examples/js/` directory for complete examples:
|
|
234
454
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
| **06-deep-research.ts** | Real API calls with DuckDuckGo/Wikipedia |
|
|
243
|
-
| **07-npm-package-import.ts** | Importing from the published npm package |
|
|
244
|
-
| **08-fetch-agent.ts** | Agent using fetch() directly (no tools) |
|
|
245
|
-
| **09-nested-agents.ts** | Manager agent delegating to worker agents |
|
|
455
|
+
- **main.ts**: Main demo with custom tools and YAML workflows
|
|
456
|
+
- **custom-tools.ts**: Custom tool implementations (TimestampTool, TextStatsTool, SlugifyTool)
|
|
457
|
+
- **agents/**: YAML workflow definitions
|
|
458
|
+
- `custom_tools.yaml`: Workflow using custom tools
|
|
459
|
+
- `bloomberg.yaml`: Bloomberg research workflow
|
|
460
|
+
- `policy.yaml`: Policy analysis workflow
|
|
461
|
+
- `simple-test.yaml`: Simple test workflow
|
|
246
462
|
|
|
247
463
|
Run an example:
|
|
248
464
|
|
|
249
465
|
```bash
|
|
250
|
-
|
|
466
|
+
cd examples/js
|
|
467
|
+
npm install
|
|
468
|
+
npx tsx main.ts
|
|
251
469
|
```
|
|
252
470
|
|
|
253
|
-
##
|
|
471
|
+
## Memory Management
|
|
254
472
|
|
|
255
|
-
|
|
473
|
+
Agents track all execution steps and manage context automatically:
|
|
256
474
|
|
|
257
475
|
```typescript
|
|
258
|
-
|
|
259
|
-
|
|
476
|
+
const agent = new CodeAgent({
|
|
477
|
+
model,
|
|
478
|
+
maxContextLength: 100000, // Token limit
|
|
479
|
+
memoryStrategy: 'truncate', // or 'compact'
|
|
480
|
+
persistent: false, // Retain memory between run() calls
|
|
481
|
+
});
|
|
260
482
|
|
|
261
|
-
|
|
262
|
-
|
|
483
|
+
// Non-persistent (default): Fresh memory each run
|
|
484
|
+
await agent.run('Task 1');
|
|
485
|
+
await agent.run('Task 2'); // Doesn't remember Task 1
|
|
263
486
|
|
|
264
|
-
|
|
487
|
+
// Persistent: Maintains conversation context
|
|
488
|
+
const persistentAgent = new CodeAgent({ model, persistent: true });
|
|
489
|
+
await persistentAgent.run('Remember this: X = 42');
|
|
490
|
+
await persistentAgent.run('What is X?'); // Remembers X = 42
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
**Memory Strategies:**
|
|
494
|
+
- **truncate**: Removes oldest steps when over token limit
|
|
495
|
+
- **compact**: Uses LLM to summarize older steps
|
|
496
|
+
|
|
497
|
+
## Session Logging
|
|
498
|
+
|
|
499
|
+
All sessions are logged to `~/.smol-js/`:
|
|
500
|
+
- `session-<timestamp>.log` - Full session transcript with color codes
|
|
501
|
+
- `packages/` - Cached npm packages from dynamic imports
|
|
502
|
+
|
|
503
|
+
## API Reference
|
|
504
|
+
|
|
505
|
+
### Agent Base Class
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
abstract class Agent {
|
|
509
|
+
constructor(config: AgentConfig)
|
|
510
|
+
run(task: string, reset?: boolean): Promise<RunResult>
|
|
265
511
|
stop(): void
|
|
266
512
|
reset(): void
|
|
267
|
-
|
|
268
|
-
// Tools
|
|
269
513
|
addTool(tool: Tool): void
|
|
270
514
|
removeTool(name: string): boolean
|
|
271
|
-
getTools(): Map<string, Tool>
|
|
272
|
-
|
|
273
|
-
// State
|
|
274
515
|
getMemory(): AgentMemory
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### CodeAgent
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
class CodeAgent extends Agent {
|
|
523
|
+
constructor(config: CodeAgentConfig)
|
|
275
524
|
getExecutor(): LocalExecutor
|
|
276
525
|
}
|
|
277
526
|
```
|
|
278
527
|
|
|
528
|
+
### ToolUseAgent
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
class ToolUseAgent extends Agent {
|
|
532
|
+
constructor(config: ToolUseAgentConfig)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
interface ToolUseAgentConfig extends AgentConfig {
|
|
536
|
+
enableParallelToolCalls?: boolean; // Execute independent tools in parallel
|
|
537
|
+
}
|
|
538
|
+
```
|
|
539
|
+
|
|
279
540
|
### RunResult
|
|
280
541
|
|
|
281
542
|
```typescript
|
|
@@ -298,68 +559,60 @@ abstract class Tool {
|
|
|
298
559
|
|
|
299
560
|
abstract execute(args: Record<string, unknown>): Promise<unknown>;
|
|
300
561
|
|
|
301
|
-
setup(): Promise<void>;
|
|
562
|
+
setup(): Promise<void>;
|
|
302
563
|
call(args: Record<string, unknown>): Promise<unknown>;
|
|
303
|
-
toCodePrompt(): string; //
|
|
564
|
+
toCodePrompt(): string; // For CodeAgent
|
|
565
|
+
toOpenAITool(): OpenAITool; // For ToolUseAgent
|
|
304
566
|
}
|
|
305
567
|
```
|
|
306
568
|
|
|
307
|
-
###
|
|
569
|
+
### Orchestrator
|
|
308
570
|
|
|
309
571
|
```typescript
|
|
310
|
-
class
|
|
311
|
-
constructor(config
|
|
572
|
+
class Orchestrator {
|
|
573
|
+
constructor(config?: { verbose?: boolean })
|
|
574
|
+
|
|
575
|
+
loadWorkflow(filePath: string): Workflow
|
|
576
|
+
loadWorkflowFromString(yaml: string): Workflow
|
|
577
|
+
runWorkflow(workflow: Workflow, task: string): Promise<void>
|
|
578
|
+
runAgent(agent: Agent, task: string): Promise<void>
|
|
579
|
+
getEventLog(): OrchestrationEvent[]
|
|
312
580
|
}
|
|
313
|
-
|
|
314
|
-
interface AgentToolConfig {
|
|
315
|
-
agent: Agent; // The agent to wrap
|
|
316
|
-
name?: string; // Tool name (default: 'managed_agent')
|
|
317
|
-
description?: string; // Tool description
|
|
318
|
-
additionalContext?: string; // Extra context for the agent
|
|
319
|
-
returnFullResult?: boolean; // Return full result vs just output
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Helper function
|
|
323
|
-
function agentAsTool(agent: Agent, options?: Omit<AgentToolConfig, 'agent'>): AgentTool
|
|
324
581
|
```
|
|
325
582
|
|
|
326
|
-
###
|
|
583
|
+
### YAMLLoader
|
|
327
584
|
|
|
328
585
|
```typescript
|
|
329
|
-
class
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
sendTools(tools: Record<string, Tool>): void
|
|
334
|
-
sendVariables(variables: Record<string, unknown>): void
|
|
335
|
-
reset(): void
|
|
336
|
-
getState(): Record<string, unknown>
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
interface ExecutorConfig {
|
|
340
|
-
timeout?: number; // Execution timeout (default: 30000ms)
|
|
341
|
-
authorizedImports?: string[]; // Allowed npm packages
|
|
342
|
-
allowFs?: boolean; // Enable fs access (default: true)
|
|
343
|
-
workingDirectory?: string; // Working dir for fs operations
|
|
586
|
+
class YAMLLoader {
|
|
587
|
+
registerToolType(typeName: string, toolClass: typeof Tool): void
|
|
588
|
+
loadFromFile(filePath: string): Workflow
|
|
589
|
+
loadFromString(yaml: string): Workflow
|
|
344
590
|
}
|
|
345
591
|
```
|
|
346
592
|
|
|
347
|
-
|
|
593
|
+
## CLI Reference
|
|
348
594
|
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
595
|
+
```bash
|
|
596
|
+
# Run a workflow
|
|
597
|
+
npx @samrahimi/smol-js <workflow.yaml> [options]
|
|
598
|
+
npx @samrahimi/smol-js run <workflow.yaml> [options]
|
|
599
|
+
|
|
600
|
+
# Validate a workflow
|
|
601
|
+
npx @samrahimi/smol-js validate <workflow.yaml>
|
|
602
|
+
|
|
603
|
+
# Options
|
|
604
|
+
--task, -t <task> Task description (prompted if not provided)
|
|
605
|
+
--quiet, -q Reduce output verbosity
|
|
606
|
+
--help, -h Show help message
|
|
356
607
|
```
|
|
357
608
|
|
|
358
|
-
##
|
|
609
|
+
## Security Considerations
|
|
359
610
|
|
|
360
|
-
|
|
361
|
-
-
|
|
362
|
-
-
|
|
611
|
+
- **Sandboxed Execution**: Code runs in Node's vm module, isolated from the main process
|
|
612
|
+
- **Authorized Imports**: Only explicitly allowed npm packages can be imported
|
|
613
|
+
- **File System Isolation**: fs operations are restricted to configured working directory
|
|
614
|
+
- **Execution Delay**: Configurable delay before code execution allows user interruption (Ctrl+C)
|
|
615
|
+
- **Timeout Protection**: Code execution has a configurable timeout (default: 30s)
|
|
363
616
|
|
|
364
617
|
## Comparison with Python smolagents
|
|
365
618
|
|
|
@@ -371,33 +624,33 @@ All sessions are logged to `~/.smol-js/`:
|
|
|
371
624
|
| Nested agents | `ManagedAgent` | `AgentTool` |
|
|
372
625
|
| Async support | Optional | All tools are async |
|
|
373
626
|
| HTTP requests | Requires tool | Built-in `fetch()` |
|
|
374
|
-
| Remote executors | E2B, Docker, etc. | Local only
|
|
375
|
-
| Agent types | CodeAgent, ToolCallingAgent | CodeAgent
|
|
376
|
-
|
|
|
377
|
-
|
|
378
|
-
## Security Considerations
|
|
379
|
-
|
|
380
|
-
- **Sandboxed Execution**: Code runs in Node's vm module, isolated from the main process
|
|
381
|
-
- **Authorized Imports**: Only explicitly allowed npm packages can be imported
|
|
382
|
-
- **File System Isolation**: fs operations are restricted to the configured working directory
|
|
383
|
-
- **Execution Delay**: Configurable delay before code execution allows user interruption (Ctrl+C)
|
|
384
|
-
- **Timeout Protection**: Code execution has a configurable timeout (default: 30s)
|
|
627
|
+
| Remote executors | E2B, Docker, etc. | Local only |
|
|
628
|
+
| Agent types | CodeAgent, ToolCallingAgent | CodeAgent, ToolUseAgent |
|
|
629
|
+
| YAML workflows | ❌ | ✅ |
|
|
630
|
+
| Exa.ai integration | ❌ | ✅ Built-in |
|
|
385
631
|
|
|
386
632
|
## Contributing
|
|
387
633
|
|
|
388
|
-
Contributions are welcome! Please open an issue or PR on GitHub.
|
|
634
|
+
Contributions are welcome! Please follow OOP principles and open an issue or PR on GitHub.
|
|
389
635
|
|
|
390
636
|
```bash
|
|
391
637
|
# Clone and install
|
|
392
|
-
git clone https://github.com/samrahimi/
|
|
393
|
-
cd smol-js
|
|
638
|
+
git clone https://github.com/samrahimi/smolagents
|
|
639
|
+
cd smolagents/smol-js
|
|
394
640
|
npm install
|
|
395
641
|
|
|
642
|
+
# Build
|
|
643
|
+
npm run build
|
|
644
|
+
|
|
396
645
|
# Run tests
|
|
397
646
|
npm test
|
|
398
647
|
|
|
399
|
-
#
|
|
400
|
-
|
|
648
|
+
# Lint
|
|
649
|
+
npm run lint
|
|
650
|
+
npm run lint:fix
|
|
651
|
+
|
|
652
|
+
# Type check
|
|
653
|
+
npm run typecheck
|
|
401
654
|
```
|
|
402
655
|
|
|
403
656
|
## License
|
|
@@ -406,4 +659,4 @@ MIT
|
|
|
406
659
|
|
|
407
660
|
## Credits
|
|
408
661
|
|
|
409
|
-
This is a TypeScript
|
|
662
|
+
This is a TypeScript framework inspired by [smolagents](https://github.com/huggingface/smolagents) by Hugging Face, with additional features including YAML orchestration, ToolUseAgent, and Exa.ai integration.
|