agentxjs 2.7.0 → 2.8.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * AgentX Server Implementation (JSON-RPC 2.0)\n *\n * Creates a WebSocket server that:\n * 1. Accepts client connections\n * 2. Handles JSON-RPC requests directly via CommandHandler\n * 3. Broadcasts stream events as JSON-RPC notifications\n *\n * Message Types:\n * - RPC Request (has id): Client → Server → Client (direct response)\n * - RPC Notification (no id): Server → Client (stream events)\n */\n\nimport type { CreateDriver } from \"@agentxjs/core/driver\";\nimport type { BusEvent, SystemEvent } from \"@agentxjs/core/event\";\nimport type { ChannelConnection } from \"@agentxjs/core/network\";\nimport {\n createErrorResponse,\n createStreamEvent,\n createSuccessResponse,\n isNotification,\n isRequest,\n parseMessage,\n RpcErrorCodes,\n type RpcMethod,\n} from \"@agentxjs/core/network\";\nimport type { AgentXPlatform } from \"@agentxjs/core/runtime\";\nimport { createAgentXRuntime } from \"@agentxjs/core/runtime\";\nimport { createLogger } from \"@deepracticex/logger\";\nimport { CommandHandler } from \"./CommandHandler\";\nimport type { AgentXServer } from \"./types\";\n\nconst logger = createLogger(\"server/Server\");\n\n/**\n * Connection state\n */\ninterface ConnectionState {\n connection: ChannelConnection;\n subscribedTopics: Set<string>;\n}\n\n/**\n * Server configuration (supports both immediate and deferred platforms)\n */\nexport interface ServerConfig {\n /**\n * AgentX Platform — must provide `channelServer` for accepting WebSocket connections.\n */\n platform: AgentXPlatform;\n\n /**\n * LLM Driver factory function - creates Driver per Agent\n */\n createDriver: CreateDriver;\n\n /**\n * Port to listen on (standalone mode)\n */\n port?: number;\n\n /**\n * Host to bind to (default: \"0.0.0.0\")\n */\n host?: string;\n\n /**\n * Existing HTTP server to attach to (attached mode)\n */\n server?: import(\"@agentxjs/core/network\").MinimalHTTPServer;\n\n /**\n * WebSocket path when attached (default: \"/ws\")\n */\n wsPath?: string;\n\n /**\n * Enable debug logging\n */\n debug?: boolean;\n}\n\n/**\n * Create an AgentX server\n */\nexport async function createServer(config: ServerConfig): Promise<AgentXServer> {\n const { wsPath = \"/ws\" } = config;\n const platform = config.platform;\n\n // Create runtime from platform + driver\n const runtime = createAgentXRuntime(platform, config.createDriver);\n\n // Get channel server from platform\n const wsServer = platform.channelServer;\n if (!wsServer) {\n throw new Error(\"Platform must provide channelServer for server mode\");\n }\n\n // Create command handler (no longer needs eventBus)\n const commandHandler = new CommandHandler(runtime);\n\n // Track connections\n const connections = new Map<string, ConnectionState>();\n\n /**\n * Subscribe connection to a topic\n */\n function subscribeToTopic(connectionId: string, topic: string): void {\n const state = connections.get(connectionId);\n if (!state || state.subscribedTopics.has(topic)) return;\n\n state.subscribedTopics.add(topic);\n logger.debug(\"Connection subscribed to topic\", { connectionId, topic });\n }\n\n /**\n * Check if event should be sent to connection based on subscriptions\n */\n function shouldSendToConnection(state: ConnectionState, event: BusEvent): boolean {\n // Skip internal driver events\n if (event.source === \"driver\" && event.intent !== \"notification\") {\n return false;\n }\n\n // Skip command events (they are handled via RPC, not broadcast)\n if (event.source === \"command\") {\n return false;\n }\n\n // Check if subscribed to event's session\n const eventWithContext = event as BusEvent & { context?: { sessionId?: string } };\n const sessionId = eventWithContext.context?.sessionId;\n if (sessionId && state.subscribedTopics.has(sessionId)) {\n return true;\n }\n\n // Send to global subscribers\n return state.subscribedTopics.has(\"global\");\n }\n\n /**\n * Send JSON-RPC response to a specific connection\n */\n function sendResponse(connection: ChannelConnection, id: string | number, result: unknown): void {\n const response = createSuccessResponse(id, result);\n connection.send(JSON.stringify(response));\n }\n\n /**\n * Send JSON-RPC error to a specific connection\n */\n function sendError(\n connection: ChannelConnection,\n id: string | number | null,\n code: number,\n message: string\n ): void {\n const response = createErrorResponse(id, code, message);\n connection.send(JSON.stringify(response));\n }\n\n // Handle new connections\n wsServer.onConnection((connection) => {\n const state: ConnectionState = {\n connection,\n subscribedTopics: new Set([\"global\"]),\n };\n connections.set(connection.id, state);\n\n logger.info(\"Client connected\", {\n connectionId: connection.id,\n totalConnections: connections.size,\n });\n\n // Handle messages from client\n connection.onMessage(async (message) => {\n try {\n const parsed = parseMessage(message);\n\n // Handle single message (not batch)\n if (!Array.isArray(parsed)) {\n await handleParsedMessage(connection, state, parsed);\n } else {\n // Handle batch (not common, but supported by JSON-RPC 2.0)\n for (const item of parsed) {\n await handleParsedMessage(connection, state, item);\n }\n }\n } catch (err) {\n logger.error(\"Failed to parse message\", { error: (err as Error).message });\n sendError(connection, null, RpcErrorCodes.PARSE_ERROR, \"Parse error\");\n }\n });\n\n // Cleanup on disconnect\n connection.onClose(() => {\n connections.delete(connection.id);\n logger.info(\"Client disconnected\", {\n connectionId: connection.id,\n totalConnections: connections.size,\n });\n });\n });\n\n /**\n * Handle a parsed JSON-RPC message\n */\n async function handleParsedMessage(\n connection: ChannelConnection,\n state: ConnectionState,\n parsed: import(\"jsonrpc-lite\").IParsedObject\n ): Promise<void> {\n if (isRequest(parsed)) {\n // JSON-RPC Request - handle and respond directly\n const payload = parsed.payload as {\n id: string | number;\n method: string;\n params: unknown;\n };\n const { id, method, params } = payload;\n\n logger.debug(\"Received RPC request\", { id, method });\n\n // Call command handler\n const result = await commandHandler.handle(method as RpcMethod, params);\n\n if (result.success) {\n sendResponse(connection, id, result.data);\n } else {\n sendError(connection, id, result.code, result.message);\n }\n } else if (isNotification(parsed)) {\n // JSON-RPC Notification - control messages\n const payload = parsed.payload as {\n method: string;\n params: unknown;\n };\n const { method, params } = payload;\n\n logger.debug(\"Received notification\", { method });\n\n if (method === \"subscribe\") {\n const { topic } = params as { topic: string };\n subscribeToTopic(connection.id, topic);\n } else if (method === \"unsubscribe\") {\n const { topic } = params as { topic: string };\n state.subscribedTopics.delete(topic);\n logger.debug(\"Connection unsubscribed from topic\", { connectionId: connection.id, topic });\n } else if (method === \"control.ack\") {\n // ACK for reliable delivery - handled by network layer\n logger.debug(\"Received ACK notification\");\n }\n } else {\n // Invalid message\n logger.warn(\"Received invalid JSON-RPC message\");\n }\n }\n\n // Route internal events to connected clients as JSON-RPC notifications\n platform.eventBus.onAny((event) => {\n // Only broadcast broadcastable events\n if (!shouldBroadcastEvent(event)) {\n return;\n }\n\n // Get topic from event context\n const eventWithContext = event as BusEvent & { context?: { sessionId?: string } };\n const topic = eventWithContext.context?.sessionId || \"global\";\n\n // Wrap as JSON-RPC notification\n const notification = createStreamEvent(topic, event as SystemEvent);\n const message = JSON.stringify(notification);\n\n for (const [connectionId, state] of connections) {\n if (shouldSendToConnection(state, event)) {\n state.connection.sendReliable(message, {\n timeout: 10000,\n onTimeout: () => {\n logger.warn(\"Event ACK timeout\", {\n connectionId,\n eventType: event.type,\n });\n },\n });\n }\n }\n });\n\n /**\n * Check if event should be broadcast\n */\n function shouldBroadcastEvent(event: BusEvent): boolean {\n // Skip internal driver events\n if (event.source === \"driver\" && event.intent !== \"notification\") {\n return false;\n }\n\n // Skip command events (handled via RPC)\n if (event.source === \"command\") {\n return false;\n }\n\n // Check broadcastable flag\n const systemEvent = event as SystemEvent;\n if (systemEvent.broadcastable === false) {\n return false;\n }\n\n return true;\n }\n\n // Attach to existing server if provided\n if (config.server) {\n wsServer.attach(config.server, wsPath);\n logger.info(\"WebSocket attached to existing server\", { path: wsPath });\n }\n\n return {\n async listen(port?: number, host?: string) {\n if (config.server) {\n throw new Error(\n \"Cannot listen when attached to existing server. The server should call listen() instead.\"\n );\n }\n\n const listenPort = port ?? config.port ?? 5200;\n const listenHost = host ?? config.host ?? \"0.0.0.0\";\n\n await wsServer.listen(listenPort, listenHost);\n logger.info(\"Server listening\", { port: listenPort, host: listenHost });\n },\n\n async close() {\n await wsServer.close();\n logger.info(\"Server closed\");\n },\n\n async dispose() {\n // Cleanup in order\n await wsServer.dispose();\n commandHandler.dispose();\n await runtime.shutdown();\n logger.info(\"Server disposed\");\n },\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxjs",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "AgentX Client SDK - Local and remote AI agent management",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,12 +23,12 @@
23
23
  "test": "bun test bdd/"
