@theaiinc/yggdrasil-ratatoskr 0.1.2 → 0.2.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.
Files changed (82) hide show
  1. package/README.md +245 -64
  2. package/dist/src/handlers/agent-handler.d.ts +9 -0
  3. package/dist/src/handlers/agent-handler.d.ts.map +1 -0
  4. package/dist/src/handlers/agent-handler.js +184 -0
  5. package/dist/src/handlers/agent-handler.js.map +1 -0
  6. package/dist/src/handlers/code-handler.d.ts +11 -0
  7. package/dist/src/handlers/code-handler.d.ts.map +1 -0
  8. package/dist/src/handlers/code-handler.js +57 -0
  9. package/dist/src/handlers/code-handler.js.map +1 -0
  10. package/dist/src/handlers/github-handler.d.ts +10 -0
  11. package/dist/src/handlers/github-handler.d.ts.map +1 -0
  12. package/dist/src/handlers/github-handler.js +33 -0
  13. package/dist/src/handlers/github-handler.js.map +1 -0
  14. package/dist/src/handlers/llm-handler.d.ts +7 -0
  15. package/dist/src/handlers/llm-handler.d.ts.map +1 -0
  16. package/dist/src/handlers/llm-handler.js +50 -0
  17. package/dist/src/handlers/llm-handler.js.map +1 -0
  18. package/dist/src/handlers/node-handler.d.ts +17 -0
  19. package/dist/src/handlers/node-handler.d.ts.map +1 -0
  20. package/dist/src/handlers/node-handler.js +47 -0
  21. package/dist/src/handlers/node-handler.js.map +1 -0
  22. package/dist/src/handlers/python-handler.d.ts +10 -0
  23. package/dist/src/handlers/python-handler.d.ts.map +1 -0
  24. package/dist/src/handlers/python-handler.js +34 -0
  25. package/dist/src/handlers/python-handler.js.map +1 -0
  26. package/dist/src/handlers/shell-handler.d.ts +7 -0
  27. package/dist/src/handlers/shell-handler.d.ts.map +1 -0
  28. package/dist/src/handlers/shell-handler.js +34 -0
  29. package/dist/src/handlers/shell-handler.js.map +1 -0
  30. package/dist/src/handlers/web-handlers.d.ts +8 -0
  31. package/dist/src/handlers/web-handlers.d.ts.map +1 -0
  32. package/dist/src/handlers/web-handlers.js +37 -0
  33. package/dist/src/handlers/web-handlers.js.map +1 -0
  34. package/dist/src/index.d.ts +5 -1
  35. package/dist/src/index.d.ts.map +1 -1
  36. package/dist/src/index.js +4 -0
  37. package/dist/src/index.js.map +1 -1
  38. package/dist/src/presets/apply.d.ts +13 -0
  39. package/dist/src/presets/apply.d.ts.map +1 -0
  40. package/dist/src/presets/apply.js +11 -0
  41. package/dist/src/presets/apply.js.map +1 -0
  42. package/dist/src/presets/builtins.d.ts +92 -0
  43. package/dist/src/presets/builtins.d.ts.map +1 -0
  44. package/dist/src/presets/builtins.js +385 -0
  45. package/dist/src/presets/builtins.js.map +1 -0
  46. package/dist/src/presets/index.d.ts +30 -0
  47. package/dist/src/presets/index.d.ts.map +1 -0
  48. package/dist/src/presets/index.js +29 -0
  49. package/dist/src/presets/index.js.map +1 -0
  50. package/dist/src/presets/resolve.d.ts +26 -0
  51. package/dist/src/presets/resolve.d.ts.map +1 -0
  52. package/dist/src/presets/resolve.js +47 -0
  53. package/dist/src/presets/resolve.js.map +1 -0
  54. package/dist/src/presets/schema.d.ts +111 -0
  55. package/dist/src/presets/schema.d.ts.map +1 -0
  56. package/dist/src/presets/schema.js +127 -0
  57. package/dist/src/presets/schema.js.map +1 -0
  58. package/dist/src/ratatoskr.d.ts +14 -5
  59. package/dist/src/ratatoskr.d.ts.map +1 -1
  60. package/dist/src/ratatoskr.js +63 -13
  61. package/dist/src/ratatoskr.js.map +1 -1
  62. package/dist/src/runner.js +16 -7
  63. package/dist/src/runner.js.map +1 -1
  64. package/dist/src/services/heartbeat-sender.d.ts +11 -0
  65. package/dist/src/services/heartbeat-sender.d.ts.map +1 -1
  66. package/dist/src/services/heartbeat-sender.js +13 -1
  67. package/dist/src/services/heartbeat-sender.js.map +1 -1
  68. package/dist/src/services/task-executor.d.ts +10 -1
  69. package/dist/src/services/task-executor.d.ts.map +1 -1
  70. package/dist/src/services/task-executor.js +13 -0
  71. package/dist/src/services/task-executor.js.map +1 -1
  72. package/dist/src/services/update-manager.d.ts +39 -0
  73. package/dist/src/services/update-manager.d.ts.map +1 -0
  74. package/dist/src/services/update-manager.js +88 -0
  75. package/dist/src/services/update-manager.js.map +1 -0
  76. package/dist/src/transports/http-transport.d.ts +3 -2
  77. package/dist/src/transports/http-transport.d.ts.map +1 -1
  78. package/dist/src/transports/http-transport.js +3 -1
  79. package/dist/src/transports/http-transport.js.map +1 -1
  80. package/dist/src/types/index.d.ts +29 -3
  81. package/dist/src/types/index.d.ts.map +1 -1
  82. package/package.json +9 -4
