orbitx 0.2.9 → 0.3.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.
Files changed (141) hide show
  1. package/Readme.md +478 -456
  2. package/dist/agents/backend.d.ts +4 -0
  3. package/dist/agents/backend.d.ts.map +1 -0
  4. package/dist/agents/backend.js +54 -0
  5. package/dist/agents/backend.js.map +1 -0
  6. package/dist/agents/frontend.d.ts +4 -0
  7. package/dist/agents/frontend.d.ts.map +1 -0
  8. package/dist/agents/frontend.js +50 -0
  9. package/dist/agents/frontend.js.map +1 -0
  10. package/dist/agents/index.d.ts +10 -0
  11. package/dist/agents/index.d.ts.map +1 -0
  12. package/dist/agents/index.js +22 -0
  13. package/dist/agents/index.js.map +1 -0
  14. package/dist/agents/planner.d.ts +4 -0
  15. package/dist/agents/planner.d.ts.map +1 -0
  16. package/dist/agents/planner.js +86 -0
  17. package/dist/agents/planner.js.map +1 -0
  18. package/dist/agents/protocol.d.ts +5 -0
  19. package/dist/agents/protocol.d.ts.map +1 -0
  20. package/dist/agents/protocol.js +70 -0
  21. package/dist/agents/protocol.js.map +1 -0
  22. package/dist/agents/reasoner.d.ts +5 -0
  23. package/dist/agents/reasoner.d.ts.map +1 -0
  24. package/dist/agents/reasoner.js +96 -0
  25. package/dist/agents/reasoner.js.map +1 -0
  26. package/dist/agents/research.d.ts +4 -0
  27. package/dist/agents/research.d.ts.map +1 -0
  28. package/dist/agents/research.js +28 -0
  29. package/dist/agents/research.js.map +1 -0
  30. package/dist/agents/tester.d.ts +4 -0
  31. package/dist/agents/tester.d.ts.map +1 -0
  32. package/dist/agents/tester.js +70 -0
  33. package/dist/agents/tester.js.map +1 -0
  34. package/dist/core/agent-definition.d.ts +61 -0
  35. package/dist/core/agent-definition.d.ts.map +1 -0
  36. package/dist/core/agent-definition.js +82 -0
  37. package/dist/core/agent-definition.js.map +1 -0
  38. package/dist/core/ai-provider.d.ts +3 -0
  39. package/dist/core/ai-provider.d.ts.map +1 -1
  40. package/dist/core/ai-provider.js.map +1 -1
  41. package/dist/core/anthropic-provider.d.ts +1 -0
  42. package/dist/core/anthropic-provider.d.ts.map +1 -1
  43. package/dist/core/anthropic-provider.js +3 -0
  44. package/dist/core/anthropic-provider.js.map +1 -1
  45. package/dist/core/base-agent.d.ts +51 -28
  46. package/dist/core/base-agent.d.ts.map +1 -1
  47. package/dist/core/base-agent.js +118 -26
  48. package/dist/core/base-agent.js.map +1 -1
  49. package/dist/core/deepseek-provider.d.ts +1 -0
  50. package/dist/core/deepseek-provider.d.ts.map +1 -1
  51. package/dist/core/deepseek-provider.js +3 -0
  52. package/dist/core/deepseek-provider.js.map +1 -1
  53. package/dist/core/mcp-computer.d.ts +14 -1
  54. package/dist/core/mcp-computer.d.ts.map +1 -1
  55. package/dist/core/mcp-computer.js +352 -71
  56. package/dist/core/mcp-computer.js.map +1 -1
  57. package/dist/core/ollama-provider.d.ts +1 -0
  58. package/dist/core/ollama-provider.d.ts.map +1 -1
  59. package/dist/core/ollama-provider.js +3 -0
  60. package/dist/core/ollama-provider.js.map +1 -1
  61. package/dist/core/openai-provider.d.ts +1 -0
  62. package/dist/core/openai-provider.d.ts.map +1 -1
  63. package/dist/core/openai-provider.js +3 -0
  64. package/dist/core/openai-provider.js.map +1 -1
  65. package/dist/core/swarm-base.d.ts +88 -0
  66. package/dist/core/swarm-base.d.ts.map +1 -0
  67. package/dist/core/swarm-base.js +427 -0
  68. package/dist/core/swarm-base.js.map +1 -0
  69. package/dist/index.d.ts +7 -5
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +4 -3
  72. package/dist/index.js.map +1 -1
  73. package/dist/tests/agents/default-agents.test.d.ts +2 -0
  74. package/dist/tests/agents/default-agents.test.d.ts.map +1 -0
  75. package/dist/tests/agents/default-agents.test.js +106 -0
  76. package/dist/tests/agents/default-agents.test.js.map +1 -0
  77. package/dist/tests/core/agent-definition.test.d.ts +2 -0
  78. package/dist/tests/core/agent-definition.test.d.ts.map +1 -0
  79. package/dist/tests/core/agent-definition.test.js +99 -0
  80. package/dist/tests/core/agent-definition.test.js.map +1 -0
  81. package/dist/tests/core/scripted-provider.d.ts +38 -0
  82. package/dist/tests/core/scripted-provider.d.ts.map +1 -0
  83. package/dist/tests/core/scripted-provider.js +85 -0
  84. package/dist/tests/core/scripted-provider.js.map +1 -0
  85. package/dist/tests/core/swarm-base.test.d.ts +2 -0
  86. package/dist/tests/core/swarm-base.test.d.ts.map +1 -0
  87. package/dist/tests/core/swarm-base.test.js +387 -0
  88. package/dist/tests/core/swarm-base.test.js.map +1 -0
  89. package/dist/tests/index.d.ts +3 -0
  90. package/dist/tests/index.d.ts.map +1 -1
  91. package/dist/tests/index.js +3 -0
  92. package/dist/tests/index.js.map +1 -1
  93. package/dist/tests/tools/agent/agent-tools.test.js +225 -153
  94. package/dist/tests/tools/agent/agent-tools.test.js.map +1 -1
  95. package/dist/tools/agent/active.d.ts +5 -0
  96. package/dist/tools/agent/active.d.ts.map +1 -0
  97. package/dist/tools/agent/active.js +40 -0
  98. package/dist/tools/agent/active.js.map +1 -0
  99. package/dist/tools/agent/fire.d.ts +5 -0
  100. package/dist/tools/agent/fire.d.ts.map +1 -0
  101. package/dist/tools/agent/fire.js +38 -0
  102. package/dist/tools/agent/fire.js.map +1 -0
  103. package/dist/tools/agent/hire.d.ts +2 -2
  104. package/dist/tools/agent/hire.d.ts.map +1 -1
  105. package/dist/tools/agent/hire.js +43 -10
  106. package/dist/tools/agent/hire.js.map +1 -1
  107. package/dist/tools/agent/index.d.ts +22 -19
  108. package/dist/tools/agent/index.d.ts.map +1 -1
  109. package/dist/tools/agent/index.js +29 -21
  110. package/dist/tools/agent/index.js.map +1 -1
  111. package/dist/tools/agent/prompt.d.ts +2 -2
  112. package/dist/tools/agent/prompt.d.ts.map +1 -1
  113. package/dist/tools/agent/prompt.js +19 -53
  114. package/dist/tools/agent/prompt.js.map +1 -1
  115. package/dist/tools/agent/registry.d.ts +74 -24
  116. package/dist/tools/agent/registry.d.ts.map +1 -1
  117. package/dist/tools/agent/registry.js +93 -48
  118. package/dist/tools/agent/registry.js.map +1 -1
  119. package/dist/tools/agent/report-group.d.ts +5 -0
  120. package/dist/tools/agent/report-group.d.ts.map +1 -0
  121. package/dist/tools/agent/report-group.js +50 -0
  122. package/dist/tools/agent/report-group.js.map +1 -0
  123. package/dist/tools/agent/report-parent.d.ts +5 -0
  124. package/dist/tools/agent/report-parent.d.ts.map +1 -0
  125. package/dist/tools/agent/report-parent.js +36 -0
  126. package/dist/tools/agent/report-parent.js.map +1 -0
  127. package/dist/tools/agent/types.d.ts +5 -0
  128. package/dist/tools/agent/types.d.ts.map +1 -0
  129. package/dist/tools/agent/types.js +17 -0
  130. package/dist/tools/agent/types.js.map +1 -0
  131. package/docs/agents.md +173 -228
  132. package/docs/api-reference.md +9 -4
  133. package/docs/getting-started.md +78 -78
  134. package/docs/index.md +24 -23
  135. package/docs/mcp-architecture.md +29 -6
  136. package/docs/providers.md +258 -254
  137. package/docs/skills.md +0 -1
  138. package/docs/streaming.md +133 -133
  139. package/docs/swarm.md +503 -0
  140. package/docs/tools.md +214 -212
  141. package/package.json +1 -1