24
24
  },
25
25
  "dependencies": {
26
- "@agentxjs/core": "^2.7.0",
26
+ "@agentxjs/core": "^2.8.0",
27
27
  "@deepracticex/id": "^0.2.0",
28
28
  "@deepracticex/logger": "^1.2.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@agentxjs/devtools": "^2.7.0",
31
+ "@agentxjs/devtools": "^2.8.0",
32
32
  "@deepracticex/bdd": "^0.3.0",
33
33
  "tsx": "^4.19.0",
34
34
  "typescript": "^5.3.3"
@@ -7,9 +7,9 @@
7
7
  import type { Message } from "@agentxjs/core/agent";
8
8
  import type { Presentation, PresentationOptions } from "./presentation";
9
9
  import type {
10
+ AgentConfig,
10
11
  AgentHandle,
11
12
  BaseResponse,
12
- Embodiment,
13
13
  MessageSendResponse,
14
14
  RuntimeNamespace,
15
15
  } from "./types";
@@ -49,12 +49,14 @@ export class AgentHandleImpl implements AgentHandle {
49
49
  return this.ns.present.create(this.instanceId, options);
50
50
  }
51
51
 
52
- async update(updates: {
53
- name?: string;
54
- description?: string;
55
- embody?: Embodiment;
56
- customData?: Record<string, unknown>;
57
- }): Promise<void> {
52
+ async update(
53
+ updates: Partial<
54
+ Pick<
55
+ AgentConfig,
56
+ "name" | "description" | "model" | "systemPrompt" | "mcpServers" | "customData"
57
+ >
58
+ >
59
+ ): Promise<void> {
58
60
  await this.ns.image.update(this.imageId, updates);
59
61
  }
60
62
 
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { UserContentPart } from "@agentxjs/core/agent";
11
+ import { DEFAULT_CONTAINER_ID } from "@agentxjs/core/container";
11
12
  import type { RpcMethod } from "@agentxjs/core/network";
12
13
  import type { AgentXRuntime } from "@agentxjs/core/runtime";
13
14
  import { createLogger } from "@deepracticex/logger";
@@ -63,14 +64,6 @@ export class CommandHandler {
63
64
 
64
65
  try {
65
66
  switch (method) {
66
- // Container
67
- case "container.create":
68
- return await this.handleContainerCreate(params);
69
- case "container.get":
70
- return await this.handleContainerGet(params);
71
- case "container.list":
72
- return await this.handleContainerList(params);
73
-
74
67
  // Image
75
68
  case "image.create":
76
69
  return await this.handleImageCreate(params);
@@ -105,18 +98,6 @@ export class CommandHandler {
105
98
  case "message.send":
106
99
  return await this.handleMessageSend(params);
107
100
 
108
- // Prototype
109
- case "prototype.create":
110
- return await this.handlePrototypeCreate(params);
111
- case "prototype.get":
112
- return await this.handlePrototypeGet(params);
113
- case "prototype.list":
114
- return await this.handlePrototypeList(params);
115
- case "prototype.update":
116
- return await this.handlePrototypeUpdate(params);
117
- case "prototype.delete":
118
- return await this.handlePrototypeDelete(params);
119
-
120
101
  // LLM Provider
121
102
  case "llm.create":
122
103
  return await this.handleLLMCreate(params);
@@ -140,50 +121,39 @@ export class CommandHandler {
140
121
  }
141
122
  }
142
123
 
143
- // ==================== Container Commands ====================
144
-
145
- private async handleContainerCreate(params: unknown): Promise<RpcResponse> {
146
- const { containerId } = params as { containerId: string };
147
- const { getOrCreateContainer } = await import("@agentxjs/core/container");
148
- const { containerRepository, imageRepository, sessionRepository } = this.runtime.platform;
149
-
150
- const container = await getOrCreateContainer(containerId, {
151
- containerRepository,
152
- imageRepository,
153
- sessionRepository,
154
- });
155
-
156
- return ok({ containerId: container.containerId });
157
- }
158
-
159
- private async handleContainerGet(params: unknown): Promise<RpcResponse> {
160
- const { containerId } = params as { containerId: string };
161
- const exists = await this.runtime.platform.containerRepository.containerExists(containerId);
162
- return ok({ containerId, exists });
163
- }
164
-
165
- private async handleContainerList(_params: unknown): Promise<RpcResponse> {
166
- const containers = await this.runtime.platform.containerRepository.findAllContainers();
167
- return ok({ containerIds: containers.map((c) => c.containerId) });
168
- }
169
-
170
124
  // ==================== Image Commands ====================
171
125
 
172
126
  private async handleImageCreate(params: unknown): Promise<RpcResponse> {
173
- const { containerId, name, description, contextId, embody, customData } = params as {
174
- containerId: string;
127
+ const {
128
+ containerId: _cid,
129
+ name,
130
+ description,
131
+ contextId,
132
+ model,
133
+ systemPrompt,
134
+ mcpServers,
135
+ customData,
136
+ } = params as {
137
+ containerId?: string;
175
138
  name?: string;
176
139
  description?: string;
177
140
  contextId?: string;
178
- embody?: import("@agentxjs/core/persistence").Embodiment;
141
+ model?: string;
142
+ systemPrompt?: string;
143
+ mcpServers?: Record<string, unknown>;
179
144
  customData?: Record<string, unknown>;
180
145
  };
181
146
 
182
147
  const { imageRepository, sessionRepository } = this.runtime.platform;
183
148
  const { createImage } = await import("@agentxjs/core/image");
184
149
 
150
+ const embody =
151
+ model || systemPrompt || mcpServers
152
+ ? ({ model, systemPrompt, mcpServers } as import("@agentxjs/core/persistence").Embodiment)
153
+ : undefined;
154
+
185
155
  const image = await createImage(
186
- { containerId, name, description, contextId, embody, customData },
156
+ { containerId: DEFAULT_CONTAINER_ID, name, description, contextId, embody, customData },
187
157
  { imageRepository, sessionRepository }
188
158
  );
189
159
 
@@ -295,7 +265,9 @@ export class CommandHandler {
295
265
  updates: {
296
266
  name?: string;
297
267
  description?: string;
298
- embody?: import("@agentxjs/core/persistence").Embodiment;
268
+ model?: string;
269
+ systemPrompt?: string;
270
+ mcpServers?: Record<string, unknown>;
299
271
  customData?: Record<string, unknown>;
300
272
  };
301
273
  };
@@ -306,12 +278,22 @@ export class CommandHandler {
306
278
  return err(404, `Image not found: ${imageId}`);
307
279
  }
308
280
 
309
- // Update image record (embody is merged, not replaced)
310
- const { embody: embodyUpdates, ...otherUpdates } = updates;
281
+ // Extract embody fields from flat updates
282
+ const { model, systemPrompt, mcpServers, ...otherUpdates } = updates;
283
+ const embodyUpdates =
284
+ model !== undefined || systemPrompt !== undefined || mcpServers !== undefined
285
+ ? ({
286
+ ...imageRecord.embody,
287
+ model,
288
+ systemPrompt,
289
+ mcpServers,
290
+ } as import("@agentxjs/core/persistence").Embodiment)
291
+ : imageRecord.embody;
292
+
311
293
  const updatedRecord = {
312
294
  ...imageRecord,
313
295
  ...otherUpdates,
314
- embody: embodyUpdates ? { ...imageRecord.embody, ...embodyUpdates } : imageRecord.embody,
296
+ embody: embodyUpdates,
315
297
  updatedAt: Date.now(),
316
298
  };
317
299
 
@@ -449,116 +431,19 @@ export class CommandHandler {
449
431
  return ok({ instanceId: targetInstanceId, imageId });
450
432
  }
451
433
 
452
- // ==================== Prototype Commands ====================
453
-
454
- private async handlePrototypeCreate(params: unknown): Promise<RpcResponse> {
455
- const { containerId, name, description, contextId, embody, customData } = params as {
456
- containerId: string;
457
- name: string;
458
- description?: string;
459
- contextId?: string;
460
- embody?: import("@agentxjs/core/persistence").Embodiment;
461
- customData?: Record<string, unknown>;
462
- };
463
-
464
- const repo = this.runtime.platform.prototypeRepository;
465
- if (!repo) {
466
- return err(-32000, "Prototype repository not available");
467
- }
468
-
469
- const now = Date.now();
470
- const random = Math.random().toString(36).slice(2, 8);
471
- const record = {
472
- prototypeId: `proto_${now}_${random}`,
473
- containerId,
474
- name,
475
- description,
476
- contextId,
477
- embody,
478
- customData,
479
- createdAt: now,
480
- updatedAt: now,
481
- };
482
-
483
- await repo.savePrototype(record);
484
- return ok({ record });
485
- }
486
-
487
- private async handlePrototypeGet(params: unknown): Promise<RpcResponse> {
488
- const { prototypeId } = params as { prototypeId: string };
489
- const repo = this.runtime.platform.prototypeRepository;
490
- if (!repo) {
491
- return err(-32000, "Prototype repository not available");
492
- }
493
-
494
- const record = await repo.findPrototypeById(prototypeId);
495
- return ok({ record });
496
- }
497
-
498
- private async handlePrototypeList(params: unknown): Promise<RpcResponse> {
499
- const { containerId } = params as { containerId?: string };
500
- const repo = this.runtime.platform.prototypeRepository;
501
- if (!repo) {
502
- return err(-32000, "Prototype repository not available");
503
- }
504
-
505
- const records = containerId
506
- ? await repo.findPrototypesByContainerId(containerId)
507
- : await repo.findAllPrototypes();
508
-
509
- return ok({ records });
510
- }
511
-
512
- private async handlePrototypeUpdate(params: unknown): Promise<RpcResponse> {
513
- const { prototypeId, updates } = params as {
514
- prototypeId: string;
515
- updates: {
516
- name?: string;
517
- description?: string;
518
- contextId?: string;
519
- embody?: import("@agentxjs/core/persistence").Embodiment;
520
- customData?: Record<string, unknown>;
521
- };
522
- };
523
-
524
- const repo = this.runtime.platform.prototypeRepository;
525
- if (!repo) {
526
- return err(-32000, "Prototype repository not available");
527
- }
528
-
529
- const existing = await repo.findPrototypeById(prototypeId);
530
- if (!existing) {
531
- return err(404, `Prototype not found: ${prototypeId}`);
532
- }
533
-
534
- const { embody: embodyUpdates, ...otherUpdates } = updates;
535
- const updated = {
536
- ...existing,
537
- ...otherUpdates,
538
- embody: embodyUpdates ? { ...existing.embody, ...embodyUpdates } : existing.embody,
539
- updatedAt: Date.now(),
540
- };
541
-
542
- await repo.savePrototype(updated);
543
- return ok({ record: updated });
544
- }
545
-
546
- private async handlePrototypeDelete(params: unknown): Promise<RpcResponse> {
547
- const { prototypeId } = params as { prototypeId: string };
548
- const repo = this.runtime.platform.prototypeRepository;
549
- if (!repo) {
550
- return err(-32000, "Prototype repository not available");
551
- }
552
-
553
- await repo.deletePrototype(prototypeId);
554
- return ok({ prototypeId });
555
- }
556
-
557
434
  // ==================== LLM Provider Commands ====================
558
435
 
559
436
  private async handleLLMCreate(params: unknown): Promise<RpcResponse> {
560
- const { containerId, name, vendor, protocol, apiKey, baseUrl, model } = params as {
561
- containerId: string;
437
+ const {
438
+ containerId: _cid,
439
+ name,
440
+ vendor,
441
+ protocol,
442
+ apiKey,
443
+ baseUrl,
444
+ model,
445
+ } = params as {
446
+ containerId?: string;
562
447
  name: string;
563
448
  vendor: string;
564
449
  protocol: string;
@@ -576,7 +461,7 @@ export class CommandHandler {
576
461
  const now = Date.now();
577
462
  const record = {
578
463
  id: generateId("llm"),
579
- containerId,
464
+ containerId: DEFAULT_CONTAINER_ID,
580
465
  name,
581
466
  vendor,
582
467
  protocol: protocol as "anthropic" | "openai",
@@ -13,19 +13,11 @@ import { createLogger } from "commonxjs/logger";
13
13
  import { AgentHandleImpl } from "./AgentHandle";
14
14
  import { CommandHandler } from "./CommandHandler";
15
15
  import { createLocalInstances } from "./namespaces/agents";
16
- import { createLocalContainers } from "./namespaces/containers";
17
16
  import { createLocalImages } from "./namespaces/images";
18
17
  import { createLocalLLM } from "./namespaces/llm";
19
18
  import { createPresentations } from "./namespaces/presentations";
20
- import { createLocalPrototypes } from "./namespaces/prototypes";
21
19
  import { createLocalSessions } from "./namespaces/sessions";
22
- import type {
23
- AgentX,
24
- ChatNamespace,
25
- LLMNamespace,
26
- PrototypeNamespace,
27
- RuntimeNamespace,
28
- } from "./types";
20
+ import type { AgentX, ChatNamespace, LLMNamespace, RuntimeNamespace } from "./types";
29
21
 
30
22
  const logger = createLogger("agentx/LocalClient");
31
23
 
@@ -40,23 +32,19 @@ export class LocalClient implements AgentX {
40
32
  readonly chat: ChatNamespace;
41
33
  readonly runtime: RuntimeNamespace;
42
34
  readonly provider: LLMNamespace;
43
- readonly prototype: PrototypeNamespace;
44
35
 
45
36
  constructor(agentxRuntime: AgentXRuntime) {
46
37
  this._runtime = agentxRuntime;
47
38
  const platform = agentxRuntime.platform;
48
39
 
49
- const container = createLocalContainers(platform);
50
40
  const image = createLocalImages(platform);
51
41
  const instance = createLocalInstances(agentxRuntime);
52
42
  const session = createLocalSessions(agentxRuntime);
53
43
  const llm = createLocalLLM(platform);
54
- const prototype = createLocalPrototypes(platform);
55
44
  const present = createPresentations(this, session);
56
45
 
57
- this.runtime = { container, image, instance, session, present, llm, prototype };
46
+ this.runtime = { image, instance, session, present, llm };
58
47
  this.provider = llm;
59
- this.prototype = prototype;
60
48
  this.chat = this.createChatNamespace();
61
49
 
62
50
  logger.info("LocalClient initialized");
@@ -113,25 +101,7 @@ export class LocalClient implements AgentX {
113
101
  const rt = this.runtime;
114
102
  return {
115
103
  async create(params) {
116
- const containerId = "default";
117
- // If prototypeId is provided, merge prototype config into params
118
- let mergedParams = { ...params };
119
- if (params.prototypeId) {
120
- const protoRes = await rt.prototype.get(params.prototypeId);
121
- if (protoRes.record) {
122
- const proto = protoRes.record;
123
- mergedParams = {
124
- name: proto.name,
125
- description: proto.description,
126
- contextId: proto.contextId,
127
- embody: proto.embody,
128
- customData: proto.customData,
129
- ...params, // inline params override prototype
130
- };
131
- }
132
- }
133
- const { prototypeId: _pid, ...imageParams } = mergedParams;
134
- const imgRes = await rt.image.create({ containerId, ...imageParams });
104
+ const imgRes = await rt.image.create(params);
135
105
  const instRes = await rt.instance.create({ imageId: imgRes.record.imageId });
136
106
  return new AgentHandleImpl(
137
107
  {
@@ -12,17 +12,14 @@ import { RpcClient, type RpcMethod } from "@agentxjs/core/network";
12
12
  import { createLogger } from "commonxjs/logger";
13
13
  import { AgentHandleImpl } from "./AgentHandle";
14
14
  import { createRemoteInstances } from "./namespaces/agents";
15
- import { createRemoteContainers } from "./namespaces/containers";
16
15
  import { createRemoteImages } from "./namespaces/images";
17
16
  import { createRemoteLLM } from "./namespaces/llm";
18
17
  import { createPresentations } from "./namespaces/presentations";
19
- import { createRemotePrototypes } from "./namespaces/prototypes";
20
18
  import { createRemoteSessions } from "./namespaces/sessions";
21
19
  import type {
22
20
  AgentX,
23
21
  ChatNamespace,
24
22
  LLMNamespace,
25
- PrototypeNamespace,
26
23
  RemoteClientConfig,
27
24
  RuntimeNamespace,
28
25
  } from "./types";
@@ -40,7 +37,6 @@ export class RemoteClient implements AgentX {
40
37
  readonly chat: ChatNamespace;
41
38
  readonly runtime: RuntimeNamespace;
42
39
  readonly provider: LLMNamespace;
43
- readonly prototype: PrototypeNamespace;
44
40
 
45
41
  constructor(config: RemoteClientConfig) {
46
42
  this.config = config;
@@ -63,17 +59,14 @@ export class RemoteClient implements AgentX {
63
59
  });
64
60
 
65
61
  // Assemble namespaces
66
- const container = createRemoteContainers(this.rpcClient);
67
62
  const image = createRemoteImages(this.rpcClient, (sessionId) => this.subscribe(sessionId));
68
63
  const instance = createRemoteInstances(this.rpcClient);
69
64
  const session = createRemoteSessions(this.rpcClient);
70
65
  const llm = createRemoteLLM(this.rpcClient);
71
- const prototype = createRemotePrototypes(this.rpcClient);
72
66
  const present = createPresentations(this, session);
73
67
 
74
- this.runtime = { container, image, instance, session, present, llm, prototype };
68
+ this.runtime = { image, instance, session, present, llm };
75
69
  this.provider = llm;
76
- this.prototype = prototype;
77
70
  this.chat = this.createChatNamespace();
78
71
  }
79
72
 
@@ -140,25 +133,7 @@ export class RemoteClient implements AgentX {
140
133
  const rt = this.runtime;
141
134
  return {
142
135
  async create(params) {
143
- const containerId = "default";
144
- // If prototypeId is provided, merge prototype config into params
145
- let mergedParams = { ...params };
146
- if (params.prototypeId) {
147
- const protoRes = await rt.prototype.get(params.prototypeId);
148
- if (protoRes.record) {
149
- const proto = protoRes.record;
150
- mergedParams = {
151
- name: proto.name,
152
- description: proto.description,
153
- contextId: proto.contextId,
154
- embody: proto.embody,
155
- customData: proto.customData,
156
- ...params, // inline params override prototype
157
- };
158
- }
159
- }
160
- const { prototypeId: _pid, ...imageParams } = mergedParams;
161
- const imgRes = await rt.image.create({ containerId, ...imageParams });
136
+ const imgRes = await rt.image.create(params);
162
137
  const instRes = await rt.instance.create({ imageId: imgRes.record.imageId });
163
138
  return new AgentHandleImpl(
164
139
  {
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * import { nodePlatform } from "@agentxjs/node-platform";
10
10
  *
11
11
  * const ax = createAgentX(nodePlatform({ createDriver }));
12
- * const agent = await ax.chat.create({ name: "Aristotle", embody: { model: "claude-sonnet-4-6" } });
12
+ * const agent = await ax.chat.create({ name: "Aristotle", model: "claude-sonnet-4-6" });
13
13
  * await agent.send("Hello!");
14
14
  * ```
15
15
  *
@@ -87,10 +87,6 @@ export function createAgentX(config?: PlatformConfig): AgentXBuilder {
87
87
  return getLocalClient().chat;
88
88
  },
89
89
 
90
- get prototype() {
91
- return getLocalClient().prototype;
92
- },
93
-
94
90
  on(type, handler) {
95
91
  return getLocalClient().on(type, handler);
96
92
  },
@@ -156,12 +152,12 @@ export function createAgentX(config?: PlatformConfig): AgentXBuilder {
156
152
  };
157
153
  }
158
154
 
159
- export type { AgentXErrorCategory, AgentXErrorContext } from "@agentxjs/core/error";
155
+ // Re-export context interfaces
156
+ export type { Capability, Context, ContextProvider } from "@agentxjs/core/context";
160
157
  // Re-export error types
158
+ export type { AgentXErrorCategory, AgentXErrorContext } from "@agentxjs/core/error";
161
159
  export { AgentXError, AgentXErrorCode } from "@agentxjs/core/error";
162
- // Re-export server
163
- export { CommandHandler } from "./CommandHandler";
164
- // Re-export Presentation types and classes
160
+ // Re-export Presentation
165
161
  export type {
166
162
  AssistantConversation,
167
163
  Block,
@@ -184,9 +180,9 @@ export {
184
180
  Presentation,
185
181
  presentationReducer,
186
182
  } from "./presentation";
187
- export { createServer, type ServerConfig } from "./server";
188
183
  // Re-export types
189
184
  export type {
185
+ AgentConfig,
190
186
  AgentHandle,
191
187
  AgentX,
192
188
  AgentXBuilder,
@@ -194,17 +190,12 @@ export type {
194
190
  BaseResponse,
195
191
  ChatNamespace,
196
192
  ConnectOptions,
197
- ContainerCreateResponse,
198
- ContainerGetResponse,
199
- ContainerInfo,
200
- ContainerListResponse,
201
- ContainerNamespace,
202
- Embodiment,
203
193
  ImageCreateResponse,
204
194
  ImageGetResponse,
205
195
  ImageListResponse,
206
196
  ImageNamespace,
207
197
  ImageRecord,
198
+ ImageUpdateResponse,
208
199
  InstanceCreateResponse,
209
200
  InstanceGetResponse,
210
201
  InstanceInfo,
@@ -219,11 +210,6 @@ export type {
219
210
  MaybeAsync,
220
211
  MessageSendResponse,
221
212
  PresentationNamespace,
222
- PrototypeCreateResponse,
223
- PrototypeGetResponse,
224
- PrototypeListResponse,
225
- PrototypeNamespace,
226
- PrototypeUpdateResponse,
227
213
  RuntimeNamespace,
228
214
  ServeConfig,
229
215
  SessionNamespace,
@@ -67,8 +67,8 @@ export function createLocalInstances(runtime: AgentXRuntime): InstanceNamespace
67
67
  };
68
68
  },
69
69
 
70
- async list(containerId?: string): Promise<InstanceListResponse> {
71
- const agents = containerId ? runtime.getAgentsByContainer(containerId) : runtime.getAgents();
70
+ async list(): Promise<InstanceListResponse> {
71
+ const agents = runtime.getAgents();
72
72
 
73
73
  return {
74
74
  agents: agents.map((a) => ({
@@ -114,8 +114,8 @@ export function createRemoteInstances(rpcClient: RpcClient): InstanceNamespace {
114
114
  return { ...result, requestId: "" };
115
115
  },
116
116
 
117
- async list(containerId?: string): Promise<InstanceListResponse> {
118
- const result = await rpcClient.call<InstanceListResponse>("instance.list", { containerId });
117
+ async list(): Promise<InstanceListResponse> {
118
+ const result = await rpcClient.call<InstanceListResponse>("instance.list", {});
119
119
  return { ...result, requestId: "" };
120
120
  },
121
121