package/README.md CHANGED
@@ -1,15 +1,10 @@
1
1
  # @theaiinc/yggdrasil-ratatoskr
2
2
 
3
- Lightweight discovery and heartbeat daemon for Yggdrasil runner registration.
3
+ Lightweight runner daemon for Yggdrasil registers, heartbeats, and executes tasks with configurable capability presets.
4
4
 
5
- Ratatoskr runs alongside an agent runner (any machine, anywhere) and continuously informs Yggdrasil about:
5
+ Ratatoskr runs alongside any agent (Docker container, laptop, server) and continuously informs [Yggdrasil](https://www.npmjs.com/package/@theaiinc/yggdrasil) about runner availability, capabilities, health, and task execution. It can execute tasks itself using its built-in LLM, shell, web, code, and file handlers.
6
6
 
7
- - Runner availability
8
- - Network endpoints
9
- - Capabilities
10
- - Health status
11
- - IP changes
12
- - Shutdown events
7
+ > **Version note**: `@theaiinc/yggdrasil-ratatoskr` and `@theaiinc/yggdrasil` are always released at the same version number.
13
8
 
14
9
  ## Installation
15
10
 
@@ -24,59 +19,89 @@ import { Ratatoskr } from '@theaiinc/yggdrasil-ratatoskr';
24
19
 
25
20
  const ratatoskr = new Ratatoskr({
26
21
  yggdrasilUrl: 'http://localhost:3000',
27
- apiKey: 'my-api-key', // required if Yggdrasil has API_KEYS set
22
+ apiKey: 'my-api-key',
28
23
  });
29
24
 
30
25
  await ratatoskr.start();
31
26
  ```
32
27
 
33
- Within seconds, Yggdrasil automatically knows that the runner exists, where it lives, what it can do, and whether it is healthy.
28
+ Within seconds, Yggdrasil knows the runner exists, its capabilities, endpoint, and health status.
34
29
 
35
- ### Running via CLI (no TypeScript needed)
30
+ ### Capabilities are Presets
31
+
32
+ Capabilities define what a runner can do. Each name is a **preset** that declares its dependencies (apt, npm), environment variables, config files, task handlers, and Docker build-time preparation steps. Presets compose transitively via `dependsOn`.
33
+
34
+ Built-in presets (available by name):
35
+
36
+ | Preset | Description | Handlers | Depends On |
37
+ |--------|-------------|----------|------------|
38
+ | `llm` | LLM inference via OpenAI-compatible API | `llm` | — |
39
+ | `web_search` | Web search and fetch | `web_search`, `web_fetch` | — |
40
+ | `shell` | Shell command execution | `shell` | — |
41
+ | `agent` | Full sub-agent loop (think-act-execute) | `agent` | `llm`, `shell`, `web_search` |
42
+ | `code` | Code generation and verification | `code` | `llm`, `shell`, `python`, `node_runtime` |
43
+ | `python` | Python script execution | `python` | — |
44
+ | `node_runtime` | Node.js script execution | `node` | — |
45
+ | `github_cli` | GitHub CLI operations | `github` | `shell` |
46
+
47
+ ```typescript
48
+ import { Ratatoskr } from '@theaiinc/yggdrasil-ratatoskr';
49
+
50
+ const ratatoskr = new Ratatoskr({
51
+ yggdrasilUrl: 'http://localhost:3000',
52
+ // 'agent' resolves transitively to agent + llm + shell + web_search
53
+ capabilities: ['agent', 'code'],
54
+ });
55
+
56
+ await ratatoskr.start();
57
+ ```
58
+
59
+ ## Running via CLI
36
60
 
37
61
  ```bash
38
62
  YGGDRASIL_URL=http://localhost:3000 \
39
- API_KEY=my-api-key \
40
- RUNNER_NAME=my-laptop \
41
- CAPABILITIES=http,health,browser \
63
+ CAPABILITIES=agent \
42
64
  npx @theaiinc/yggdrasil-ratatoskr
43
65
  ```
44
66
 
45
- The `YGGDRASIL_URL` can point to a remote Yggdrasil over the internet — Ratatoskr connects outbound.
67
+ The `YGGDRASIL_URL` can point to a remote Yggdrasil instance — Ratatoskr connects outbound.
46
68
 
47
- ## Advanced Usage
69
+ ## Full Configuration
48
70
 
49
71
  ```typescript
50
- import { Ratatoskr } from '@theaiinc/yggdrasil-ratatoskr';
51
-
52
72
  const ratatoskr = new Ratatoskr({
53
73
  runnerId: 'runner-a',
54
74
  name: 'MacBook Pro',
55
75
  yggdrasilUrl: 'https://yggdrasil.mycompany.com',
56
76
  apiKey: process.env['YGGDRASIL_API_KEY'],
57
- capabilities: ['browser', 'computer-use', 'llm'],
77
+ capabilities: ['agent', 'code'],
58
78
  heartbeatInterval: 15,
59
79
  leaseTtl: 45,
80
+ taskPollInterval: 10,
60
81
  detectLocalIp: true,
61
82
  detectPublicIp: false,
62
83
  endpointProvider: async () => 'http://192.168.1.5:8080',
63
84
  healthProvider: async () => ({ status: 'healthy' }),
85
+ labels: { region: 'us-east' },
86
+ metadata: { team: 'infra' },
64
87
  });
65
88
 
66
89
  await ratatoskr.start();
67
90
  ```
68
91
 
69
- ## Configuration
92
+ ### Configuration Options
70
93
 
71
94
  | Option | Type | Default | Description |
72
95
  |--------|------|---------|-------------|
73
96
  | `runnerId` | `string` | Auto-generated | Unique runner identifier |
74
- | `name` | `string` | `'unknown'` | Human-readable runner name |
75
- | `yggdrasilUrl` | `string` | (required) | Yggdrasil server URL (local or remote) |
97
+ | `name` | `string` | hostname | Human-readable runner name |
98
+ | `yggdrasilUrl` | `string` | (required) | Yggdrasil server URL |
76
99
  | `apiKey` | `string` | `''` | API key for Yggdrasil auth |
77
- | `capabilities` | `string[]` | `[]` | List of runner capabilities |
100
+ | `capabilities` | `string[]` | `[]` | Capability presets (resolved transitively) |
78
101
  | `heartbeatInterval` | `number` | `30` | Heartbeat interval in seconds |
79
102
  | `leaseTtl` | `number` | `60` | Lease TTL in seconds |
103
+ | `taskPollInterval` | `number` | `10` | Task poll interval in seconds (0 = disable) |
104
+ | `taskHandlers` | `Record<string, TaskHandler>` | `{}` | Custom task handlers (overrides presets) |
80
105
  | `detectLocalIp` | `boolean` | `true` | Auto-detect local IP |
81
106
  | `detectPublicIp` | `boolean` | `false` | Auto-detect public IP |
82
107
  | `endpointProvider` | `() => Promise<string>` | `undefined` | Custom endpoint resolver |
@@ -84,65 +109,221 @@ await ratatoskr.start();
84
109
  | `labels` | `Record<string, string>` | `{}` | Additional labels |
85
110
  | `metadata` | `Record<string, unknown>` | `{}` | Additional metadata |
86
111
 
87
- ## Environment Variables (for CLI runner)
112
+ ## Capability Presets System
113
+
114
+ Presets are the core of Ratatoskr's flexibility. Each preset is a JSON-like descriptor:
115
+
116
+ ```typescript
117
+ import type { CapabilityPreset, CombinedPreset } from '@theaiinc/yggdrasil-ratatoskr';
118
+ ```
119
+
120
+ ### Preset Structure
121
+
122
+ ```typescript
123
+ interface CapabilityPreset {
124
+ name: string;
125
+ description?: string;
126
+ dependsOn?: string[]; // Transitive dependencies
127
+ apt?: string[]; // apt packages (Docker build)
128
+ npm?: string[]; // npm packages (Docker build)
129
+ environment?: Record<string, { // Env vars with defaults
130
+ description: string;
131
+ default?: string;
132
+ required?: boolean;
133
+ }>;
134
+ files?: PresetFile[]; // Config files (Docker build)
135
+ handlers?: Record<string, PresetHandler>; // Task handlers
136
+ prepare?: string[]; // Docker RUN commands
137
+ }
138
+ ```
139
+
140
+ ### Resolving Capabilities
141
+
142
+ ```typescript
143
+ import { resolveCapabilities, applyPresetDefaults } from '@theaiinc/yggdrasil-ratatoskr';
144
+
145
+ const { capabilities, combined } = resolveCapabilities(['agent', 'code']);
146
+ // capabilities => ['agent', 'llm', 'shell', 'web_search', 'code', 'python', 'node_runtime']
147
+
148
+ // Apply environment defaults to process.env
149
+ applyPresetDefaults(combined);
150
+ ```
151
+
152
+ ### Combining Presets
153
+
154
+ ```typescript
155
+ import { combinePresets, generateDockerfile, getPreset } from '@theaiinc/yggdrasil-ratatoskr';
156
+
157
+ const combined = combinePresets(getPreset('llm'), getPreset('shell'));
158
+
159
+ // Generate a Dockerfile with all dependencies baked in
160
+ const dockerfile = generateDockerfile(combined, {
161
+ baseImage: 'node:20-alpine',
162
+ port: 3100,
163
+ });
164
+ ```
165
+
166
+ ### Registering Custom Presets
167
+
168
+ ```typescript
169
+ import { registerPreset, getPreset } from '@theaiinc/yggdrasil-ratatoskr';
170
+ import type { CapabilityPreset } from '@theaiinc/yggdrasil-ratatoskr';
171
+
172
+ registerPreset({
173
+ name: 'my-tool',
174
+ description: 'Custom tool with binary',
175
+ apt: ['ffmpeg'],
176
+ environment: {
177
+ MY_TOOL_PATH: { description: 'Path to config', default: '/etc/my-tool' },
178
+ },
179
+ handlers: {
180
+ my_tool: { module: './handlers/my-tool.js', export: 'myToolHandler' },
181
+ },
182
+ });
183
+
184
+ const preset = getPreset('my-tool');
185
+ ```
186
+
187
+ ## Task Execution
188
+
189
+ Ratatoskr polls Yggdrasil for assigned tasks and executes them using registered handlers. Each capability preset maps to one or more task handlers.
190
+
191
+ ### Built-in Task Output Format
192
+
193
+ All built-in handlers return structured metadata:
194
+
195
+ | Handler | Metadata Fields |
196
+ |---------|----------------|
197
+ | `llm` | `{ model, usage: { input, output }, response }` |
198
+ | `agent` | `{ final_message, model, tokens: { input, output } }` |
199
+ | `shell` | `{ stdout, stderr, code }` |
200
+ | `web_search` | `{ results }` |
201
+ | `web_fetch` | `{ content }` |
202
+ | `python` | `{ stdout, stderr, code }` |
203
+ | `node` | `{ stdout, stderr, code }` |
204
+ | `github` | `{ stdout, stderr, code }` |
205
+
206
+ > **Cost tracking**: Cost is computed server-side by the orchestration layer (e.g. Oasis api-gateway's `PricingService`). Ratatoskr reports the actual model used and token counts — the server applies per-model pricing.
207
+
208
+ ### Custom Task Handlers
209
+
210
+ ```typescript
211
+ import { Ratatoskr } from '@theaiinc/yggdrasil-ratatoskr';
212
+ import type { TaskHandler } from '@theaiinc/yggdrasil-ratatoskr';
213
+
214
+ const echoHandler: TaskHandler = async (task) => {
215
+ return {
216
+ status: 'completed',
217
+ metadata: {
218
+ message: task.metadata?.message || 'hello',
219
+ },
220
+ };
221
+ };
222
+
223
+ const ratatoskr = new Ratatoskr({
224
+ yggdrasilUrl: 'http://localhost:3000',
225
+ capabilities: ['agent'],
226
+ taskHandlers: { echo: echoHandler },
227
+ });
228
+ ```
229
+
230
+ ## Agent Sub-Agent Loop
231
+
232
+ When the `agent` capability is active, Ratatoskr runs a full think-act-execute loop:
233
+
234
+ 1. **Think**: LLM receives the goal + available tools
235
+ 2. **Act**: LLM emits a `tool` block → handler executes
236
+ 3. **Observe**: Result is fed back to the LLM
237
+ 4. **Repeat**: Until the LLM emits a `final` block or max iterations reached
238
+
239
+ The agent has access to: `shell`, `read_file`, `write_file`, `web_search`, `web_fetch`, `python`, `node`, `github` tools.
240
+
241
+ ## Environment Variables (CLI Runner)
88
242
 
89
243
  | Variable | Default | Description |
90
244
  |----------|---------|-------------|
91
- | `YGGDRASIL_URL` | `http://orchestration-controller:3000` | Yggdrasil server URL |
245
+ | `YGGDRASIL_URL` | `http://localhost:3000` | Yggdrasil server URL |
92
246
  | `API_KEY` | `''` | API key for authentication |
93
247
  | `RUNNER_NAME` | `ratatoskr-<hostname>` | Human-readable runner name |
94
- | `CAPABILITIES` | `http,health` | Comma-separated capabilities |
95
-
96
- ## Architecture
248
+ | `CAPABILITIES` | `agent` | Comma-separated capability presets |
249
+ | `LLM_MODEL` | `google/gemma-4-26b-a4b-qat` | Model for LLM inference |
250
+ | `LLM_BASE_URL` | `http://host.docker.internal:1234/v1` | OpenAI-compatible base URL |
251
+ | `LLM_API_KEY` | `''` | API key (optional for local LM Studio) |
252
+ | `AGENT_MAX_TOOL_ITERATIONS` | `25` | Max tool call cycles per agent task |
253
+
254
+ ## Services
255
+
256
+ | Service | Description |
257
+ |---------|-------------|
258
+ | `Registrar` | Runner registration lifecycle |
259
+ | `HeartbeatSender` | Periodic heartbeat sender |
260
+ | `TaskExecutor` | Task polling and execution |
261
+ | `EndpointDetector` | IP/hostname change detection |
262
+ | `HealthMonitor` | Health check orchestration |
263
+ | `LeaseManager` | Lease expiry tracking |
264
+ | `RetryManager` | Exponential backoff retry |
265
+ | `ResourceCollector` | CPU/memory/uptime collection |
266
+ | `UpdateManager` | Self-update on Yggdrasil signal |
267
+ | `HttpTransport` | HTTP transport with API key support |
268
+
269
+ ## Self-Update
270
+
271
+ Ratatoskr can update itself when Yggdrasil signals a pending update via heartbeat response. The update is deferred until all current tasks complete.
97
272
 
273
+ ```typescript
274
+ // Yggdrasil admin API:
275
+ POST /runners/:id/request-update
276
+ { "version": "0.3.0", "command": "npm update -g @theaiinc/yggdrasil-ratatoskr" }
98
277
  ```
99
- yggdrasil-ratatoskr
100
-
101
- ├── runner.ts # CLI entrypoint (reads env vars)
102
- ├── ratatoskr.ts # Main daemon class
103
- ├── types/ # TypeScript interfaces and enums
104
- ├── transports/ # Transport abstraction (HTTP)
105
- │ └── http-transport.ts # HTTP transport with API key support
106
- └── services/
107
- ├── registrar.ts # Runner registration lifecycle
108
- ├── heartbeat-sender.ts # Periodic heartbeat sender
109
- ├── endpoint-detector.ts # IP/hostname change detection
110
- ├── health-monitor.ts # Health check orchestration
111
- ├── lease-manager.ts # Lease expiry tracking
112
- └── retry-manager.ts # Exponential backoff retry
113
- ```
278
+
279
+ On the next heartbeat, the runner receives the `pendingUpdate` field, finishes its tasks, runs the update command, and restarts.
114
280
 
115
281
  ## How It Works
116
282
 
117
- 1. **`ratatoskr.start()`** — Registers the runner with Yggdrasil, begins heartbeats, starts monitoring IP and lease expiry, and registers shutdown handlers.
118
- 2. **Heartbeats** — Sent every N seconds (configurable) to confirm the runner is alive.
119
- 3. **Lease** — Each registration has a TTL. If Yggdrasil misses enough heartbeats, the runner is marked `offline`.
120
- 4. **IP Changes** — Detected every 10 seconds; if the local IP changes, Yggdrasil is notified via `POST /runners/update`.
121
- 5. **Graceful Shutdown** — On SIGTERM/SIGINT, Ratatoskr deregisters the runner with `POST /runners/offline`.
283
+ 1. **`ratatoskr.start()`** — Resolves capability presets, registers with Yggdrasil, begins heartbeats, starts task polling
284
+ 2. **Heartbeats** — Sent every N seconds with health, resources, and current tasks
285
+ 3. **Lease** — Each registration has a TTL; Yggdrasil marks runner `offline` on timeout
286
+ 4. **Task polling** — Polls `GET /runners/:id/tasks` for tasks in `running` status every N seconds
287
+ 5. **Task execution** — Dispatches to registered handler by task type, reports completion via `PATCH`
288
+ 6. **IP Changes** — Detected every 10 seconds; Yggdrasil notified via `POST /runners/update`
289
+ 7. **Graceful Shutdown** — On SIGTERM/SIGINT, deregisters with `POST /runners/offline`
122
290
 
123
291
  ## Reliability
124
292
 
125
293
  Ratatoskr is designed to survive:
126
-
127
- - Temporary network outages
128
- - Yggdrasil restarts
129
- - IP changes
294
+ - Temporary network outages (exponential backoff)
295
+ - Yggdrasil restarts (automatic re-registration)
296
+ - IP changes (dynamic endpoint updates)
130
297
  - Laptop sleep/wake cycles
131
298
  - Docker container restarts
132
299
 
133
- It uses exponential backoff for retries, persistent runner IDs, and automatic re-registration.
134
-
135
- ## API Endpoints (Yggdrasil)
300
+ ## Public API (Export Summary)
136
301
 
137
- Ratatoskr expects these endpoints on the Yggdrasil server:
138
-
139
- | Method | Path | Purpose |
140
- |--------|------|---------|
141
- | `POST` | `/runners/register` | Register a new runner |
142
- | `POST` | `/runners/heartbeat` | Send a heartbeat |
143
- | `POST` | `/runners/update` | Update runner endpoint |
144
- | `POST` | `/runners/offline` | Deregister a runner |
302
+ ```typescript
303
+ // Classes
304
+ import { Ratatoskr } from '@theaiinc/yggdrasil-ratatoskr';
305
+ import { HttpTransport, EndpointDetector, HealthMonitor, HeartbeatSender,
306
+ LeaseManager, Registrar, RetryManager, ResourceCollector,
307
+ TaskExecutor, UpdateManager } from '@theaiinc/yggdrasil-ratatoskr';
308
+
309
+ // Preset system
310
+ import { registerPreset, getPreset, listPresets, combinePresets,
311
+ generateDockerfile, applyPresetDefaults, resolveCapabilities } from '@theaiinc/yggdrasil-ratatoskr';
312
+ import type { CapabilityPreset, CombinedPreset, DockerfileOptions,
313
+ PresetEnvVar, PresetHandler, PresetFile } from '@theaiinc/yggdrasil-ratatoskr';
314
+
315
+ // Built-in presets
316
+ import { llm, webSearch, shell, agent, codeRunner, python,
317
+ nodeRuntime, githubCli } from '@theaiinc/yggdrasil-ratatoskr';
318
+
319
+ // Types
320
+ import type { Transport, RatatoskrConfig, RatatoskrState, RunnerRegistration,
321
+ HeartbeatPayload, HeartbeatResponse, PendingUpdate,
322
+ HealthResult, SystemResources, RunnerTask,
323
+ TaskHandler, TaskExecutorConfig } from '@theaiinc/yggdrasil-ratatoskr';
324
+ import { RunnerHealth } from '@theaiinc/yggdrasil-ratatoskr';
325
+ ```
145
326
 
146
327
  ## License
147
328
 
148
- MIT
329
+ MIT — © 2026 The AI Inc
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Agent handler — full sub-agent loop (think-act-execute) with LLM + tools.
3
+ *
4
+ * Implements the 'agent' task type. Uses the LLM to plan and execute,
5
+ * calling shell, file, and web tools as needed.
6
+ */
7
+ import type { TaskHandler } from '../types/index.js';
8
+ export declare const agentHandler: TaskHandler;
9
+ //# sourceMappingURL=agent-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-handler.d.ts","sourceRoot":"","sources":["../../../src/handlers/agent-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA6GrD,eAAO,MAAM,YAAY,EAAE,WA4D1B,CAAC"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Agent handler — full sub-agent loop (think-act-execute) with LLM + tools.
3
+ *
4
+ * Implements the 'agent' task type. Uses the LLM to plan and execute,
5
+ * calling shell, file, and web tools as needed.
6
+ */
7
+ import { execSync } from 'child_process';
8
+ import axios from 'axios';
9
+ const LLM_MODEL = process.env.LLM_MODEL || 'google/gemma-4-26b-a4b-qat';
10
+ const LLM_BASE_URL = (process.env.LLM_BASE_URL || 'http://host.docker.internal:1234/v1').replace(/\/$/, '');
11
+ const LLM_API_KEY = process.env.LLM_API_KEY || process.env.OASIS_OPENAI_API_KEY || '';
12
+ const MAX_TOOL_ITERATIONS = parseInt(process.env.AGENT_MAX_TOOL_ITERATIONS || '25', 10);
13
+ const tools = {
14
+ shell: async (command) => {
15
+ try {
16
+ const output = execSync(command, { encoding: 'utf-8', timeout: 30_000, maxBuffer: 10 * 1024 * 1024 });
17
+ return { success: true, output: output.slice(0, 100_000) };
18
+ }
19
+ catch (err) {
20
+ return { success: false, output: err.stdout || '', error: err.stderr || err.message };
21
+ }
22
+ },
23
+ read_file: async (path) => {
24
+ try {
25
+ const fs = await import('fs');
26
+ const content = fs.readFileSync(path, 'utf-8');
27
+ return { success: true, output: content.slice(0, 100_000) };
28
+ }
29
+ catch (err) {
30
+ return { success: false, output: '', error: err.message };
31
+ }
32
+ },
33
+ write_file: async (path, content) => {
34
+ try {
35
+ const fs = await import('fs');
36
+ const pathModule = await import('path');
37
+ fs.mkdirSync(pathModule.dirname(path), { recursive: true });
38
+ fs.writeFileSync(path, content, 'utf-8');
39
+ return { success: true, output: `Written ${content.length} bytes to ${path}` };
40
+ }
41
+ catch (err) {
42
+ return { success: false, output: '', error: err.message };
43
+ }
44
+ },
45
+ web_search: async (query) => {
46
+ try {
47
+ const { data } = await axios.get(process.env.WEB_SEARCH_API || 'https://api.duckduckgo.com', {
48
+ params: { q: query, format: 'json' }, timeout: 15_000,
49
+ });
50
+ const results = data.AbstractText || (data.RelatedTopics || []).slice(0, 5).map((r) => r.Text || r.FirstURL).join('\n');
51
+ return { success: true, output: results || 'No results.' };
52
+ }
53
+ catch (err) {
54
+ return { success: false, output: '', error: err.message };
55
+ }
56
+ },
57
+ web_fetch: async (url) => {
58
+ try {
59
+ const { data } = await axios.get(url, { timeout: 15_000 });
60
+ const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
61
+ return { success: true, output: text.slice(0, 100_000) };
62
+ }
63
+ catch (err) {
64
+ return { success: false, output: '', error: err.message };
65
+ }
66
+ },
67
+ python: async (script) => {
68
+ try {
69
+ const { pythonHandler } = await import('./python-handler.js');
70
+ const result = await pythonHandler({ script });
71
+ return { success: result.code === 0, output: result.stdout.slice(0, 100_000), error: result.stderr || '' };
72
+ }
73
+ catch (err) {
74
+ return { success: false, output: '', error: err.message };
75
+ }
76
+ },
77
+ node: async (script) => {
78
+ try {
79
+ const { nodeHandler } = await import('./node-handler.js');
80
+ const result = await nodeHandler({ script });
81
+ return { success: result.code === 0, output: result.stdout.slice(0, 100_000), error: result.stderr || '' };
82
+ }
83
+ catch (err) {
84
+ return { success: false, output: '', error: err.message };
85
+ }
86
+ },
87
+ github: async (command, ...args) => {
88
+ try {
89
+ const { githubHandler } = await import('./github-handler.js');
90
+ const result = await githubHandler({ command, args });
91
+ return { success: result.code === 0, output: result.stdout.slice(0, 100_000), error: result.stderr || '' };
92
+ }
93
+ catch (err) {
94
+ return { success: false, output: '', error: err.message };
95
+ }
96
+ },
97
+ };
98
+ const toolNames = Object.keys(tools);
99
+ async function callLlm(messages) {
100
+ const { data } = await axios.post(`${LLM_BASE_URL}/chat/completions`, { model: LLM_MODEL, messages, max_tokens: 4096, temperature: 0.3 }, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${LLM_API_KEY}` }, timeout: 120_000 });
101
+ return {
102
+ content: data.choices?.[0]?.message?.content || '',
103
+ model: data.model || LLM_MODEL,
104
+ inputTokens: data.usage?.prompt_tokens || 0,
105
+ outputTokens: data.usage?.completion_tokens || 0,
106
+ };
107
+ }
108
+ export const agentHandler = async (task) => {
109
+ const goal = task.metadata?.goal || task.type || 'agent task';
110
+ if (!LLM_API_KEY) {
111
+ return { status: 'completed', metadata: { final_message: `No LLM configured. Goal: "${goal.slice(0, 120)}"`, tokens: { input: 0, output: 0 } } };
112
+ }
113
+ const messages = [
114
+ {
115
+ role: 'system',
116
+ content: [
117
+ 'You are a capable sub-agent. Your job is to accomplish the given goal.',
118
+ 'Available tools:', ...toolNames.map((n) => ` - ${n}`),
119
+ '',
120
+ 'To use a tool:',
121
+ '```tool',
122
+ '{"name": "<tool_name>", "arguments": {"arg1": "value", ...}}',
123
+ '```',
124
+ '',
125
+ 'When done:',
126
+ '```final',
127
+ '{"result": "your answer", "summary": "brief summary"}',
128
+ '```',
129
+ ].join('\n'),
130
+ },
131
+ { role: 'user', content: `Goal: ${goal}` },
132
+ ];
133
+ let totalInput = 0, totalOutput = 0, finalAnswer = '', lastModel = LLM_MODEL;
134
+ for (let iter = 0; iter < MAX_TOOL_ITERATIONS; iter++) {
135
+ const llm = await callLlm(messages);
136
+ totalInput += llm.inputTokens;
137
+ totalOutput += llm.outputTokens;
138
+ lastModel = llm.model;
139
+ const content = llm.content.trim();
140
+ const finalMatch = content.match(/```final\n([\s\S]*?)```/);
141
+ if (finalMatch) {
142
+ const json = finalMatch[1];
143
+ try {
144
+ finalAnswer = json ? (JSON.parse(json).result || JSON.parse(json).summary || content) : content;
145
+ }
146
+ catch {
147
+ finalAnswer = content;
148
+ }
149
+ break;
150
+ }
151
+ const toolMatch = content.match(/```tool\n([\s\S]*?)```/);
152
+ if (toolMatch) {
153
+ const match = toolMatch[1];
154
+ let call;
155
+ if (!match) {
156
+ messages.push({ role: 'assistant', content }, { role: 'user', content: 'Empty tool block.' });
157
+ continue;
158
+ }
159
+ try {
160
+ call = JSON.parse(match);
161
+ }
162
+ catch {
163
+ messages.push({ role: 'assistant', content }, { role: 'user', content: 'Invalid JSON. Use valid JSON.' });
164
+ continue;
165
+ }
166
+ const fn = tools[call.name];
167
+ if (!fn) {
168
+ messages.push({ role: 'assistant', content }, { role: 'user', content: `Unknown tool: ${call.name}. Available: ${toolNames.join(', ')}` });
169
+ continue;
170
+ }
171
+ const result = await fn(...Object.values(call.arguments));
172
+ messages.push({ role: 'assistant', content }, { role: 'user', content: result.success ? `Output:\n${result.output}` : `Error: ${result.error || result.output}` });
173
+ continue;
174
+ }
175
+ messages.push({ role: 'assistant', content }, { role: 'user', content: 'Respond with a `tool` or `final` block.' });
176
+ }
177
+ if (!finalAnswer)
178
+ finalAnswer = 'Max iterations reached without final answer.';
179
+ return {
180
+ status: 'completed',
181
+ metadata: { final_message: finalAnswer, model: lastModel, tokens: { input: totalInput, output: totalOutput } },
182
+ };
183
+ };
184
+ //# sourceMappingURL=agent-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-handler.js","sourceRoot":"","sources":["../../../src/handlers/agent-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Code handler — generates code via LLM with a coding-optimised profile.
3
+ *
4
+ * Uses an LLM (default: gemma4:12b via Ollama) to write code for a given
5
+ * task description. Returns the generated source code as the result.
6
+ *
7
+ * This is NOT a sandbox executor — code runs in the user's dev environment.
8
+ */
9
+ import type { TaskHandler } from '../types/index.js';
10
+ export declare const codeHandler: TaskHandler;
11
+ //# sourceMappingURL=code-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-handler.d.ts","sourceRoot":"","sources":["../../../src/handlers/code-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAkBrD,eAAO,MAAM,WAAW,EAAE,WAgDzB,CAAC"}