@agentxjs/runtime 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Deepractice
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,598 @@
1
+ # @agentxjs/runtime
2
+
3
+ > Complete Runtime implementation for AI Agents with Claude SDK integration
4
+
5
+ ## Overview
6
+
7
+ `@agentxjs/runtime` provides the complete runtime infrastructure for AI agents, including:
8
+
9
+ - **SystemBus** - Event-driven communication backbone
10
+ - **Container** - Agent lifecycle management
11
+ - **Environment** (Receptor + Effector) - External world interface (Claude SDK)
12
+ - **Session** - Message persistence
13
+ - **Persistence** - Storage layer (SQLite, Memory)
14
+
15
+ **Key Features:**
16
+
17
+ - **Event-Driven Architecture** - All operations via command events
18
+ - **Claude SDK Integration** - Production-ready ClaudeEnvironment
19
+ - **Pluggable Storage** - SQLite, Memory, or custom backends
20
+ - **Type-Safe Commands** - Request/response pattern with full typing
21
+ - **Cross-Platform** - Works in Node.js (Browser support via agentxjs)
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pnpm add @agentxjs/runtime
27
+ ```
28
+
29
+ **Dependencies:**
30
+
31
+ - `@anthropic-ai/claude-agent-sdk` - Claude API client
32
+ - `better-sqlite3` - SQLite database (optional, for persistence)
33
+ - `unstorage` - Unified storage layer
34
+
35
+ ---
36
+
37
+ ## Quick Start
38
+
39
+ ### Minimal Setup
40
+
41
+ ```typescript
42
+ import { createRuntime } from "@agentxjs/runtime";
43
+
44
+ // Minimal - uses environment variable ANTHROPIC_API_KEY
45
+ const runtime = createRuntime();
46
+
47
+ // Subscribe to events
48
+ runtime.on("text_delta", (e) => {
49
+ console.log(e.data.text);
50
+ });
51
+
52
+ // Create container
53
+ const containerRes = await runtime.request("container_create_request", {
54
+ containerId: "my-container",
55
+ });
56
+
57
+ // Run agent
58
+ const agentRes = await runtime.request("agent_run_request", {
59
+ containerId: "my-container",
60
+ config: {
61
+ name: "Assistant",
62
+ systemPrompt: "You are a helpful assistant",
63
+ },
64
+ });
65
+
66
+ // Send message
67
+ await runtime.request("agent_receive_request", {
68
+ agentId: agentRes.data.agentId,
69
+ content: "Hello!",
70
+ });
71
+
72
+ // Cleanup
73
+ await runtime.dispose();
74
+ ```
75
+
76
+ ### With Configuration
77
+
78
+ ```typescript
79
+ import { createRuntime, createPersistence } from "@agentxjs/runtime";
80
+
81
+ const runtime = createRuntime({
82
+ // LLM configuration
83
+ llm: {
84
+ apiKey: process.env.ANTHROPIC_API_KEY,
85
+ baseUrl: "https://api.anthropic.com",
86
+ },
87
+
88
+ // Persistence
89
+ persistence: createPersistence({
90
+ driver: "sqlite",
91
+ options: {
92
+ filename: "./data.db",
93
+ },
94
+ }),
95
+
96
+ // Logger
97
+ logger: {
98
+ level: "info",
99
+ enableTimestamp: true,
100
+ },
101
+ });
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Architecture
107
+
108
+ ### System Overview
109
+
110
+ ```text
111
+ ┌────────────────────────────────────────────────────────────────┐
112
+ │ Runtime │
113
+ ├────────────────────────────────────────────────────────────────┤
114
+ │ │
115
+ │ ┌─────────────────────────────────────────────────────────┐ │
116
+ │ │ SystemBus │ │
117
+ │ │ (Central event bus - all communication flows here) │ │
118
+ │ └──────────────────────┬──────────────────────────────────┘ │
119
+ │ │ │
120
+ │ ┌───────────────┼───────────────┐ │
121
+ │ │ │ │ │
122
+ │ ▼ ▼ ▼ │
123
+ │ ┌─────────────┐ ┌──────────┐ ┌────────────┐ │
124
+ │ │Environment │ │Container │ │Persistence │ │
125
+ │ │ │ │ │ │ │ │
126
+ │ │ Receptor │ │ Agent1 │ │ SQLite │ │
127
+ │ │ Effector │ │ Agent2 │ │ Images │ │
128
+ │ │ (Claude SDK)│ │ Agent3 │ │ Sessions │ │
129
+ │ └─────────────┘ └──────────┘ └────────────┘ │
130
+ │ │
131
+ └────────────────────────────────────────────────────────────────┘
132
+ ```
133
+
134
+ ### Component Responsibilities
135
+
136
+ | Component | Role | Examples |
137
+ | --------------- | ------------------------ | --------------------------------- |
138
+ | **SystemBus** | Event distribution | Emit, subscribe, request/response |
139
+ | **Environment** | External world interface | Claude API calls, streaming |
140
+ | **Container** | Agent lifecycle | Create, destroy, manage agents |
141
+ | **Session** | Message persistence | Save/load conversation history |
142
+ | **Persistence** | Storage backend | SQLite, Memory, custom |
143
+
144
+ ---
145
+
146
+ ## SystemBus - Event Backbone
147
+
148
+ All Runtime operations go through the SystemBus using **command events**.
149
+
150
+ ### Request/Response Pattern
151
+
152
+ ```typescript
153
+ // Type-safe request
154
+ const response = await runtime.request("container_create_request", {
155
+ containerId: "my-container",
156
+ });
157
+
158
+ // Response is fully typed
159
+ console.log(response.data.containerId); // ✓ TypeScript knows this exists
160
+ ```
161
+
162
+ ### Event Subscription
163
+
164
+ ```typescript
165
+ // Subscribe to specific event type
166
+ runtime.on("text_delta", (event) => {
167
+ console.log(event.data.text);
168
+ });
169
+
170
+ // Subscribe to multiple types
171
+ runtime.on(["message_start", "message_stop"], (event) => {
172
+ console.log(event.type);
173
+ });
174
+
175
+ // Subscribe to all events
176
+ runtime.onAny((event) => {
177
+ console.log(event.type, event.data);
178
+ });
179
+
180
+ // Unsubscribe
181
+ const unsubscribe = runtime.on("text_delta", handler);
182
+ unsubscribe();
183
+ ```
184
+
185
+ ### Available Commands
186
+
187
+ #### Container Commands
188
+
189
+ ```typescript
190
+ // Create container
191
+ const res = await runtime.request("container_create_request", {
192
+ containerId: "my-container",
193
+ });
194
+
195
+ // Destroy container
196
+ await runtime.request("container_destroy_request", {
197
+ containerId: "my-container",
198
+ });
199
+ ```
200
+
201
+ #### Agent Commands
202
+
203
+ ```typescript
204
+ // Run agent
205
+ const res = await runtime.request("agent_run_request", {
206
+ containerId: "my-container",
207
+ config: {
208
+ name: "Assistant",
209
+ systemPrompt: "You are helpful",
210
+ },
211
+ });
212
+
213
+ // Send message
214
+ await runtime.request("agent_receive_request", {
215
+ agentId: res.data.agentId,
216
+ content: "Hello!",
217
+ });
218
+
219
+ // Interrupt agent
220
+ await runtime.request("agent_interrupt_request", {
221
+ agentId: res.data.agentId,
222
+ });
223
+
224
+ // Destroy agent
225
+ await runtime.request("agent_destroy_request", {
226
+ agentId: res.data.agentId,
227
+ });
228
+ ```
229
+
230
+ #### Session Commands
231
+
232
+ ```typescript
233
+ // Create session
234
+ await runtime.request("session_create_request", {
235
+ sessionId: "session_123",
236
+ containerId: "my-container",
237
+ agentId: "agent_123",
238
+ });
239
+
240
+ // Get session
241
+ const res = await runtime.request("session_get_request", {
242
+ sessionId: "session_123",
243
+ });
244
+
245
+ // Delete session
246
+ await runtime.request("session_delete_request", {
247
+ sessionId: "session_123",
248
+ });
249
+ ```
250
+
251
+ ### Direct Command Emission
252
+
253
+ For advanced use cases:
254
+
255
+ ```typescript
256
+ // Emit command directly (fire and forget)
257
+ runtime.emitCommand("agent_receive_request", {
258
+ requestId: "req_123",
259
+ agentId: "agent_123",
260
+ content: "Hello!",
261
+ });
262
+
263
+ // Listen for response
264
+ runtime.onCommand("agent_receive_response", (event) => {
265
+ if (event.data.requestId === "req_123") {
266
+ console.log("Response:", event.data);
267
+ },
268
+ });
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Environment - External World Interface
274
+
275
+ Environment connects Runtime to the external world (Claude API).
276
+
277
+ ### ClaudeEnvironment
278
+
279
+ Built-in implementation using `@anthropic-ai/claude-agent-sdk`:
280
+
281
+ ```typescript
282
+ import { createRuntime } from "@agentxjs/runtime";
283
+
284
+ const runtime = createRuntime({
285
+ llm: {
286
+ apiKey: process.env.ANTHROPIC_API_KEY,
287
+ baseUrl: "https://api.anthropic.com",
288
+ },
289
+ });
290
+ ```
291
+
292
+ ### Architecture
293
+
294
+ ```text
295
+ ┌────────────────────────────────────────────────────────────┐
296
+ │ Environment │
297
+ ├────────────────────────────────────────────────────────────┤
298
+ │ │
299
+ │ Receptor (Perceives external world → emits to SystemBus) │
300
+ │ │ │
301
+ │ │ Claude API Streaming Response │
302
+ │ ▼ │
303
+ │ ┌──────────────────────────────────────────────────────┐ │
304
+ │ │ Transforms Claude SDK events → DriveableEvent │ │
305
+ │ │ (message_delta, tool_use, etc.) │ │
306
+ │ └──────────────────────────────────────────────────────┘ │
307
+ │ │ │
308
+ │ │ emit to SystemBus │
309
+ │ ▼ │
310
+ │ SystemBus │
311
+ │ │ │
312
+ │ │ subscribe │
313
+ │ ▼ │
314
+ │ Effector (Subscribes to SystemBus → acts on external world)│
315
+ │ │ │
316
+ │ │ Executes tool calls │
317
+ │ ▼ │
318
+ │ External Tools (MCP, filesystem, etc.) │
319
+ │ │
320
+ └────────────────────────────────────────────────────────────┘
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Container - Agent Lifecycle
326
+
327
+ Container manages multiple agents:
328
+
329
+ ```typescript
330
+ // Via command events (recommended)
331
+ const res = await runtime.request("container_create_request", {
332
+ containerId: "my-container",
333
+ });
334
+
335
+ // Run agents in container
336
+ const agent1 = await runtime.request("agent_run_request", {
337
+ containerId: "my-container",
338
+ config: { name: "Agent1" },
339
+ });
340
+
341
+ const agent2 = await runtime.request("agent_run_request", {
342
+ containerId: "my-container",
343
+ config: { name: "Agent2" },
344
+ });
345
+
346
+ // Destroy container (destroys all agents)
347
+ await runtime.request("container_destroy_request", {
348
+ containerId: "my-container",
349
+ });
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Persistence - Storage Layer
355
+
356
+ ### Built-in Storage Backends
357
+
358
+ #### SQLite (Production)
359
+
360
+ ```typescript
361
+ import { createRuntime, createPersistence } from "@agentxjs/runtime";
362
+
363
+ const runtime = createRuntime({
364
+ persistence: createPersistence({
365
+ driver: "sqlite",
366
+ options: {
367
+ filename: "./data.db",
368
+ },
369
+ }),
370
+ });
371
+ ```
372
+
373
+ #### Memory (Development)
374
+
375
+ ```typescript
376
+ const runtime = createRuntime({
377
+ persistence: createPersistence({
378
+ driver: "memory",
379
+ }),
380
+ });
381
+ ```
382
+
383
+ ### Storage Schema
384
+
385
+ Persistence stores:
386
+
387
+ - **Images** - Agent snapshots with conversation history
388
+ - **Containers** - Container metadata
389
+ - **Sessions** - Message history per agent
390
+
391
+ ```typescript
392
+ // Save agent image
393
+ const image = await runtime.request("image_snapshot_request", {
394
+ agentId: "agent_123",
395
+ });
396
+
397
+ // Resume from image
398
+ const agent = await runtime.request("image_resume_request", {
399
+ imageId: image.data.imageId,
400
+ });
401
+ ```
402
+
403
+ ---
404
+
405
+ ## Advanced Usage
406
+
407
+ ### Custom Persistence Backend
408
+
409
+ ```typescript
410
+ import { type StorageDriver } from "@agentxjs/runtime";
411
+
412
+ const customDriver: StorageDriver = {
413
+ async getItem(key) {
414
+ // Fetch from your backend
415
+ },
416
+ async setItem(key, value) {
417
+ // Save to your backend
418
+ },
419
+ async removeItem(key) {
420
+ // Delete from your backend
421
+ },
422
+ async getKeys(base) {
423
+ // List keys with prefix
424
+ },
425
+ async clear() {
426
+ // Clear all data
427
+ },
428
+ };
429
+
430
+ const runtime = createRuntime({
431
+ persistence: createPersistence({
432
+ driver: customDriver,
433
+ }),
434
+ });
435
+ ```
436
+
437
+ ### Event Filtering
438
+
439
+ ```typescript
440
+ // Filter events by agent
441
+ runtime.on(
442
+ "text_delta",
443
+ (event) => {
444
+ console.log(event.data.text);
445
+ },
446
+ {
447
+ filter: (event) => event.context?.agentId === "agent_123",
448
+ }
449
+ );
450
+
451
+ // Priority execution
452
+ runtime.on("message_stop", handler, {
453
+ priority: 10, // Higher priority runs first
454
+ });
455
+
456
+ // One-time subscription
457
+ runtime.once("agent_created", (event) => {
458
+ console.log("Agent created:", event.data.agentId);
459
+ });
460
+ ```
461
+
462
+ ---
463
+
464
+ ## Testing
465
+
466
+ Runtime is designed for easy testing:
467
+
468
+ ```typescript
469
+ import { createRuntime, createPersistence } from "@agentxjs/runtime";
470
+ import { describe, it, expect } from "vitest";
471
+
472
+ describe("Runtime", () => {
473
+ it("creates and runs agent", async () => {
474
+ const runtime = createRuntime({
475
+ llm: {
476
+ apiKey: "test-key",
477
+ },
478
+ persistence: createPersistence({ driver: "memory" }),
479
+ });
480
+
481
+ // Create container
482
+ const containerRes = await runtime.request("container_create_request", {
483
+ containerId: "test-container",
484
+ });
485
+
486
+ expect(containerRes.data.containerId).toBe("test-container");
487
+
488
+ // Run agent
489
+ const agentRes = await runtime.request("agent_run_request", {
490
+ containerId: "test-container",
491
+ config: { name: "TestAgent" },
492
+ });
493
+
494
+ expect(agentRes.data.name).toBe("TestAgent");
495
+
496
+ await runtime.dispose();
497
+ });
498
+ });
499
+ ```
500
+
501
+ ---
502
+
503
+ ## Design Decisions
504
+
505
+ ### Why Event-Driven?
506
+
507
+ Event-driven architecture enables:
508
+
509
+ 1. **Decoupling** - Components communicate via events, not direct calls
510
+ 2. **Extensibility** - Add new components without modifying existing ones
511
+ 3. **Testability** - Mock events instead of entire components
512
+ 4. **Observability** - All operations are visible as events
513
+
514
+ ### Why SystemBus?
515
+
516
+ SystemBus provides:
517
+
518
+ 1. **Single Source of Truth** - All communication flows through one point
519
+ 2. **Type Safety** - Commands are fully typed
520
+ 3. **Request/Response** - Async operations with correlation IDs
521
+ 4. **Priority/Filtering** - Advanced subscription options
522
+
523
+ ### Why Separate Environment?
524
+
525
+ Environment abstraction allows:
526
+
527
+ 1. **Multiple Backends** - Claude, OpenAI, local models
528
+ 2. **Testing** - Mock Environment in tests
529
+ 3. **Cross-Platform** - Different implementations for Node.js, Browser
530
+ 4. **Clear Boundary** - External world vs. internal logic
531
+
532
+ ---
533
+
534
+ ## Configuration Reference
535
+
536
+ ```typescript
537
+ interface RuntimeConfig {
538
+ // LLM configuration
539
+ llm?: {
540
+ apiKey?: string; // Default: process.env.ANTHROPIC_API_KEY
541
+ baseUrl?: string; // Default: "https://api.anthropic.com"
542
+ };
543
+
544
+ // Persistence
545
+ persistence?: Persistence;
546
+
547
+ // Logger
548
+ logger?: {
549
+ level?: LogLevel;
550
+ enableTimestamp?: boolean;
551
+ enableColor?: boolean;
552
+ };
553
+ }
554
+ ```
555
+
556
+ ---
557
+
558
+ ## Environment Variables
559
+
560
+ ```bash
561
+ # Required
562
+ ANTHROPIC_API_KEY=sk-ant-xxxxx
563
+
564
+ # Optional
565
+ ANTHROPIC_BASE_URL=https://api.anthropic.com # Custom endpoint
566
+ LOG_LEVEL=info # debug, info, warn, error
567
+ ```
568
+
569
+ ---
570
+
571
+ ## Package Dependencies
572
+
573
+ ```text
574
+ @agentxjs/types Type definitions
575
+
576
+ @agentxjs/common Logger facade
577
+
578
+ @agentxjs/agent AgentEngine
579
+
580
+ @agentxjs/runtime This package (Runtime + Environment + Persistence)
581
+
582
+ agentxjs High-level unified API
583
+ ```
584
+
585
+ ---
586
+
587
+ ## Related Packages
588
+
589
+ - **[@agentxjs/types](../types)** - Type definitions
590
+ - **[@agentxjs/common](../common)** - Logger facade
591
+ - **[@agentxjs/agent](../agent)** - AgentEngine
592
+ - **[agentxjs](../agentx)** - High-level unified API
593
+
594
+ ---
595
+
596
+ ## License
597
+
598
+ MIT