@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.
- package/README.md +245 -64
- package/dist/src/handlers/agent-handler.d.ts +9 -0
- package/dist/src/handlers/agent-handler.d.ts.map +1 -0
- package/dist/src/handlers/agent-handler.js +184 -0
- package/dist/src/handlers/agent-handler.js.map +1 -0
- package/dist/src/handlers/code-handler.d.ts +11 -0
- package/dist/src/handlers/code-handler.d.ts.map +1 -0
- package/dist/src/handlers/code-handler.js +57 -0
- package/dist/src/handlers/code-handler.js.map +1 -0
- package/dist/src/handlers/github-handler.d.ts +10 -0
- package/dist/src/handlers/github-handler.d.ts.map +1 -0
- package/dist/src/handlers/github-handler.js +33 -0
- package/dist/src/handlers/github-handler.js.map +1 -0
- package/dist/src/handlers/llm-handler.d.ts +7 -0
- package/dist/src/handlers/llm-handler.d.ts.map +1 -0
- package/dist/src/handlers/llm-handler.js +50 -0
- package/dist/src/handlers/llm-handler.js.map +1 -0
- package/dist/src/handlers/node-handler.d.ts +17 -0
- package/dist/src/handlers/node-handler.d.ts.map +1 -0
- package/dist/src/handlers/node-handler.js +47 -0
- package/dist/src/handlers/node-handler.js.map +1 -0
- package/dist/src/handlers/python-handler.d.ts +10 -0
- package/dist/src/handlers/python-handler.d.ts.map +1 -0
- package/dist/src/handlers/python-handler.js +34 -0
- package/dist/src/handlers/python-handler.js.map +1 -0
- package/dist/src/handlers/shell-handler.d.ts +7 -0
- package/dist/src/handlers/shell-handler.d.ts.map +1 -0
- package/dist/src/handlers/shell-handler.js +34 -0
- package/dist/src/handlers/shell-handler.js.map +1 -0
- package/dist/src/handlers/web-handlers.d.ts +8 -0
- package/dist/src/handlers/web-handlers.d.ts.map +1 -0
- package/dist/src/handlers/web-handlers.js +37 -0
- package/dist/src/handlers/web-handlers.js.map +1 -0
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/presets/apply.d.ts +13 -0
- package/dist/src/presets/apply.d.ts.map +1 -0
- package/dist/src/presets/apply.js +11 -0
- package/dist/src/presets/apply.js.map +1 -0
- package/dist/src/presets/builtins.d.ts +92 -0
- package/dist/src/presets/builtins.d.ts.map +1 -0
- package/dist/src/presets/builtins.js +385 -0
- package/dist/src/presets/builtins.js.map +1 -0
- package/dist/src/presets/index.d.ts +30 -0
- package/dist/src/presets/index.d.ts.map +1 -0
- package/dist/src/presets/index.js +29 -0
- package/dist/src/presets/index.js.map +1 -0
- package/dist/src/presets/resolve.d.ts +26 -0
- package/dist/src/presets/resolve.d.ts.map +1 -0
- package/dist/src/presets/resolve.js +47 -0
- package/dist/src/presets/resolve.js.map +1 -0
- package/dist/src/presets/schema.d.ts +111 -0
- package/dist/src/presets/schema.d.ts.map +1 -0
- package/dist/src/presets/schema.js +127 -0
- package/dist/src/presets/schema.js.map +1 -0
- package/dist/src/ratatoskr.d.ts +14 -5
- package/dist/src/ratatoskr.d.ts.map +1 -1
- package/dist/src/ratatoskr.js +63 -13
- package/dist/src/ratatoskr.js.map +1 -1
- package/dist/src/runner.js +16 -7
- package/dist/src/runner.js.map +1 -1
- package/dist/src/services/heartbeat-sender.d.ts +11 -0
- package/dist/src/services/heartbeat-sender.d.ts.map +1 -1
- package/dist/src/services/heartbeat-sender.js +13 -1
- package/dist/src/services/heartbeat-sender.js.map +1 -1
- package/dist/src/services/task-executor.d.ts +10 -1
- package/dist/src/services/task-executor.d.ts.map +1 -1
- package/dist/src/services/task-executor.js +13 -0
- package/dist/src/services/task-executor.js.map +1 -1
- package/dist/src/services/update-manager.d.ts +39 -0
- package/dist/src/services/update-manager.d.ts.map +1 -0
- package/dist/src/services/update-manager.js +88 -0
- package/dist/src/services/update-manager.js.map +1 -0
- package/dist/src/transports/http-transport.d.ts +3 -2
- package/dist/src/transports/http-transport.d.ts.map +1 -1
- package/dist/src/transports/http-transport.js +3 -1
- package/dist/src/transports/http-transport.js.map +1 -1
- package/dist/src/types/index.d.ts +29 -3
- package/dist/src/types/index.d.ts.map +1 -1
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
# @theaiinc/yggdrasil-ratatoskr
|
|
2
2
|
|
|
3
|
-
Lightweight
|
|
3
|
+
Lightweight runner daemon for Yggdrasil — registers, heartbeats, and executes tasks with configurable capability presets.
|
|
4
4
|
|
|
5
|
-
Ratatoskr runs alongside
|
|
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
|
-
-
|
|
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',
|
|
22
|
+
apiKey: 'my-api-key',
|
|
28
23
|
});
|
|
29
24
|
|
|
30
25
|
await ratatoskr.start();
|
|
31
26
|
```
|
|
32
27
|
|
|
33
|
-
Within seconds, Yggdrasil
|
|
28
|
+
Within seconds, Yggdrasil knows the runner exists, its capabilities, endpoint, and health status.
|
|
34
29
|
|
|
35
|
-
###
|
|
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
|
-
|
|
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
|
|
67
|
+
The `YGGDRASIL_URL` can point to a remote Yggdrasil instance — Ratatoskr connects outbound.
|
|
46
68
|
|
|
47
|
-
##
|
|
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: ['
|
|
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
|
-
|
|
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` |
|
|
75
|
-
| `yggdrasilUrl` | `string` | (required) | Yggdrasil server URL
|
|
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[]` | `[]` |
|
|
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
|
-
##
|
|
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://
|
|
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` | `
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
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()`** —
|
|
118
|
-
2. **Heartbeats** — Sent every N seconds
|
|
119
|
-
3. **Lease** — Each registration has a TTL
|
|
120
|
-
4. **
|
|
121
|
-
5. **
|
|
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
|
-
-
|
|
128
|
-
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
## API Endpoints (Yggdrasil)
|
|
300
|
+
## Public API (Export Summary)
|
|
136
301
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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"}
|