@samrahimi/smol-js 0.6.4 → 0.7.0

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 CHANGED
@@ -1,24 +1,27 @@
1
1
  # smol-js
2
2
 
3
- **A TypeScript port of the [smolagents](https://github.com/huggingface/smolagents) agentic framework.**
3
+ **A TypeScript agentic framework inspired by [smolagents](https://github.com/huggingface/smolagents).**
4
4
 
5
- Build AI agents that solve tasks by writing and executing JavaScript code. The agent reasons about problems, generates code, executes it in a sandbox, observes results, and iterates until it finds the answer.
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
  [![npm version](https://img.shields.io/npm/v/@samrahimi/smol-js.svg)](https://www.npmjs.com/package/@samrahimi/smol-js)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
 
10
10
  ## Features
11
11
 
12
- - **ReAct Framework**: Reasoning + Acting loop (Thought → Code → Observation → repeat)
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**: Extensible tools that agents can call as functions
15
- - **Nested Agents**: Use agents as tools for hierarchical task delegation
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 (OpenRouter by default)
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
- # Or for OpenAI directly
60
- OPENAI_API_KEY=sk-your-openai-key
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 (default: OpenRouter)
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 (OFF, ERROR, INFO, DEBUG)
181
+ verboseLevel: LogLevel.INFO, // Logging level
86
182
  streamOutputs: true, // Stream LLM output in real-time
87
- additionalAuthorizedImports: ['lodash'], // npm packages the agent can import
88
- workingDirectory: '/path/to/dir', // Working dir for fs operations
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
- ## Creating Tools
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
- Tools extend the agent's capabilities. The agent sees tools as async functions it can call.
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
- ### Functional Tools
236
+ ### Registering Tools for YAML Workflows
128
237
 
129
238
  ```typescript
130
- import { createTool } from '@samrahimi/smol-js';
131
-
132
- const calculator = createTool({
133
- name: 'calculate',
134
- description: 'Evaluate a math expression',
135
- inputs: {
136
- expression: { type: 'string', description: 'Math expression to evaluate', required: true },
137
- },
138
- outputType: 'number',
139
- execute: async (args) => {
140
- return new Function('Math', `return ${args.expression}`)(Math);
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
- ## Nested Agents (Agent as Tool)
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
- Use agents as tools for hierarchical task delegation. A "manager" agent can delegate specialized tasks to "worker" agents.
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, agentAsTool } from '@samrahimi/smol-js';
327
+ import { CodeAgent, ToolUseAgent, OpenAIModel, AgentTool } from '@samrahimi/smol-js';
151
328
 
152
- // Create a specialized worker agent
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 reports results
333
+ verboseLevel: LogLevel.OFF, // Quiet - manager handles output
158
334
  });
159
335
 
160
- // Wrap it as a tool
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 problems to a specialized math agent',
347
+ description: 'Delegate math and calculation tasks to this agent',
165
348
  });
166
349
 
167
- // Or use the helper function
168
- const mathExpert = agentAsTool(mathAgent, {
169
- name: 'math_expert',
170
- description: 'Delegate math problems to a specialized math agent',
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 worker
174
- const manager = new CodeAgent({
356
+ // Create manager that uses the workers
357
+ const manager = new ToolUseAgent({
175
358
  model,
176
- tools: [mathExpert, researchExpert], // Agents as tools!
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
- ## Using fetch() Directly
366
+ ## Exa.ai Integration
367
+
368
+ Three tools for web research powered by Exa.ai:
184
369
 
185
- Agents can make HTTP requests directly in their code without needing a tool:
370
+ ### ExaSearchTool
371
+
372
+ Semantic search with advanced filtering:
186
373
 
187
374
  ```typescript
188
- const agent = new CodeAgent({
189
- model,
190
- tools: [], // No tools needed!
191
- customInstructions: `You can use fetch() directly to make HTTP requests.
192
- Example: const data = await fetch('https://api.example.com').then(r => r.json());`,
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
- await agent.run('Fetch users from https://jsonplaceholder.typicode.com/users');
391
+ const contentTool = new ExaGetContentsTool({
392
+ apiKey: process.env.EXA_API_KEY,
393
+ textOnly: true,
394
+ });
196
395
  ```
197
396
 
198
- ## Dynamic npm Imports
397
+ ### ExaResearchTool
199
398
 
200
- The agent can import npm packages dynamically:
399
+ Agentic web research that writes comprehensive reports:
201
400
 
202
401
  ```typescript
203
- const agent = new CodeAgent({
204
- model,
205
- additionalAuthorizedImports: ['lodash', 'dayjs', 'uuid'],
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 agent can now write:
209
- // const _ = await importPackage('lodash');
210
- // const dayjs = await importPackage('dayjs');
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
- Packages are fetched from [jsdelivr CDN](https://www.jsdelivr.com/) and cached locally in `~/.smol-js/packages/`.
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 agent's sandbox includes:
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.readFileSync()`, `fs.writeFileSync()`, `fs.existsSync()`, etc. |
224
- | **Path** | `path.join()`, `path.resolve()`, `path.dirname()`, etc. |
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
- The `examples/` folder contains complete, runnable examples:
453
+ See the `examples/js/` directory for complete examples:
234
454
 
235
- | Example | Description |
236
- |---------|-------------|
237
- | **01-simple-math.ts** | Basic calculation task |
238
- | **02-dynamic-imports.ts** | Using npm packages dynamically |
239
- | **03-variable-persistence.ts** | Multi-step state management |
240
- | **04-research-with-tools.ts** | Custom tools for research tasks |
241
- | **05-error-recovery.ts** | Handling and recovering from errors |
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
- npx tsx examples/08-fetch-agent.ts
466
+ cd examples/js
467
+ npm install
468
+ npx tsx main.ts
251
469
  ```
252
470
 
253
- ## API Reference
471
+ ## Memory Management
254
472
 
255
- ### CodeAgent
473
+ Agents track all execution steps and manage context automatically:
256
474
 
257
475
  ```typescript
258
- class CodeAgent {
259
- constructor(config: CodeAgentConfig)
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
- // Run a task
262
- run(task: string, reset?: boolean): Promise<RunResult>
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
- // Control
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>; // Optional async initialization
562
+ setup(): Promise<void>;
302
563
  call(args: Record<string, unknown>): Promise<unknown>;
303
- toCodePrompt(): string; // Generate function signature for prompt
564
+ toCodePrompt(): string; // For CodeAgent
565
+ toOpenAITool(): OpenAITool; // For ToolUseAgent
304
566
  }
305
567
  ```
306
568
 
307
- ### AgentTool
569
+ ### Orchestrator
308
570
 
309
571
  ```typescript
310
- class AgentTool extends Tool {
311
- constructor(config: AgentToolConfig)
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
- ### LocalExecutor
583
+ ### YAMLLoader
327
584
 
328
585
  ```typescript
329
- class LocalExecutor {
330
- constructor(config?: ExecutorConfig)
331
-
332
- execute(code: string): Promise<CodeExecutionOutput>
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
- ### LogLevel
593
+ ## CLI Reference
348
594
 
349
- ```typescript
350
- enum LogLevel {
351
- OFF = 0, // No output
352
- ERROR = 1, // Errors only
353
- INFO = 2, // Normal output (default)
354
- DEBUG = 3, // Detailed debugging
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
- ## Session Logging
609
+ ## Security Considerations
359
610
 
360
- All sessions are logged to `~/.smol-js/`:
361
- - `session-<timestamp>.log` - Full session transcript
362
- - `packages/` - Cached npm packages
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 (for now) |
375
- | Agent types | CodeAgent, ToolCallingAgent | CodeAgent only |
376
- | Multi-agent | Yes | Yes (via AgentTool) |
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/smol-js
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
- # Run examples
400
- npx tsx examples/01-simple-math.ts
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 port of [smolagents](https://github.com/huggingface/smolagents) by Hugging Face.
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.