@samrahimi/smol-js 0.7.1 → 0.7.3

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
@@ -2,22 +2,23 @@
2
2
 
3
3
  **A TypeScript agentic framework inspired by [smolagents](https://github.com/huggingface/smolagents).**
4
4
 
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.
5
+ Build AI agents that solve tasks autonomously using the ReAct (Reasoning + Acting) pattern. Agents can write and execute JavaScript code, call tools, run shell commands, 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
- - **Two Agent Types**:
13
- - `CodeAgent` - Writes JavaScript code to solve tasks
14
- - `ToolUseAgent` - Uses native LLM function calling (OpenAI-style)
12
+ - **Three Agent Types**:
13
+ - `CodeAgent` Writes and executes JavaScript code in a sandboxed VM
14
+ - `ToolUseAgent` Uses native LLM function calling (OpenAI-style)
15
+ - `TerminalAgent` — Executes shell commands on your macOS terminal
15
16
  - **YAML Orchestration**: Define complex agent workflows declaratively
16
- - **Sandboxed Execution**: JavaScript runs in Node's vm module with state persistence
17
- - **Extensible Tool System**: Built-in tools + easy custom tool creation
17
+ - **Custom Tool Plugins**: Drop standalone `.ts` tool files into a folder — no build step, no config
18
18
  - **Nested Agents**: Manager-worker patterns for hierarchical task delegation
19
+ - **Sandboxed Execution**: JavaScript runs in Node's vm module with state persistence
19
20
  - **Exa.ai Integration**: Semantic web search, content extraction, and research automation
20
- - **Dynamic Imports**: Import npm packages on-the-fly via jsdelivr CDN
21
+ - **Dynamic Imports**: Import npm packages on-the-fly in CodeAgent
21
22
  - **OpenAI-Compatible**: Works with OpenRouter, OpenAI, Azure, Anthropic, and local servers
22
23
  - **Streaming**: Real-time output streaming from the LLM
23
24
  - **Memory Management**: Context-aware with truncate/compact strategies
@@ -29,6 +30,12 @@ Build AI agents that solve tasks autonomously using the ReAct (Reasoning + Actin
29
30
  npm install @samrahimi/smol-js
30
31
  ```
31
32
 
33
+ Or run workflows directly without installing:
34
+
35
+ ```bash
36
+ npx @samrahimi/smol-js workflow.yaml --task "Your task here"
37
+ ```
38
+
32
39
  ## Quick Start
33
40
 
34
41
  ### Via CLI (YAML Workflows)
@@ -101,6 +108,8 @@ const result = await agent.run('Calculate the first 10 prime numbers');
101
108
  console.log(result.output); // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
102
109
  ```
103
110
 
111
+ ---
112
+
104
113
  ## Agent Types
105
114
 
106
115
  ### CodeAgent
@@ -127,7 +136,7 @@ await agent.run('Analyze the file data.csv and create a summary');
127
136
 
128
137
  ### ToolUseAgent
129
138
 
130
- Uses native LLM function calling (OpenAI-style tool calling). Better for LLMs with strong tool-calling capabilities.
139
+ Uses native LLM function calling (OpenAI-style tool calling). Best for LLMs with strong structured-output capabilities.
131
140
 
132
141
  ```typescript
133
142
  import { ToolUseAgent, OpenAIModel } from '@samrahimi/smol-js';
@@ -142,6 +151,258 @@ const agent = new ToolUseAgent({
142
151
  await agent.run('Search for recent AI papers and summarize the top 3');
143
152
  ```
144
153
 
154
+ ### TerminalAgent
155
+
156
+ Accomplishes tasks by reasoning about and executing shell commands on your terminal. Tuned for macOS — uses zsh, understands BSD conventions, and gives you full visibility into what it's doing.
157
+
158
+ ```typescript
159
+ import { TerminalAgent, OpenAIModel } from '@samrahimi/smol-js';
160
+
161
+ const agent = new TerminalAgent({
162
+ model,
163
+ maxSteps: 10,
164
+ commandDelay: 5, // seconds before running commands (Ctrl+C window)
165
+ maxOutputLength: 8000, // chars of command output fed back to the LLM
166
+ });
167
+
168
+ await agent.run('Set up a new Node.js project with TypeScript and Jest');
169
+ ```
170
+
171
+ **How it works:**
172
+ 1. Agent reasons about what shell commands to run
173
+ 2. Commands are displayed for your review (with a configurable delay — default 5 seconds — so you can Ctrl+C if anything looks wrong)
174
+ 3. Commands execute sequentially via `/bin/zsh`
175
+ 4. stdout, stderr, and exit codes are captured and fed back as observations
176
+ 5. Repeats until the agent signals completion with `FINAL_ANSWER:`
177
+
178
+ **Key behaviours:**
179
+ - **Verbose by default.** You see the agent's reasoning, pending commands, and live output at every step.
180
+ - **Safety delay.** Every command batch pauses for 5 seconds before execution. Read what's about to run. Press Ctrl+C to abort.
181
+ - **Error recovery.** If a command fails (non-zero exit code), the agent sees the error and tries a different approach.
182
+ - **No user-assigned tools.** TerminalAgent is a pure shell agent. It can only delegate to sub-agents (via the manager-worker pattern) — it doesn't use function-calling tools.
183
+
184
+ #### TerminalAgent in YAML
185
+
186
+ ```yaml
187
+ name: system-inspector
188
+ description: Gathers system information using shell commands.
189
+
190
+ model:
191
+ modelId: anthropic/claude-sonnet-4.5
192
+ baseUrl: https://openrouter.ai/api/v1
193
+
194
+ agents:
195
+ inspector:
196
+ type: TerminalAgent
197
+ maxSteps: 5
198
+ commandDelay: 3
199
+ customInstructions: >
200
+ Gather system information: OS version, CPU, RAM, disk usage,
201
+ and list running processes sorted by CPU. Summarize your findings.
202
+
203
+ entrypoint: inspector
204
+ ```
205
+
206
+ Run it:
207
+
208
+ ```bash
209
+ npx @samrahimi/smol-js system-inspector.yaml --task "What are my system specs?"
210
+ ```
211
+
212
+ #### TerminalAgent as a Sub-Agent (Manager-Worker)
213
+
214
+ One of the most powerful patterns: a ToolUseAgent manager that delegates shell tasks to a TerminalAgent while handling other work itself.
215
+
216
+ ```yaml
217
+ name: manager-demo
218
+ description: >
219
+ A ToolUseAgent manager orchestrates a TerminalAgent (shell commands)
220
+ and a ToolUseAgent file reader. The manager delegates and synthesizes.
221
+
222
+ model:
223
+ modelId: anthropic/claude-sonnet-4.5
224
+ baseUrl: https://openrouter.ai/api/v1
225
+
226
+ tools:
227
+ read:
228
+ type: read_file
229
+
230
+ agents:
231
+ terminal_worker:
232
+ type: TerminalAgent
233
+ description: Runs shell commands to gather system information.
234
+ maxSteps: 3
235
+ customInstructions: >
236
+ Gather the requested system information by running shell commands.
237
+ When you have everything, call final_answer with a clear summary.
238
+
239
+ file_worker:
240
+ type: ToolUseAgent
241
+ description: Reads files from the project and summarizes their contents.
242
+ tools:
243
+ - read
244
+ maxSteps: 3
245
+ customInstructions: >
246
+ Read the file(s) you are asked about and return a concise summary
247
+ of the relevant details.
248
+
249
+ manager:
250
+ type: ToolUseAgent
251
+ description: >
252
+ Delegates to terminal_worker for shell tasks and file_worker for
253
+ file reads, then synthesizes the results.
254
+ agents:
255
+ - terminal_worker
256
+ - file_worker
257
+ maxSteps: 5
258
+ customInstructions: >
259
+ You are a manager agent. You have no tools of your own — your job
260
+ is to delegate to your sub-agents and combine their results.
261
+ - terminal_worker: use for anything that needs shell commands or live system state
262
+ - file_worker: use for reading files on disk
263
+ Delegate both tasks in parallel if possible, then synthesize a final answer.
264
+
265
+ entrypoint: manager
266
+ ```
267
+
268
+ Run it:
269
+
270
+ ```bash
271
+ npx @samrahimi/smol-js examples/js/agents/manager-demo.yaml \
272
+ --task "Tell me my macOS version and summarize the smol-js README"
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Custom Tool Plugins
278
+
279
+ The custom tool system lets you write standalone tool files that any agent can use — without modifying the framework or writing boilerplate. Drop a `.ts` file into a folder, point the CLI at it, and it just works.
280
+
281
+ ### How It Works
282
+
283
+ 1. You write a single `.ts` file that exports `TOOL_METADATA` and an `execute()` function
284
+ 2. You tell the CLI where to find your tools: `--custom-tools-folder ./my-tools`
285
+ 3. At startup, smol-js scans the folder, discovers your tools, and makes them available in YAML workflows
286
+ 4. When an agent calls your tool, smol-js spawns an isolated [Bun](https://bun.sh) process to run it
287
+
288
+ The tool file is **transport-agnostic**. It has zero knowledge of how it's invoked. All the process management, argument passing, and result serialization is handled by a harness adapter that ships with the package.
289
+
290
+ ### Writing a Custom Tool
291
+
292
+ A custom tool is a single `.ts` file. Here's a complete example — `WeatherLookup.ts`:
293
+
294
+ ```typescript
295
+ /**
296
+ * WeatherLookup — fetches weather data from Open-Meteo API.
297
+ *
298
+ * This file exports two things and nothing else:
299
+ * 1. TOOL_METADATA — describes the tool to the smol-js scanner
300
+ * 2. execute(args) — the actual function; called by the toolHarness adapter
301
+ *
302
+ * It has zero knowledge of how it is invoked. The harness handles argument
303
+ * deserialization, protocol framing, and process lifecycle.
304
+ *
305
+ * Dependencies are resolved by Bun at runtime — no package.json or
306
+ * npm install needed.
307
+ */
308
+
309
+ import chalk from 'chalk'; // Bun resolves this from npm automatically
310
+ import dayjs from 'dayjs'; // Same here — zero config
311
+
312
+ // TOOL_METADATA — parsed by the scanner at discovery time.
313
+ // The `name` field MUST match this file's basename (WeatherLookup).
314
+ export const TOOL_METADATA = {
315
+ name: 'WeatherLookup',
316
+ description: 'Fetches current weather for a given city using the Open-Meteo API.',
317
+ inputs: {
318
+ city: {
319
+ type: 'string',
320
+ description: 'The city to look up (e.g. "London", "Tokyo")',
321
+ required: true,
322
+ },
323
+ units: {
324
+ type: 'string',
325
+ description: 'Temperature units: "celsius" (default) or "fahrenheit"',
326
+ required: false,
327
+ default: 'celsius',
328
+ },
329
+ },
330
+ outputType: 'string',
331
+ };
332
+
333
+ // execute — the tool's entry point. Just a function.
334
+ // args contains the deserialized parameters passed by the agent.
335
+ // Return your result. Throw an Error if something goes wrong.
336
+ // console.log() calls are streamed back as output the agent can see.
337
+ export async function execute(args: Record<string, unknown>): Promise<string> {
338
+ const city = args.city as string;
339
+ console.log(chalk.dim(` Geocoding "${city}"...`));
340
+
341
+ // ... fetch weather data ...
342
+
343
+ return `Weather in ${city}: 22°C, Partly cloudy`;
344
+ }
345
+ ```
346
+
347
+ ### The Rules
348
+
349
+ 1. **File name must match `TOOL_METADATA.name`** — if the metadata says `WeatherLookup`, the file must be `WeatherLookup.ts`
350
+ 2. **Export exactly two things**: `TOOL_METADATA` and `execute()`
351
+ 3. **Dependencies are free** — Bun resolves npm packages natively. Just `import` them. No `package.json`, no `npm install`.
352
+ 4. **Don't add a `main()` function.** Don't read `process.argv`. Don't write `[TOOL_RESULT]` lines. The framework's harness handles all of that.
353
+ 5. **`execute` must be async** and return a `Promise`
354
+ 6. **`console.log()` works** — output is streamed back and visible to the agent as context
355
+
356
+ ### Using Custom Tools in a Workflow
357
+
358
+ Reference your tool by its metadata name in the `tools` section:
359
+
360
+ ```yaml
361
+ name: weather-assistant
362
+ description: A helpful weather assistant.
363
+
364
+ model:
365
+ modelId: anthropic/claude-haiku-4.5
366
+ baseUrl: https://openrouter.ai/api/v1
367
+
368
+ tools:
369
+ WeatherLookup:
370
+ type: WeatherLookup # Must match TOOL_METADATA.name
371
+
372
+ agents:
373
+ assistant:
374
+ type: ToolUseAgent
375
+ tools:
376
+ - WeatherLookup
377
+ maxSteps: 5
378
+ customInstructions: >
379
+ You are a friendly weather assistant. Use WeatherLookup to get
380
+ current conditions. Present results conversationally.
381
+
382
+ entrypoint: assistant
383
+ ```
384
+
385
+ Run it:
386
+
387
+ ```bash
388
+ npx @samrahimi/smol-js weather-assistant.yaml \
389
+ --task "What's the weather in Tokyo?" \
390
+ --custom-tools-folder ./custom-tools
391
+ ```
392
+
393
+ ### Tool-Maker Agent
394
+
395
+ If you'd rather have an AI write your custom tools, there's a tool-maker agent in the examples:
396
+
397
+ ```bash
398
+ npx @samrahimi/smol-js examples/js/agents/tool-maker/tool-maker.yaml \
399
+ --task "Create a tool that converts currencies using the ExchangeRate API"
400
+ ```
401
+
402
+ The tool-maker reads the WeatherLookup reference, understands the contract, generates a new standalone tool file, creates a matching YAML workflow, and outputs a ready-to-run `npx` command. Drop the output into any `--custom-tools-folder` and it works.
403
+
404
+ ---
405
+
145
406
  ## Configuration
146
407
 
147
408
  ### Environment Variables
@@ -183,11 +444,25 @@ const agent = new CodeAgent({
183
444
  persistent: false, // Retain memory between run() calls
184
445
  maxContextLength: 100000, // Token limit for context
185
446
  memoryStrategy: 'truncate', // 'truncate' or 'compact'
186
- additionalAuthorizedImports: ['lodash'], // npm packages (CodeAgent only)
187
- workingDirectory: '/path/to/dir', // Working dir for fs operations
447
+ additionalAuthorizedImports: ['lodash'], // npm packages (CodeAgent only)
448
+ workingDirectory: '/path/to/dir', // Working dir for fs operations
449
+ });
450
+ ```
451
+
452
+ ### TerminalAgent Configuration
453
+
454
+ ```typescript
455
+ const agent = new TerminalAgent({
456
+ model,
457
+ maxSteps: 10,
458
+ commandDelay: 5, // Seconds before executing commands (default: 5)
459
+ maxOutputLength: 8000, // Max chars of output fed back per command (default: 8000)
460
+ customInstructions: 'Focus on Python tooling only.',
188
461
  });
189
462
  ```
190
463
 
464
+ ---
465
+
191
466
  ## Built-in Tools
192
467
 
193
468
  - **FinalAnswerTool**: Return the final result (always available)
@@ -200,9 +475,9 @@ const agent = new CodeAgent({
200
475
  - **ExaResearchTool**: Multi-step research workflow
201
476
  - **AgentTool**: Wrap agents as tools for nested architectures
202
477
 
203
- ## Creating Custom Tools
478
+ ## Creating Custom Tools (Class-Based)
204
479
 
205
- ### Class-Based Tools
480
+ For tools that need to live inside your TypeScript project (rather than as standalone plugin files), extend the `Tool` class:
206
481
 
207
482
  ```typescript
208
483
  import { Tool } from '@samrahimi/smol-js';
@@ -256,6 +531,8 @@ const orchestrator = new Orchestrator();
256
531
  await orchestrator.runWorkflow(workflow, 'Your task here');
257
532
  ```
258
533
 
534
+ ---
535
+
259
536
  ## YAML Workflow System
260
537
 
261
538
  Define complex agent architectures declaratively:
@@ -282,7 +559,7 @@ tools:
282
559
  type: write_file
283
560
 
284
561
  agents:
285
- # Worker agent: specialized in research
562
+ # Worker: specialized in research
286
563
  researcher:
287
564
  type: ToolUseAgent
288
565
  tools:
@@ -290,25 +567,32 @@ agents:
290
567
  - read
291
568
  maxSteps: 8
292
569
  temperature: 0.3
293
- customInstructions: "You are a research specialist. Be thorough and cite sources."
570
+ customInstructions: "Be thorough and cite sources."
294
571
 
295
- # Worker agent: specialized in writing
572
+ # Worker: specialized in writing
296
573
  writer:
297
574
  type: CodeAgent
298
575
  tools:
299
576
  - write
300
577
  maxSteps: 5
301
578
  temperature: 0.7
302
- customInstructions: "You are a skilled technical writer. Create clear, engaging content."
579
+ customInstructions: "Create clear, engaging content."
580
+
581
+ # Worker: runs shell commands
582
+ sysadmin:
583
+ type: TerminalAgent
584
+ maxSteps: 5
585
+ customInstructions: "Handle any system or environment setup tasks."
303
586
 
304
- # Manager agent: delegates to workers
587
+ # Manager: delegates to all three workers
305
588
  manager:
306
589
  type: ToolUseAgent
307
590
  agents:
308
- - researcher # Available as a tool
309
- - writer # Available as a tool
591
+ - researcher
592
+ - writer
593
+ - sysadmin
310
594
  maxSteps: 10
311
- customInstructions: "You coordinate research and writing tasks. Delegate appropriately."
595
+ customInstructions: "Coordinate research, writing, and system tasks. Delegate appropriately."
312
596
 
313
597
  entrypoint: manager
314
598
  ```
@@ -319,24 +603,26 @@ Run it:
319
603
  npx @samrahimi/smol-js research-workflow.yaml --task "Write a report on quantum computing"
320
604
  ```
321
605
 
606
+ ---
607
+
322
608
  ## Nested Agents (Manager-Worker Pattern)
323
609
 
324
610
  Use agents as tools for hierarchical task delegation:
325
611
 
326
612
  ```typescript
327
- import { CodeAgent, ToolUseAgent, OpenAIModel, AgentTool } from '@samrahimi/smol-js';
613
+ import { CodeAgent, ToolUseAgent, TerminalAgent, OpenAIModel, AgentTool } from '@samrahimi/smol-js';
328
614
 
329
615
  // Create specialized worker agents
330
616
  const mathAgent = new CodeAgent({
331
617
  model,
332
618
  maxSteps: 5,
333
- verboseLevel: LogLevel.OFF, // Quiet - manager handles output
619
+ verboseLevel: LogLevel.OFF,
334
620
  });
335
621
 
336
- const researchAgent = new ToolUseAgent({
622
+ const sysAgent = new TerminalAgent({
337
623
  model,
338
- tools: [searchTool],
339
- maxSteps: 8,
624
+ maxSteps: 5,
625
+ commandDelay: 3,
340
626
  verboseLevel: LogLevel.OFF,
341
627
  });
342
628
 
@@ -344,25 +630,27 @@ const researchAgent = new ToolUseAgent({
344
630
  const mathExpert = new AgentTool({
345
631
  agent: mathAgent,
346
632
  name: 'math_expert',
347
- description: 'Delegate math and calculation tasks to this agent',
633
+ description: 'Delegate math and calculation tasks',
348
634
  });
349
635
 
350
- const researcher = new AgentTool({
351
- agent: researchAgent,
352
- name: 'researcher',
353
- description: 'Delegate research and information gathering to this agent',
636
+ const sysAdmin = new AgentTool({
637
+ agent: sysAgent,
638
+ name: 'sys_admin',
639
+ description: 'Delegate shell commands and system tasks',
354
640
  });
355
641
 
356
- // Create manager that uses the workers
642
+ // Manager delegates to workers
357
643
  const manager = new ToolUseAgent({
358
644
  model,
359
- tools: [mathExpert, researcher],
645
+ tools: [mathExpert, sysAdmin],
360
646
  maxSteps: 10,
361
647
  });
362
648
 
363
- await manager.run('Research Tokyo population and calculate water consumption per capita');
649
+ await manager.run('Check disk usage and calculate how many GB are free as a percentage');
364
650
  ```
365
651
 
652
+ ---
653
+
366
654
  ## Exa.ai Integration
367
655
 
368
656
  Three tools for web research powered by Exa.ai:
@@ -413,10 +701,11 @@ const researchTool = new ExaResearchTool({
413
701
  // 4. Synthesizes findings into a markdown report with citations
414
702
  // 5. Returns the complete report (typically 20-90 seconds)
415
703
 
416
- // Usage in agent:
417
- await agent.run('Use exa_research to write a comprehensive report on quantum computing breakthroughs in 2024');
704
+ await agent.run('Use exa_research to write a report on quantum computing breakthroughs in 2024');
418
705
  ```
419
706
 
707
+ ---
708
+
420
709
  ## Built-in Capabilities (CodeAgent)
421
710
 
422
711
  The CodeAgent sandbox includes:
@@ -448,6 +737,8 @@ const agent = new CodeAgent({
448
737
 
449
738
  Packages are fetched from [jsdelivr CDN](https://www.jsdelivr.com/) and cached in `~/.smol-js/packages/`.
450
739
 
740
+ ---
741
+
451
742
  ## Examples
452
743
 
453
744
  See the `examples/js/` directory for complete examples:
@@ -455,11 +746,17 @@ See the `examples/js/` directory for complete examples:
455
746
  - **main.ts**: Main demo with custom tools and YAML workflows
456
747
  - **custom-tools.ts**: Custom tool implementations (TimestampTool, TextStatsTool, SlugifyTool)
457
748
  - **agents/**: YAML workflow definitions
458
- - `custom_tools.yaml`: Workflow using custom tools
749
+ - `custom-tool-workflow.yaml`: Weather assistant using the standalone custom tool plugin system
750
+ - `manager-demo.yaml`: Manager + TerminalAgent worker + file-reader worker
751
+ - `tool-maker/tool-maker.yaml`: AI agent that generates custom tool files
459
752
  - `bloomberg.yaml`: Bloomberg research workflow
460
753
  - `policy.yaml`: Policy analysis workflow
461
754
  - `simple-test.yaml`: Simple test workflow
462
755
 
756
+ And the `custom-tools/` directory at the repo root contains example standalone tool plugins:
757
+
758
+ - `WeatherLookup.ts`: Fetches weather from Open-Meteo (demonstrates npm deps, streaming output, error handling)
759
+
463
760
  Run an example:
464
761
 
465
762
  ```bash
@@ -468,6 +765,8 @@ npm install
468
765
  npx tsx main.ts
469
766
  ```
470
767
 
768
+ ---
769
+
471
770
  ## Memory Management
472
771
 
473
772
  Agents track all execution steps and manage context automatically:
@@ -494,11 +793,15 @@ await persistentAgent.run('What is X?'); // Remembers X = 42
494
793
  - **truncate**: Removes oldest steps when over token limit
495
794
  - **compact**: Uses LLM to summarize older steps
496
795
 
796
+ ---
797
+
497
798
  ## Session Logging
498
799
 
499
800
  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
801
+ - `session-<timestamp>.log` Full session transcript with color codes
802
+ - `packages/` Cached npm packages from dynamic imports
803
+
804
+ ---
502
805
 
503
806
  ## API Reference
504
807
 
@@ -533,7 +836,20 @@ class ToolUseAgent extends Agent {
533
836
  }
534
837
 
535
838
  interface ToolUseAgentConfig extends AgentConfig {
536
- enableParallelToolCalls?: boolean; // Execute independent tools in parallel
839
+ enableParallelToolCalls?: boolean;
840
+ }
841
+ ```
842
+
843
+ ### TerminalAgent
844
+
845
+ ```typescript
846
+ class TerminalAgent extends Agent {
847
+ constructor(config: TerminalAgentConfig)
848
+ }
849
+
850
+ interface TerminalAgentConfig extends AgentConfig {
851
+ commandDelay?: number; // Seconds before executing (default: 5)
852
+ maxOutputLength?: number; // Max chars of output per command (default: 8000)
537
853
  }
538
854
  ```
539
855
 
@@ -585,11 +901,14 @@ class Orchestrator {
585
901
  ```typescript
586
902
  class YAMLLoader {
587
903
  registerToolType(typeName: string, toolClass: typeof Tool): void
904
+ registerToolInstance(name: string, tool: Tool): void
588
905
  loadFromFile(filePath: string): Workflow
589
906
  loadFromString(yaml: string): Workflow
590
907
  }
591
908
  ```
592
909
 
910
+ ---
911
+
593
912
  ## CLI Reference
594
913
 
595
914
  ```bash
@@ -601,18 +920,24 @@ npx @samrahimi/smol-js run <workflow.yaml> [options]
601
920
  npx @samrahimi/smol-js validate <workflow.yaml>
602
921
 
603
922
  # Options
604
- --task, -t <task> Task description (prompted if not provided)
605
- --quiet, -q Reduce output verbosity
606
- --help, -h Show help message
923
+ --task, -t <task> Task description (prompted if not provided)
924
+ --custom-tools-folder <path> Path to folder containing standalone tool plugins
925
+ --quiet, -q Reduce output verbosity
926
+ --help, -h Show help message
607
927
  ```
608
928
 
929
+ ---
930
+
609
931
  ## Security Considerations
610
932
 
611
933
  - **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
934
+ - **Authorized Imports**: Only explicitly allowed npm packages can be imported in CodeAgent
613
935
  - **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)
936
+ - **Execution Delay**: Configurable delay before code/command execution allows user interruption (Ctrl+C)
937
+ - **Timeout Protection**: Code execution has a configurable timeout (default: 30s); shell commands timeout at 2 minutes
938
+ - **Isolated Tool Processes**: Custom tool plugins run in separate Bun processes — a misbehaving tool can't affect the main framework
939
+
940
+ ---
616
941
 
617
942
  ## Comparison with Python smolagents
618
943
 
@@ -625,9 +950,12 @@ npx @samrahimi/smol-js validate <workflow.yaml>
625
950
  | Async support | Optional | All tools are async |
626
951
  | HTTP requests | Requires tool | Built-in `fetch()` |
627
952
  | Remote executors | E2B, Docker, etc. | Local only |
628
- | Agent types | CodeAgent, ToolCallingAgent | CodeAgent, ToolUseAgent |
953
+ | Agent types | CodeAgent, ToolCallingAgent | CodeAgent, ToolUseAgent, TerminalAgent |
629
954
  | YAML workflows | ❌ | ✅ |
630
955
  | Exa.ai integration | ❌ | ✅ Built-in |
956
+ | Custom tool plugins | ❌ | ✅ Standalone `.ts` files |
957
+
958
+ ---
631
959
 
632
960
  ## Contributing
633
961
 
@@ -635,8 +963,8 @@ Contributions are welcome! Please follow OOP principles and open an issue or PR
635
963
 
636
964
  ```bash
637
965
  # Clone and install
638
- git clone https://github.com/samrahimi/smolagents
639
- cd smolagents/smol-js
966
+ git clone https://github.com/samrahimi/smol.git
967
+ cd smol/smol-js
640
968
  npm install
641
969
 
642
970
  # Build
@@ -659,4 +987,4 @@ MIT
659
987
 
660
988
  ## Credits
661
989
 
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.
990
+ This is a TypeScript framework inspired by [smolagents](https://github.com/huggingface/smolagents) by Hugging Face, with additional features including YAML orchestration, ToolUseAgent, TerminalAgent, custom tool plugins, and Exa.ai integration.