package/Readme.md CHANGED
@@ -1,457 +1,479 @@
1
- [![OrbitX Logo](https://raw.githubusercontent.com/ali39af/orbitx/refs/heads/main/orbitx.svg)](#)
2
-
3
- 📖 **[Full documentation](./docs/index.md)** — a deeper, page-by-page guide (providers, agents, tools, skills, MCP transport, streaming, full API reference), written to be useful both to humans learning the library and to AI agents coding against it.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install orbitx
9
- ```
10
-
11
- ## Demo
12
-
13
- <table>
14
- <tr>
15
- <td align="center">
16
- <a href="https://www.youtube.com/watch?v=nuIhIBdBjTI">
17
- <img src="https://img.youtube.com/vi/nuIhIBdBjTI/maxresdefault.jpg" width="400" alt="Demo 1">
18
- </a>
19
- <br>
20
- <b>Demo 1</b>
21
- </td>
22
- <td align="center">
23
- <a href="https://www.youtube.com/watch?v=Go1PIYo0sFw">
24
- <img src="https://img.youtube.com/vi/Go1PIYo0sFw/maxresdefault.jpg" width="400" alt="Demo 2">
25
- </a>
26
- <br>
27
- <b>Demo 2</b>
28
- </td>
29
- </tr>
30
- </table>
31
-
32
-
33
- ## Quick Start
34
-
35
- The fastest way to get an agent running is `SimpleAgent` — give it a provider, an instruction, and a list of tools/skills.
36
-
37
- ```ts
38
- import { OllamaProvider, SimpleAgent, GetCurrentTimeTool } from "orbitx";
39
-
40
- const ollamaProvider = new OllamaProvider("gemma4:e4b");
41
-
42
- const agent = new SimpleAgent({
43
- aiProvider: ollamaProvider,
44
- instruction: "You are a helpful assistant.",
45
- tools: [GetCurrentTimeTool()],
46
- });
47
-
48
- let oldRole: "assistant" | "tool" | "user" | undefined;
49
-
50
- agent.run("what is current time?", (chunk) => {
51
- if (oldRole !== chunk.role) {
52
- process.stdout.write(`\n${chunk.role}: `);
53
- oldRole = chunk.role;
54
- }
55
- process.stdout.write(chunk.content);
56
-
57
- if (chunk.done && chunk.role === "assistant" && chunk.toolCalls?.length) {
58
- console.log(chunk.toolCalls);
59
- }
60
- if (chunk.role === "tool") {
61
- console.log({ toolCallId: chunk.toolCallId, toolName: chunk.toolName });
62
- }
63
-
64
- if (chunk.done) {
65
- process.stdout.write("\n\n");
66
- oldRole = undefined;
67
- }
68
- });
69
- ```
70
-
71
- All tools and skills passed in are baked into the system prompt once, up front — there's no separate routing/selection step deciding what the model can see turn to turn.
72
-
73
- ### Recovering an agent's state
74
-
75
- `getCurrentAgentStates()` returns a plain JSON-serializable snapshot (messages, memory, token counters). Save it wherever you like, and pass it back in as `initData` to resume the exact same agent later — a process restart, a saved session, etc.
76
-
77
- ```ts
78
- import { writeFileSync, existsSync, readFileSync } from "fs";
79
-
80
- const initData = existsSync("./state.json")
81
- ? JSON.parse(readFileSync("./state.json", "utf-8"))
82
- : undefined;
83
-
84
- const agent = new SimpleAgent({
85
- aiProvider: ollamaProvider,
86
- instruction: "You are a helpful assistant.",
87
- tools: [GetCurrentTimeTool()],
88
- ...(initData ? { initData } : {}),
89
- });
90
-
91
- // after any run() call:
92
- writeFileSync("./state.json", JSON.stringify(agent.getCurrentAgentStates()));
93
- ```
94
-
95
- Old messages are never rewritten once written — the agent only ever appends. When the conversation grows past its memory limit, OrbitX keeps the full history intact on disk (`messagesFull`) and instead resets the model's working context window from a running summary of what it already did, so it can keep going indefinitely without losing the ability to act on what happened earlier.
96
-
97
- ## Providers
98
-
99
- OrbitX ships with pluggable AI providers so you can swap models without changing your agent logic.
100
-
101
- ### Ollama
102
-
103
- ```ts
104
- import { OllamaProvider } from "orbitx";
105
-
106
- const ollamaProvider = new OllamaProvider("gemma4:e4b");
107
- ```
108
-
109
- ### DeepSeek
110
-
111
- ```ts
112
- import { DeepSeekProvider } from "orbitx";
113
-
114
- const deepseekProvider = new DeepSeekProvider("api-key", "deepseek-v4-flash");
115
- ```
116
-
117
- ### Anthropic
118
-
119
- ```ts
120
- import { AnthropicProvider } from "orbitx";
121
-
122
- const anthropicProvider = new AnthropicProvider("api-key", "claude-sonnet-5");
123
- ```
124
-
125
- ### OpenAI
126
-
127
- ```ts
128
- import { OpenAIProvider } from "orbitx";
129
-
130
- const openaiProvider = new OpenAIProvider("api-key", "gpt-5");
131
- ```
132
-
133
- ### Think effort
134
-
135
- Every provider accepts a universal `thinkEffort` option (`0`-`1`, e.g. `0.5` or `0.8`) instead of a provider-specific string — each provider maps it onto whatever scale it actually accepts (DeepSeek's `none/low/high/max`, OpenAI/Ollama's `low/medium/high`, Anthropic's numeric thinking budget), and it's silently ignored by providers/models that don't support thinking at all:
136
-
137
- ```ts
138
- import { AnthropicProvider } from "orbitx";
139
-
140
- const anthropicProvider = new AnthropicProvider("api-key", "claude-sonnet-5", { thinkEffort: 0.7 });
141
- ```
142
-
143
- See the [docs](./docs/providers.md#think-effort) for the per-provider mapping and how thinking text streams (where supported).
144
-
145
- ### Two providers: main + image
146
-
147
- An agent uses exactly two provider roles — `main` (drives the agent loop itself) and `image` (describes image tool output, e.g. screenshots, so the main conversation doesn't have to carry raw image bytes). Pass a single provider to use it for both roles, or an array to split them:
148
-
149
- ```ts
150
- import { BaseAgent, DeepSeekProvider, OllamaProvider } from "orbitx";
151
-
152
- const agent = new BaseAgent({
153
- aiProvider: [
154
- { type: "main", aiProvider: new DeepSeekProvider("api-key", "deepseek-v4-flash") },
155
- { type: "image", aiProvider: new OllamaProvider("llava:latest") },
156
- ],
157
- instruction: "You are a helpful assistant.",
158
- mcpClient,
159
- allowedTools: [/* ... */],
160
- });
161
- ```
162
-
163
- ## Available Tools
164
-
165
- Tools are grouped by domain. Import each group's array (e.g. `FsTools()`) to get every tool in that group at once, or import individual tools by name.
166
-
167
- ### Filesystem (`FsTools`)
168
-
169
- ⚠️ EXTREMELY IMPORTANT WARNING ABOUT `FsWriteFileTool` / `FsDeleteTool` ⚠️
170
-
171
- 🔴 CRITICAL: FsWriteFileTool and FsDeleteTool can permanently overwrite, delete, or corrupt existing files – no undo available.
172
-
173
- We strongly prefer running bash commands through MCPComputer, which provides a sandboxed, isolated environment – protecting your host system from accidental damage.
174
-
175
-
176
- | Tool | Purpose |
177
- |---|---|
178
- | `FsReadFileTool` | Read a text file, paging through large files by line. |
179
- | `FsWriteFileTool` | Write/overwrite a file's full content (creates parent dirs as needed). ⚠️ No undo. |
180
- | `FsEditFileTool` | Replace a specific line range in an existing file without rewriting the whole thing. |
181
- | `FsListDirTool` | List a directory's entries, paged by index for large directories. |
182
- | `FsCreateDirTool` | Create a directory, including missing parents. |
183
- | `FsDeleteTool` | Permanently delete a file or directory (recursive optional). ⚠️ No undo. |
184
- | `FsMoveTool` | Move or rename a file or directory. |
185
- | `FsStatTool` | Check whether a path exists and get its metadata (type, size, modified time). |
186
-
187
- ### Bash / processes (`BashTools`)
188
-
189
- ⚠️ EXTREMELY IMPORTANT WARNING ABOUT `BashRunTool` ⚠️
190
-
191
- 🔴 CRITICAL: Shell commands can permanently delete files, corrupt data, modify system settings, or execute harmful operations – no undo available.
192
-
193
- We strongly prefer running bash commands through MCPComputer, which provides a sandboxed, isolated environment – protecting your host system from accidental damage.
194
-
195
- | Tool | Purpose |
196
- |---|---|
197
- | `BashRunTool` | Launch a shell command as a background process; returns immediately if it's still running after `waitMs` (e.g. a dev server). |
198
- | `BashWaitTool` | Wait again on a previously started process and get its latest status/output. |
199
- | `BashLogsTool` | Read a process's combined stdout/stderr, paged by line. |
200
- | `BashListTool` | List every process launched so far with its status. |
201
- | `BashWriteInputTool` | Send text to a running process's stdin (answer an interactive prompt like `(y/n)`). |
202
- | `BashTerminateTool` | Terminate a running process. |
203
-
204
- ### Browser (`BrowserTools`)
205
-
206
- Drives a real headless browser session.
207
-
208
- | Tool | Purpose |
209
- |---|---|
210
- | `BrowserCreateSessionTool` | Open a new headless browser session at a URL, returns its `sessionId`. |
211
- | `BrowserRemoveSessionTool` | Close and remove a browser session. |
212
- | `BrowserGetSessionsTool` | List all currently open session ids. |
213
- | `BrowserNavigateTool` | Navigate an existing session to a new URL. |
214
- | `BrowserReadTool` | Read the page as a text outline (headings, tables, links, forms), assigning ref ids to clickable/fillable elements. |
215
- | `BrowserClickTool` | Click a `[CLICKABLE]` element by ref id. |
216
- | `BrowserFillTool` | Type into a `[FILLABLE]` element by ref id; can submit via Enter if the field's form has no visible submit button. |
217
- | `BrowserSubmitFormTool` | Submit a `[FORM]` ref directly — for forms with no visible submit button. |
218
- | `BrowserScrollInfoTool` | Get total scrollable length and current scroll position. |
219
- | `BrowserScrollTool` | Scroll to a given vertical pixel position. |
220
- | `BrowserConsoleTool` | Read captured browser console log messages. |
221
- | `BrowserNetworkTool` | Read captured network request/response activity. |
222
- | `BrowserNetworkStatusTool` | Check whether the page currently has in-flight network activity (use before assuming a "no response yet" state means something broke). |
223
- | `BrowserInjectTool` | Evaluate arbitrary JS in the page and return the result. |
224
- | `BrowserScreenshotTool` | Capture a screenshot; can be described by the `image` provider instead of passed raw to the main model. |
225
-
226
- ### Todo lists (`TodoTools`)
227
-
228
- | Tool | Purpose |
229
- |---|---|
230
- | `TodoCreateListTool` | Create a new todo list, returns its `todoListId`. |
231
- | `TodoRemoveListTool` | Remove one or more todo lists (and their tasks). |
232
- | `TodoGetListsTool` | Get all existing todo list ids. |
233
- | `TodoGetListTool` | Get all tasks belonging to a list. |
234
- | `TodoCreateTaskTool` | Create one or more tasks inside a list. |
235
- | `TodoRemoveTaskTool` | Remove one or more tasks by id. |
236
- | `TodoCheckTaskTool` | Set the checked/unchecked state of one or more tasks. |
237
-
238
- ### Present / deliverables (`PresentTools`)
239
-
240
- | Tool | Purpose |
241
- |---|---|
242
- | `PresentAddTool` | Present a file to the user by copying it into the present folder (zip folders first — this only accepts single files). |
243
- | `PresentClearTool` | Clear out every file currently presented. |
244
- | `PresentGetListTool` | Get the list of files currently presented. |
245
-
246
- ### Utility (`UtilTools`)
247
-
248
- | Tool | Purpose |
249
- |---|---|
250
- | `GetCurrentTimeTool` | Get the current date/time (ISO string, unix timestamp, timezone). |
251
- | `DelayTool` | Wait a given number of milliseconds (max 60000ms) before continuing. |
252
-
253
- ### Multi-agent (`AgentTools`) — Experimental
254
-
255
- ⚠️ This feature is new and still settling — names and behavior may change in a future release.
256
-
257
- Unlike the other domains, this one takes parameters — a roster of `WorkerAgent`s (a `BaseAgent` with a name/description/rating) you build ahead of time, and an optional hiring cap: `AgentTools([worker1, worker2, ...], { maxHired: 2 })`. Give the result to your planner agent so it can list, hire, and prompt those workers as sub-agents; give each worker its own `AgentReportTool()` so it can hand a result back and stop. Full walkthrough in the [docs](./docs/agents.md#multi-agent-workeragent-experimental).
258
-
259
- | Tool | Purpose |
260
- |---|---|
261
- | `agent-list` | List every worker in the roster — name, description, rating, hired status. |
262
- | `agent-hire` | Hire a worker by name, making it eligible for `agent-prompt`. |
263
- | `agent-prompt` | Send a prompt to a hired worker and return its response once it's done. |
264
-
265
- ## Available Skills
266
-
267
- A `Skill` bundles instructions with the tools that go with them. Passing a skill into an agent adds its tools automatically and folds its instructions into the system prompt.
268
-
269
- | Skill | Purpose |
270
- |---|---|
271
- | `PlannerSkill` | Stands up a persistent, checkable todo list for any large/multi-step/vague job so progress survives long conversations and context resets. |
272
- | `BigTaskSkill` | Keeps the agent from stopping short on large or ambitious jobs — no declaring victory on a partial slice, no handing a big job back half-finished. |
273
- | `LongTaskEfficiencySkill` | Keeps a long job efficient — batching, avoiding redundant reads, checkpointing, not gold-plating — without giving up on getting through the full scope. |
274
- | `NodeBackendSkill` | Building, running, and debugging Node.js backends: APIs, servers, CLIs, workers, schedulers, DB access layers — new or existing. |
275
- | `ReactFrontendSkill` | Building, running, and debugging modern React (`.tsx`/`.jsx`) projects, typically Vite-scaffolded — new or existing. |
276
- | `UiUxDesignSkill` | Visual and interaction design quality for any user-facing UI — layout, hierarchy, feedback states, accessibility, responsiveness. |
277
- | `BackendSecuritySkill` | Hardening server-side code that touches auth, sessions, tokens, uploads, DB queries, payments, or any trust boundary. |
278
- | `CodeVerificationSkill` | Running the right type checker/build/lint/test suite before handing code back, and telling real bugs apart from sandbox artifacts. |
279
- | `WebEndToEndTestSkill` | Testing a live web app like a real user would (fill, click, navigate) and verifying via the rendered page, console, and network — not by reading source and assuming. |
280
- | `ResearchSkill` | Answering questions that need real, current information from the live web — opens pages, cross-checks multiple sources, never trusts one page. |
281
- | `ShoppingSkill` | Purchase-decision help — real current listings, prices, links, and review sentiment instead of recommending from memory. |
282
- | `PresentSkill` | Deciding how to hand back a job's output as files (individually or zipped) and cleaning build artifacts out first. |
283
-
284
- ## Building from the Base Agent
285
-
286
- For full control over the MCP server, connection, and client, compose an agent from the base primitives:
287
-
288
- ```ts
289
- import {
290
- OllamaProvider,
291
- MCPConnection,
292
- MCPServer,
293
- MCPClient,
294
- BaseAgent,
295
- GetCurrentTimeTool,
296
- } from "orbitx";
297
-
298
- const ollamaProvider = new OllamaProvider("gemma4:e4b");
299
-
300
- const connection = new MCPConnection();
301
-
302
- const mcpServer = new MCPServer(connection);
303
- mcpServer.registerTool(GetCurrentTimeTool());
304
-
305
- const mcpClient = new MCPClient("DEFAULT_ENV", connection);
306
-
307
- const agent = new BaseAgent({
308
- aiProvider: ollamaProvider,
309
- instruction: "",
310
- mcpClient,
311
- allowedTools: [GetCurrentTimeTool()],
312
- });
313
-
314
- let oldRole: "assistant" | "tool" | "user" | undefined;
315
-
316
- agent.run("what is current time?", (chunk) => {
317
- if (oldRole !== chunk.role) {
318
- process.stdout.write(`\n${chunk.role}: `);
319
- oldRole = chunk.role;
320
- }
321
- process.stdout.write(chunk.content);
322
- if (chunk.done) {
323
- process.stdout.write("\n\n");
324
- oldRole = undefined;
325
- }
326
- });
327
- ```
328
-
329
- ### IPC Connections
330
-
331
- Run your MCP server as a separate process and connect to it over an inter-process communication (IPC) channel:
332
-
333
- ```ts
334
- import os from "os";
335
- import { MCPIPCConnection } from "orbitx";
336
-
337
- const path =
338
- os.platform() === "win32" ? `\\\\.\\pipe\\mcp_test` : `/tmp/mcp_test.sock`;
339
-
340
- const ipcConnection = new MCPIPCConnection({ mode: "server", socketPath: path });
341
- ```
342
-
343
- ### WS Connections
344
-
345
- Run your MCP server as a separate process and connect to it over an web-socket communication (WS) channel:
346
-
347
- ```ts
348
- import os from "os";
349
- import { MCPWSConnection } from "orbitx";
350
-
351
- const wsConnection = new MCPWSConnection({ mode: "server", host: "0.0.0.0", port: 9257, token: "1234" });
352
- ```
353
-
354
-
355
- ## Creating a Custom Tool
356
-
357
- Define your own tools with `MCPTool` to extend an agent's capabilities and integrate with your own ecosystem.
358
-
359
- ```ts
360
- import { MCPTool } from "orbitx";
361
-
362
- export const SumTool = () => new MCPTool({
363
- name: "math-sum",
364
- description: "get two numbers and sum them",
365
- inputs: [
366
- {
367
- name: "first",
368
- type: "number",
369
- description: "first number",
370
- required: true,
371
- },
372
- {
373
- name: "second",
374
- type: "number",
375
- description: "second number",
376
- required: true,
377
- },
378
- ],
379
- execute: async (_envID: string, inputs: Record<string, any>) => {
380
- const { first, second } = inputs;
381
-
382
- if (typeof first !== "number") {
383
- throw new Error("first must be a number");
384
- }
385
- if (typeof second !== "number") {
386
- throw new Error("second must be a number");
387
- }
388
-
389
- return { output: first + second };
390
- },
391
- });
392
- ```
393
-
394
- Use it like any built-in tool:
395
-
396
- ```ts
397
- const agent = new SimpleAgent({
398
- aiProvider: ollamaProvider,
399
- instruction: "You are a helpful assistant.",
400
- tools: [SumTool()],
401
- });
402
- ```
403
-
404
- ## Creating a Custom Skill
405
-
406
- A `Skill` bundles instructions with the tools it needs, so an agent that includes it automatically gets both.
407
-
408
- ```ts
409
- import { Skill, FsReadFileTool, FsWriteFileTool } from "orbitx";
410
- import { SumTool } from "./sum-tool.js";
411
-
412
- export const MathHelperSkill = () => new Skill({
413
- name: "math-helper",
414
- description:
415
- "Use this skill whenever the user asks for arithmetic that should be computed exactly " +
416
- "rather than estimated from the model's own reasoning — sums, running totals, or " +
417
- "anything written to a file afterward.",
418
- instructions: `
419
- - Always use the math-sum tool for addition instead of computing it yourself.
420
- - If asked to save a result, write it to disk with fs-write-file and confirm the path back to the user.
421
- `,
422
- tools: [
423
- SumTool(),
424
- FsReadFileTool(),
425
- FsWriteFileTool(),
426
- ],
427
- });
428
- ```
429
-
430
- ```ts
431
- const agent = new SimpleAgent({
432
- aiProvider: ollamaProvider,
433
- instruction: "You are a helpful assistant.",
434
- skills: [MathHelperSkill()],
435
- });
436
- ```
437
-
438
- ## MCPComputer (Experimental Feature)
439
-
440
- Spins up a sandboxed Docker container running the MCP server and returns a ready-to-use client connection — no need to manage IPC sockets, ports, or tokens manually.
441
-
442
- ```typescript
443
- import { MCPComputer } from "orbitx";
444
-
445
- const computer = new MCPComputer("/path/to/mount", [3000, 8080]);
446
- await computer.start();
447
-
448
- const connection = computer.getConnection();
449
- await computer.stop();
450
- ```
451
-
452
- - **`mountPath`**: host directory mounted into the container
453
- - **`ports`**: ports to expose, or `"*"` for host network mode (Linux only, or Windows via WSL2)
454
- - **`getConnection()`**: returns a ready `MCPConnection` (IPC on Linux/macOS, WebSocket on Windows)
455
- - **`stop()`**: kills the container
456
-
1
+ [![OrbitX Logo](https://raw.githubusercontent.com/ali39af/orbitx/refs/heads/main/orbitx.svg)](#)
2
+
3
+ 📖 **[Full documentation](./docs/index.md)** — a deeper, page-by-page guide (providers, agents, swarms, tools, skills, MCP transport, streaming, full API reference), written to be useful both to humans learning the library and to AI agents coding against it.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install orbitx
9
+ ```
10
+
11
+ ## Demo
12
+
13
+ <table>
14
+ <tr>
15
+ <td align="center">
16
+ <a href="https://www.youtube.com/watch?v=nuIhIBdBjTI">
17
+ <img src="https://img.youtube.com/vi/nuIhIBdBjTI/maxresdefault.jpg" width="400" alt="Demo 1">
18
+ </a>
19
+ <br>
20
+ <b>Demo 1</b>
21
+ </td>
22
+ <td align="center">
23
+ <a href="https://www.youtube.com/watch?v=Go1PIYo0sFw">
24
+ <img src="https://img.youtube.com/vi/Go1PIYo0sFw/maxresdefault.jpg" width="400" alt="Demo 2">
25
+ </a>
26
+ <br>
27
+ <b>Demo 2</b>
28
+ </td>
29
+ </tr>
30
+ </table>
31
+
32
+
33
+ ## Quick Start
34
+
35
+ The fastest way to get an agent running is `SimpleAgent` — give it a provider, an instruction, and a list of tools/skills.
36
+
37
+ ```ts
38
+ import { OllamaProvider, SimpleAgent, GetCurrentTimeTool } from "orbitx";
39
+
40
+ const ollamaProvider = new OllamaProvider("gemma4:e4b");
41
+
42
+ const agent = new SimpleAgent({
43
+ aiProvider: ollamaProvider,
44
+ instruction: "You are a helpful assistant.",
45
+ tools: [GetCurrentTimeTool()],
46
+ });
47
+
48
+ let oldRole: "assistant" | "tool" | "user" | undefined;
49
+
50
+ agent.run("what is current time?", (chunk) => {
51
+ if (oldRole !== chunk.role) {
52
+ process.stdout.write(`\n${chunk.role}: `);
53
+ oldRole = chunk.role;
54
+ }
55
+ process.stdout.write(chunk.content);
56
+
57
+ if (chunk.done && chunk.role === "assistant" && chunk.toolCalls?.length) {
58
+ console.log(chunk.toolCalls);
59
+ }
60
+ if (chunk.role === "tool") {
61
+ console.log({ toolCallId: chunk.toolCallId, toolName: chunk.toolName });
62
+ }
63
+
64
+ if (chunk.done) {
65
+ process.stdout.write("\n\n");
66
+ oldRole = undefined;
67
+ }
68
+ });
69
+ ```
70
+
71
+ All tools and skills passed in are baked into the system prompt once, up front — there's no separate routing/selection step deciding what the model can see turn to turn.
72
+
73
+ ### Recovering an agent's state
74
+
75
+ `getCurrentAgentStates()` returns a plain JSON-serializable snapshot (messages, memory, token counters). Save it wherever you like, and pass it back in as `initData` to resume the exact same agent later — a process restart, a saved session, etc.
76
+
77
+ ```ts
78
+ import { writeFileSync, existsSync, readFileSync } from "fs";
79
+
80
+ const initData = existsSync("./state.json")
81
+ ? JSON.parse(readFileSync("./state.json", "utf-8"))
82
+ : undefined;
83
+
84
+ const agent = new SimpleAgent({
85
+ aiProvider: ollamaProvider,
86
+ instruction: "You are a helpful assistant.",
87
+ tools: [GetCurrentTimeTool()],
88
+ ...(initData ? { initData } : {}),
89
+ });
90
+
91
+ // after any run() call:
92
+ writeFileSync("./state.json", JSON.stringify(agent.getCurrentAgentStates()));
93
+ ```
94
+
95
+ Old messages are never rewritten once written — the agent only ever appends. When the conversation grows past its memory limit, OrbitX keeps the full history intact on disk (`messagesFull`) and instead resets the model's working context window from a running summary of what it already did, so it can keep going indefinitely without losing the ability to act on what happened earlier.
96
+
97
+ ## Providers
98
+
99
+ OrbitX ships with pluggable AI providers so you can swap models without changing your agent logic.
100
+
101
+ ### Ollama
102
+
103
+ ```ts
104
+ import { OllamaProvider } from "orbitx";
105
+
106
+ const ollamaProvider = new OllamaProvider("gemma4:e4b");
107
+ ```
108
+
109
+ ### DeepSeek
110
+
111
+ ```ts
112
+ import { DeepSeekProvider } from "orbitx";
113
+
114
+ const deepseekProvider = new DeepSeekProvider("api-key", "deepseek-v4-flash");
115
+ ```
116
+
117
+ ### Anthropic
118
+
119
+ ```ts
120
+ import { AnthropicProvider } from "orbitx";
121
+
122
+ const anthropicProvider = new AnthropicProvider("api-key", "claude-sonnet-5");
123
+ ```
124
+
125
+ ### OpenAI
126
+
127
+ ```ts
128
+ import { OpenAIProvider } from "orbitx";
129
+
130
+ const openaiProvider = new OpenAIProvider("api-key", "gpt-5");
131
+ ```
132
+
133
+ ### Think effort
134
+
135
+ Every provider accepts a universal `thinkEffort` option (`0`-`1`, e.g. `0.5` or `0.8`) instead of a provider-specific string — each provider maps it onto whatever scale it actually accepts (DeepSeek's `none/low/high/max`, OpenAI/Ollama's `low/medium/high`, Anthropic's numeric thinking budget), and it's silently ignored by providers/models that don't support thinking at all:
136
+
137
+ ```ts
138
+ import { AnthropicProvider } from "orbitx";
139
+
140
+ const anthropicProvider = new AnthropicProvider("api-key", "claude-sonnet-5", { thinkEffort: 0.7 });
141
+ ```
142
+
143
+ See the [docs](./docs/providers.md#think-effort) for the per-provider mapping and how thinking text streams (where supported).
144
+
145
+ ### Two providers: main + image
146
+
147
+ An agent uses exactly two provider roles — `main` (drives the agent loop itself) and `image` (describes image tool output, e.g. screenshots, so the main conversation doesn't have to carry raw image bytes). Pass a single provider to use it for both roles, or an array to split them:
148
+
149
+ ```ts
150
+ import { BaseAgent, DeepSeekProvider, OllamaProvider } from "orbitx";
151
+
152
+ const agent = new BaseAgent({
153
+ aiProvider: [
154
+ { type: "main", aiProvider: new DeepSeekProvider("api-key", "deepseek-v4-flash") },
155
+ { type: "image", aiProvider: new OllamaProvider("llava:latest") },
156
+ ],
157
+ instruction: "You are a helpful assistant.",
158
+ mcpClient,
159
+ allowedTools: [/* ... */],
160
+ });
161
+ ```
162
+
163
+ ## Available Tools
164
+
165
+ Tools are grouped by domain. Import each group's array (e.g. `FsTools()`) to get every tool in that group at once, or import individual tools by name.
166
+
167
+ ### Filesystem (`FsTools`)
168
+
169
+ ⚠️ EXTREMELY IMPORTANT WARNING ABOUT `FsWriteFileTool` / `FsDeleteTool` ⚠️
170
+
171
+ 🔴 CRITICAL: FsWriteFileTool and FsDeleteTool can permanently overwrite, delete, or corrupt existing files – no undo available.
172
+
173
+ We strongly prefer running bash commands through MCPComputer, which provides a sandboxed, isolated environment – protecting your host system from accidental damage.
174
+
175
+
176
+ | Tool | Purpose |
177
+ |---|---|
178
+ | `FsReadFileTool` | Read a text file, paging through large files by line. |
179
+ | `FsWriteFileTool` | Write/overwrite a file's full content (creates parent dirs as needed). ⚠️ No undo. |
180
+ | `FsEditFileTool` | Replace a specific line range in an existing file without rewriting the whole thing. |
181
+ | `FsListDirTool` | List a directory's entries, paged by index for large directories. |
182
+ | `FsCreateDirTool` | Create a directory, including missing parents. |
183
+ | `FsDeleteTool` | Permanently delete a file or directory (recursive optional). ⚠️ No undo. |
184
+ | `FsMoveTool` | Move or rename a file or directory. |
185
+ | `FsStatTool` | Check whether a path exists and get its metadata (type, size, modified time). |
186
+
187
+ ### Bash / processes (`BashTools`)
188
+
189
+ ⚠️ EXTREMELY IMPORTANT WARNING ABOUT `BashRunTool` ⚠️
190
+
191
+ 🔴 CRITICAL: Shell commands can permanently delete files, corrupt data, modify system settings, or execute harmful operations – no undo available.
192
+
193
+ We strongly prefer running bash commands through MCPComputer, which provides a sandboxed, isolated environment – protecting your host system from accidental damage.
194
+
195
+ | Tool | Purpose |
196
+ |---|---|
197
+ | `BashRunTool` | Launch a shell command as a background process; returns immediately if it's still running after `waitMs` (e.g. a dev server). |
198
+ | `BashWaitTool` | Wait again on a previously started process and get its latest status/output. |
199
+ | `BashLogsTool` | Read a process's combined stdout/stderr, paged by line. |
200
+ | `BashListTool` | List every process launched so far with its status. |
201
+ | `BashWriteInputTool` | Send text to a running process's stdin (answer an interactive prompt like `(y/n)`). |
202
+ | `BashTerminateTool` | Terminate a running process. |
203
+
204
+ ### Browser (`BrowserTools`)
205
+
206
+ Drives a real headless browser session.
207
+
208
+ | Tool | Purpose |
209
+ |---|---|
210
+ | `BrowserCreateSessionTool` | Open a new headless browser session at a URL, returns its `sessionId`. |
211
+ | `BrowserRemoveSessionTool` | Close and remove a browser session. |
212
+ | `BrowserGetSessionsTool` | List all currently open session ids. |
213
+ | `BrowserNavigateTool` | Navigate an existing session to a new URL. |
214
+ | `BrowserReadTool` | Read the page as a text outline (headings, tables, links, forms), assigning ref ids to clickable/fillable elements. |
215
+ | `BrowserClickTool` | Click a `[CLICKABLE]` element by ref id. |
216
+ | `BrowserFillTool` | Type into a `[FILLABLE]` element by ref id; can submit via Enter if the field's form has no visible submit button. |
217
+ | `BrowserSubmitFormTool` | Submit a `[FORM]` ref directly — for forms with no visible submit button. |
218
+ | `BrowserScrollInfoTool` | Get total scrollable length and current scroll position. |
219
+ | `BrowserScrollTool` | Scroll to a given vertical pixel position. |
220
+ | `BrowserConsoleTool` | Read captured browser console log messages. |
221
+ | `BrowserNetworkTool` | Read captured network request/response activity. |
222
+ | `BrowserNetworkStatusTool` | Check whether the page currently has in-flight network activity (use before assuming a "no response yet" state means something broke). |
223
+ | `BrowserInjectTool` | Evaluate arbitrary JS in the page and return the result. |
224
+ | `BrowserScreenshotTool` | Capture a screenshot; can be described by the `image` provider instead of passed raw to the main model. |
225
+
226
+ ### Todo lists (`TodoTools`)
227
+
228
+ | Tool | Purpose |
229
+ |---|---|
230
+ | `TodoCreateListTool` | Create a new todo list, returns its `todoListId`. |
231
+ | `TodoRemoveListTool` | Remove one or more todo lists (and their tasks). |
232
+ | `TodoGetListsTool` | Get all existing todo list ids. |
233
+ | `TodoGetListTool` | Get all tasks belonging to a list. |
234
+ | `TodoCreateTaskTool` | Create one or more tasks inside a list. |
235
+ | `TodoRemoveTaskTool` | Remove one or more tasks by id. |
236
+ | `TodoCheckTaskTool` | Set the checked/unchecked state of one or more tasks. |
237
+
238
+ ### Present / deliverables (`PresentTools`)
239
+
240
+ | Tool | Purpose |
241
+ |---|---|
242
+ | `PresentAddTool` | Present a file to the user by copying it into the present folder (zip folders first — this only accepts single files). |
243
+ | `PresentClearTool` | Clear out every file currently presented. |
244
+ | `PresentGetListTool` | Get the list of files currently presented. |
245
+
246
+ ### Utility (`UtilTools`)
247
+
248
+ | Tool | Purpose |
249
+ |---|---|
250
+ | `GetCurrentTimeTool` | Get the current date/time (ISO string, unix timestamp, timezone). |
251
+ | `DelayTool` | Wait a given number of milliseconds (max 60000ms) before continuing. |
252
+
253
+ ### Swarm (`getAgentTools`)
254
+
255
+ The tools a group of agents uses to hire, task, and report to each other. Unlike the other domains this one returns a **handle**, not an array — `handle.tools` goes into your tool pool, and the handle itself goes into `SwarmBase`, because both sides share the state built with it (the shared hire pool, and which swarm the tools drive).
256
+
257
+ ```ts
258
+ const agentTools = getAgentTools({ maxHired: 5 });
259
+
260
+ const swarm = new SwarmBase({
261
+ tools: [...FsTools(), ...BashTools(), ...UtilTools(), ...agentTools.tools],
262
+ agents: DefaultAgents(), // planner, reasoner, backend, frontend, tester, research
263
+ default: "planner",
264
+ agentTools,
265
+ aiProvider,
266
+ });
267
+
268
+ const done = await swarm.run("Build the checkout flow", chunk => {
269
+ process.stdout.write(`[${chunk.agentId}] ${chunk.content}`);
270
+ });
271
+ // true only once the planner AND every agent it hired are idle
272
+ ```
273
+
274
+ | Tool | Purpose |
275
+ |---|---|
276
+ | `agent-types` | List the kinds of agent this swarm can hire — description, ratings, how many are working, slots left. |
277
+ | `agent-hire` | Spawn an agent of a type, optionally into a group and with a standing briefing. |
278
+ | `agent-fire` | Release one of your own hires and free its slot. |
279
+ | `agent-active` | List every hired agent — id, type, groups, parent, busy. |
280
+ | `agent-prompt` | Hand a task to one of your hires; returns immediately, the answer arrives later as a report. |
281
+ | `agent-report-parent` | Send a result to the agent that hired you, ending your turn. |
282
+ | `agent-report-group` | Message your group's other members; your parent never sees it. |
283
+
284
+ Which agent can do what is decided by its `allowedTools` — hiring tools for a planner, reporting tools for a worker — and agents themselves are written as reusable `AgentDefinition`s (the `Skill` idea, applied to agents) that you import rather than assemble.
285
+
286
+ `DefaultAgents()` ships a pipeline, not just a list: the planner hires a **reasoner** (five personas arguing for a measured five minutes before answering), then a **backend** agent that must publish an API contract, then a **tester** that verifies that contract against the running server *before* it reaches anyone, then one to three **frontend** agents in a shared group who agree on the scaffold and claim files between themselves so they never overwrite each other, and finally a **tester** on the whole flow. Point the shared `MCPClient` at an [`MCPComputer`](./docs/mcp-architecture.md#mcpcomputer-sandboxed-execution) and all of that happens inside a container instead of on your machine. Full walkthrough in the [docs](./docs/swarm.md).
287
+
288
+ ## Available Skills
289
+
290
+ A `Skill` bundles instructions with the tools that go with them. Passing a skill into an agent adds its tools automatically and folds its instructions into the system prompt.
291
+
292
+ | Skill | Purpose |
293
+ |---|---|
294
+ | `PlannerSkill` | Stands up a persistent, checkable todo list for any large/multi-step/vague job so progress survives long conversations and context resets. |
295
+ | `BigTaskSkill` | Keeps the agent from stopping short on large or ambitious jobs — no declaring victory on a partial slice, no handing a big job back half-finished. |
296
+ | `LongTaskEfficiencySkill` | Keeps a long job efficient — batching, avoiding redundant reads, checkpointing, not gold-plating — without giving up on getting through the full scope. |
297
+ | `NodeBackendSkill` | Building, running, and debugging Node.js backends: APIs, servers, CLIs, workers, schedulers, DB access layers — new or existing. |
298
+ | `ReactFrontendSkill` | Building, running, and debugging modern React (`.tsx`/`.jsx`) projects, typically Vite-scaffolded — new or existing. |
299
+ | `UiUxDesignSkill` | Visual and interaction design quality for any user-facing UI — layout, hierarchy, feedback states, accessibility, responsiveness. |
300
+ | `BackendSecuritySkill` | Hardening server-side code that touches auth, sessions, tokens, uploads, DB queries, payments, or any trust boundary. |
301
+ | `CodeVerificationSkill` | Running the right type checker/build/lint/test suite before handing code back, and telling real bugs apart from sandbox artifacts. |
302
+ | `WebEndToEndTestSkill` | Testing a live web app like a real user would (fill, click, navigate) and verifying via the rendered page, console, and network — not by reading source and assuming. |
303
+ | `ResearchSkill` | Answering questions that need real, current information from the live web — opens pages, cross-checks multiple sources, never trusts one page. |
304
+ | `PresentSkill` | Deciding how to hand back a job's output as files (individually or zipped) and cleaning build artifacts out first. |
305
+
306
+ ## Building from the Base Agent
307
+
308
+ For full control over the MCP server, connection, and client, compose an agent from the base primitives:
309
+
310
+ ```ts
311
+ import {
312
+ OllamaProvider,
313
+ MCPConnection,
314
+ MCPServer,
315
+ MCPClient,
316
+ BaseAgent,
317
+ GetCurrentTimeTool,
318
+ } from "orbitx";
319
+
320
+ const ollamaProvider = new OllamaProvider("gemma4:e4b");
321
+
322
+ const connection = new MCPConnection();
323
+
324
+ const mcpServer = new MCPServer(connection);
325
+ mcpServer.registerTool(GetCurrentTimeTool());
326
+
327
+ const mcpClient = new MCPClient("DEFAULT_ENV", connection);
328
+
329
+ const agent = new BaseAgent({
330
+ aiProvider: ollamaProvider,
331
+ instruction: "",
332
+ mcpClient,
333
+ allowedTools: [GetCurrentTimeTool()],
334
+ });
335
+
336
+ let oldRole: "assistant" | "tool" | "user" | undefined;
337
+
338
+ agent.run("what is current time?", (chunk) => {
339
+ if (oldRole !== chunk.role) {
340
+ process.stdout.write(`\n${chunk.role}: `);
341
+ oldRole = chunk.role;
342
+ }
343
+ process.stdout.write(chunk.content);
344
+ if (chunk.done) {
345
+ process.stdout.write("\n\n");
346
+ oldRole = undefined;
347
+ }
348
+ });
349
+ ```
350
+
351
+ ### IPC Connections
352
+
353
+ Run your MCP server as a separate process and connect to it over an inter-process communication (IPC) channel:
354
+
355
+ ```ts
356
+ import os from "os";
357
+ import { MCPIPCConnection } from "orbitx";
358
+
359
+ const path =
360
+ os.platform() === "win32" ? `\\\\.\\pipe\\mcp_test` : `/tmp/mcp_test.sock`;
361
+
362
+ const ipcConnection = new MCPIPCConnection({ mode: "server", socketPath: path });
363
+ ```
364
+
365
+ ### WS Connections
366
+
367
+ Run your MCP server as a separate process and connect to it over an web-socket communication (WS) channel:
368
+
369
+ ```ts
370
+ import os from "os";
371
+ import { MCPWSConnection } from "orbitx";
372
+
373
+ const wsConnection = new MCPWSConnection({ mode: "server", host: "0.0.0.0", port: 9257, token: "1234" });
374
+ ```
375
+
376
+
377
+ ## Creating a Custom Tool
378
+
379
+ Define your own tools with `MCPTool` to extend an agent's capabilities and integrate with your own ecosystem.
380
+
381
+ ```ts
382
+ import { MCPTool } from "orbitx";
383
+
384
+ export const SumTool = () => new MCPTool({
385
+ name: "math-sum",
386
+ description: "get two numbers and sum them",
387
+ inputs: [
388
+ {
389
+ name: "first",
390
+ type: "number",
391
+ description: "first number",
392
+ required: true,
393
+ },
394
+ {
395
+ name: "second",
396
+ type: "number",
397
+ description: "second number",
398
+ required: true,
399
+ },
400
+ ],
401
+ execute: async (_envID: string, inputs: Record<string, any>) => {
402
+ const { first, second } = inputs;
403
+
404
+ if (typeof first !== "number") {
405
+ throw new Error("first must be a number");
406
+ }
407
+ if (typeof second !== "number") {
408
+ throw new Error("second must be a number");
409
+ }
410
+
411
+ return { output: first + second };
412
+ },
413
+ });
414
+ ```
415
+
416
+ Use it like any built-in tool:
417
+
418
+ ```ts
419
+ const agent = new SimpleAgent({
420
+ aiProvider: ollamaProvider,
421
+ instruction: "You are a helpful assistant.",
422
+ tools: [SumTool()],
423
+ });
424
+ ```
425
+
426
+ ## Creating a Custom Skill
427
+
428
+ A `Skill` bundles instructions with the tools it needs, so an agent that includes it automatically gets both.
429
+
430
+ ```ts
431
+ import { Skill, FsReadFileTool, FsWriteFileTool } from "orbitx";
432
+ import { SumTool } from "./sum-tool.js";
433
+
434
+ export const MathHelperSkill = () => new Skill({
435
+ name: "math-helper",
436
+ description:
437
+ "Use this skill whenever the user asks for arithmetic that should be computed exactly " +
438
+ "rather than estimated from the model's own reasoning — sums, running totals, or " +
439
+ "anything written to a file afterward.",
440
+ instructions: `
441
+ - Always use the math-sum tool for addition instead of computing it yourself.
442
+ - If asked to save a result, write it to disk with fs-write-file and confirm the path back to the user.
443
+ `,
444
+ tools: [
445
+ SumTool(),
446
+ FsReadFileTool(),
447
+ FsWriteFileTool(),
448
+ ],
449
+ });
450
+ ```
451
+
452
+ ```ts
453
+ const agent = new SimpleAgent({
454
+ aiProvider: ollamaProvider,
455
+ instruction: "You are a helpful assistant.",
456
+ skills: [MathHelperSkill()],
457
+ });
458
+ ```
459
+
460
+ ## MCPComputer (Experimental Feature)
461
+
462
+ Spins up a sandboxed Docker container running the MCP server and returns a ready-to-use client connection — no need to manage IPC sockets, ports, or tokens manually.
463
+
464
+ ```typescript
465
+ import { MCPComputer } from "orbitx";
466
+
467
+ const computer = new MCPComputer("/path/to/mount", [3000, 8080]);
468
+ await computer.start();
469
+
470
+ const connection = computer.getConnection();
471
+ await computer.stop();
472
+ ```
473
+
474
+ - **`mountPath`**: host directory mounted into the container
475
+ - **`ports`**: ports to expose, or `"*"` for host network mode (Linux only, or Windows via WSL2)
476
+ - **`getConnection()`**: returns a ready `MCPConnection` (IPC on Linux/macOS, WebSocket on Windows)
477
+ - **`stop()`**: kills the container
478
+
457
479
  Requires the `aliafsordeh/orbitx-sandbox:0.1` image (pull it, or build from the `Dockerfile.sandbox` reference on our GitHub page).