agentxjs 2.4.0 → 2.6.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.
@@ -105,6 +105,18 @@ export class CommandHandler {
105
105
  case "message.send":
106
106
  return await this.handleMessageSend(params);
107
107
 
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
+
108
120
  // LLM Provider
109
121
  case "llm.create":
110
122
  return await this.handleLLMCreate(params);
@@ -158,12 +170,12 @@ export class CommandHandler {
158
170
  // ==================== Image Commands ====================
159
171
 
160
172
  private async handleImageCreate(params: unknown): Promise<RpcResponse> {
161
- const { containerId, name, description, systemPrompt, mcpServers, customData } = params as {
173
+ const { containerId, name, description, contextId, embody, customData } = params as {
162
174
  containerId: string;
163
175
  name?: string;
164
176
  description?: string;
165
- systemPrompt?: string;
166
- mcpServers?: Record<string, unknown>;
177
+ contextId?: string;
178
+ embody?: import("@agentxjs/core/persistence").Embodiment;
167
179
  customData?: Record<string, unknown>;
168
180
  };
169
181
 
@@ -171,7 +183,7 @@ export class CommandHandler {
171
183
  const { createImage } = await import("@agentxjs/core/image");
172
184
 
173
185
  const image = await createImage(
174
- { containerId, name, description, systemPrompt, mcpServers: mcpServers as any, customData },
186
+ { containerId, name, description, contextId, embody, customData },
175
187
  { imageRepository, sessionRepository }
176
188
  );
177
189
 
@@ -280,7 +292,12 @@ export class CommandHandler {
280
292
  private async handleImageUpdate(params: unknown): Promise<RpcResponse> {
281
293
  const { imageId, updates } = params as {
282
294
  imageId: string;
283
- updates: { name?: string; description?: string; customData?: Record<string, unknown> };
295
+ updates: {
296
+ name?: string;
297
+ description?: string;
298
+ embody?: import("@agentxjs/core/persistence").Embodiment;
299
+ customData?: Record<string, unknown>;
300
+ };
284
301
  };
285
302
 
286
303
  // Get existing image
@@ -289,10 +306,12 @@ export class CommandHandler {
289
306
  return err(404, `Image not found: ${imageId}`);
290
307
  }
291
308
 
292
- // Update image record
309
+ // Update image record (embody is merged, not replaced)
310
+ const { embody: embodyUpdates, ...otherUpdates } = updates;
293
311
  const updatedRecord = {
294
312
  ...imageRecord,
295
- ...updates,
313
+ ...otherUpdates,
314
+ embody: embodyUpdates ? { ...imageRecord.embody, ...embodyUpdates } : imageRecord.embody,
296
315
  updatedAt: Date.now(),
297
316
  };
298
317
 
@@ -430,6 +449,111 @@ export class CommandHandler {
430
449
  return ok({ agentId: targetAgentId, imageId });
431
450
  }
432
451
 
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
+
433
557
  // ==================== LLM Provider Commands ====================
434
558
 
435
559
  private async handleLLMCreate(params: unknown): Promise<RpcResponse> {
@@ -10,21 +10,21 @@ import type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from "@agentxjs
10
10
  import type { RpcMethod } from "@agentxjs/core/network";
11
11
  import type { AgentXRuntime } from "@agentxjs/core/runtime";
12
12
  import { createLogger } from "commonxjs/logger";
13
+ import { AgentHandleImpl } from "./AgentHandle";
13
14
  import { CommandHandler } from "./CommandHandler";
14
15
  import { createLocalAgents } from "./namespaces/agents";
15
16
  import { createLocalContainers } from "./namespaces/containers";
16
17
  import { createLocalImages } from "./namespaces/images";
17
18
  import { createLocalLLM } from "./namespaces/llm";
18
19
  import { createPresentations } from "./namespaces/presentations";
20
+ import { createLocalPrototypes } from "./namespaces/prototypes";
19
21
  import { createLocalSessions } from "./namespaces/sessions";
20
22
  import type {
21
- AgentNamespace,
22
23
  AgentX,
23
- ContainerNamespace,
24
- ImageNamespace,
24
+ ChatNamespace,
25
25
  LLMNamespace,
26
- PresentationNamespace,
27
- SessionNamespace,
26
+ PrototypeNamespace,
27
+ RuntimeNamespace,
28
28
  } from "./types";
29
29
 
30
30
  const logger = createLogger("agentx/LocalClient");
@@ -33,27 +33,31 @@ const logger = createLogger("agentx/LocalClient");
33
33
  * LocalClient - Embedded runtime implementation
34
34
  */
35
35
  export class LocalClient implements AgentX {
36
- private readonly runtime: AgentXRuntime;
36
+ private readonly _runtime: AgentXRuntime;
37
37
  private commandHandler: CommandHandler | null = null;
38
38
  private isDisposed = false;
39
39
 
40
- readonly container: ContainerNamespace;
41
- readonly image: ImageNamespace;
42
- readonly agent: AgentNamespace;
43
- readonly session: SessionNamespace;
44
- readonly presentation: PresentationNamespace;
45
- readonly llm: LLMNamespace;
40
+ readonly chat: ChatNamespace;
41
+ readonly runtime: RuntimeNamespace;
42
+ readonly provider: LLMNamespace;
43
+ readonly prototype: PrototypeNamespace;
46
44
 
47
- constructor(runtime: AgentXRuntime) {
48
- this.runtime = runtime;
49
- const platform = runtime.platform;
45
+ constructor(agentxRuntime: AgentXRuntime) {
46
+ this._runtime = agentxRuntime;
47
+ const platform = agentxRuntime.platform;
50
48
 
51
- this.container = createLocalContainers(platform);
52
- this.image = createLocalImages(platform);
53
- this.agent = createLocalAgents(runtime);
54
- this.session = createLocalSessions(runtime);
55
- this.presentation = createPresentations(this);
56
- this.llm = createLocalLLM(platform);
49
+ const container = createLocalContainers(platform);
50
+ const image = createLocalImages(platform);
51
+ const agent = createLocalAgents(agentxRuntime);
52
+ const session = createLocalSessions(agentxRuntime);
53
+ const llm = createLocalLLM(platform);
54
+ const prototype = createLocalPrototypes(platform);
55
+ const present = createPresentations(this, image);
56
+
57
+ this.runtime = { container, image, agent, session, present, llm, prototype };
58
+ this.provider = llm;
59
+ this.prototype = prototype;
60
+ this.chat = this.createChatNamespace();
57
61
 
58
62
  logger.info("LocalClient initialized");
59
63
  }
@@ -65,17 +69,17 @@ export class LocalClient implements AgentX {
65
69
  }
66
70
 
67
71
  get events(): EventBus {
68
- return this.runtime.platform.eventBus;
72
+ return this._runtime.platform.eventBus;
69
73
  }
70
74
 
71
75
  // ==================== Event Subscription ====================
72
76
 
73
77
  on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe {
74
- return this.runtime.platform.eventBus.on(type, handler);
78
+ return this._runtime.platform.eventBus.on(type, handler);
75
79
  }
76
80
 
77
81
  onAny(handler: BusEventHandler): Unsubscribe {
78
- return this.runtime.platform.eventBus.onAny(handler);
82
+ return this._runtime.platform.eventBus.onAny(handler);
79
83
  }
80
84
 
81
85
  subscribe(_sessionId: string): void {
@@ -85,7 +89,7 @@ export class LocalClient implements AgentX {
85
89
  // ==================== Error Handling ====================
86
90
 
87
91
  onError(handler: (error: AgentXError) => void): Unsubscribe {
88
- return this.runtime.platform.eventBus.on("agentx_error", (event) => {
92
+ return this._runtime.platform.eventBus.on("agentx_error", (event) => {
89
93
  handler(event.data as AgentXError);
90
94
  });
91
95
  }
@@ -94,7 +98,7 @@ export class LocalClient implements AgentX {
94
98
 
95
99
  async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {
96
100
  if (!this.commandHandler) {
97
- this.commandHandler = new CommandHandler(this.runtime);
101
+ this.commandHandler = new CommandHandler(this._runtime);
98
102
  }
99
103
  const result = await this.commandHandler.handle(method as RpcMethod, params);
100
104
  if (result.success) {
@@ -103,6 +107,62 @@ export class LocalClient implements AgentX {
103
107
  throw new Error(result.message);
104
108
  }
105
109
 
110
+ // ==================== Private ====================
111
+
112
+ private createChatNamespace(): ChatNamespace {
113
+ const instance = this.runtime;
114
+ return {
115
+ 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 instance.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 instance.image.create({ containerId, ...imageParams });
135
+ const agentRes = await instance.agent.create({ imageId: imgRes.record.imageId });
136
+ return new AgentHandleImpl(
137
+ {
138
+ agentId: agentRes.agentId,
139
+ imageId: agentRes.imageId,
140
+ containerId: agentRes.containerId,
141
+ sessionId: agentRes.sessionId,
142
+ },
143
+ instance
144
+ );
145
+ },
146
+ async list() {
147
+ return instance.image.list();
148
+ },
149
+ async get(id) {
150
+ const res = await instance.image.get(id);
151
+ if (!res.record) return null;
152
+ const r = res.record;
153
+ return new AgentHandleImpl(
154
+ {
155
+ agentId: r.imageId,
156
+ imageId: r.imageId,
157
+ containerId: r.containerId,
158
+ sessionId: r.sessionId,
159
+ },
160
+ instance
161
+ );
162
+ },
163
+ };
164
+ }
165
+
106
166
  // ==================== Lifecycle ====================
107
167
 
108
168
  async disconnect(): Promise<void> {
@@ -111,7 +171,7 @@ export class LocalClient implements AgentX {
111
171
 
112
172
  async dispose(): Promise<void> {
113
173
  if (this.isDisposed) return;
114
- await this.runtime.shutdown();
174
+ await this._runtime.shutdown();
115
175
  this.isDisposed = true;
116
176
  logger.info("LocalClient disposed");
117
177
  }
@@ -10,21 +10,21 @@ import type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from "@agentxjs
10
10
  import { EventBusImpl } from "@agentxjs/core/event";
11
11
  import { RpcClient, type RpcMethod } from "@agentxjs/core/network";
12
12
  import { createLogger } from "commonxjs/logger";
13
+ import { AgentHandleImpl } from "./AgentHandle";
13
14
  import { createRemoteAgents } from "./namespaces/agents";
14
15
  import { createRemoteContainers } from "./namespaces/containers";
15
16
  import { createRemoteImages } from "./namespaces/images";
16
17
  import { createRemoteLLM } from "./namespaces/llm";
17
18
  import { createPresentations } from "./namespaces/presentations";
19
+ import { createRemotePrototypes } from "./namespaces/prototypes";
18
20
  import { createRemoteSessions } from "./namespaces/sessions";
19
21
  import type {
20
- AgentNamespace,
21
22
  AgentX,
22
- ContainerNamespace,
23
- ImageNamespace,
23
+ ChatNamespace,
24
24
  LLMNamespace,
25
- PresentationNamespace,
25
+ PrototypeNamespace,
26
26
  RemoteClientConfig,
27
- SessionNamespace,
27
+ RuntimeNamespace,
28
28
  } from "./types";
29
29
 
30
30
  const logger = createLogger("agentx/RemoteClient");
@@ -37,12 +37,10 @@ export class RemoteClient implements AgentX {
37
37
  private readonly eventBus: EventBus;
38
38
  private readonly rpcClient: RpcClient;
39
39
 
40
- readonly container: ContainerNamespace;
41
- readonly image: ImageNamespace;
42
- readonly agent: AgentNamespace;
43
- readonly session: SessionNamespace;
44
- readonly presentation: PresentationNamespace;
45
- readonly llm: LLMNamespace;
40
+ readonly chat: ChatNamespace;
41
+ readonly runtime: RuntimeNamespace;
42
+ readonly provider: LLMNamespace;
43
+ readonly prototype: PrototypeNamespace;
46
44
 
47
45
  constructor(config: RemoteClientConfig) {
48
46
  this.config = config;
@@ -65,12 +63,18 @@ export class RemoteClient implements AgentX {
65
63
  });
66
64
 
67
65
  // Assemble namespaces
68
- this.container = createRemoteContainers(this.rpcClient);
69
- this.image = createRemoteImages(this.rpcClient, (sessionId) => this.subscribe(sessionId));
70
- this.agent = createRemoteAgents(this.rpcClient);
71
- this.session = createRemoteSessions(this.rpcClient);
72
- this.presentation = createPresentations(this);
73
- this.llm = createRemoteLLM(this.rpcClient);
66
+ const container = createRemoteContainers(this.rpcClient);
67
+ const image = createRemoteImages(this.rpcClient, (sessionId) => this.subscribe(sessionId));
68
+ const agent = createRemoteAgents(this.rpcClient);
69
+ const session = createRemoteSessions(this.rpcClient);
70
+ const llm = createRemoteLLM(this.rpcClient);
71
+ const prototype = createRemotePrototypes(this.rpcClient);
72
+ const present = createPresentations(this, image);
73
+
74
+ this.runtime = { container, image, agent, session, present, llm, prototype };
75
+ this.provider = llm;
76
+ this.prototype = prototype;
77
+ this.chat = this.createChatNamespace();
74
78
  }
75
79
 
76
80
  // ==================== Properties ====================
@@ -129,4 +133,60 @@ export class RemoteClient implements AgentX {
129
133
  async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {
130
134
  return this.rpcClient.call<T>(method as RpcMethod, params);
131
135
  }
136
+
137
+ // ==================== Private ====================
138
+
139
+ private createChatNamespace(): ChatNamespace {
140
+ const instance = this.runtime;
141
+ return {
142
+ 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 instance.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 instance.image.create({ containerId, ...imageParams });
162
+ const agentRes = await instance.agent.create({ imageId: imgRes.record.imageId });
163
+ return new AgentHandleImpl(
164
+ {
165
+ agentId: agentRes.agentId,
166
+ imageId: agentRes.imageId,
167
+ containerId: agentRes.containerId,
168
+ sessionId: agentRes.sessionId,
169
+ },
170
+ instance
171
+ );
172
+ },
173
+ async list() {
174
+ return instance.image.list();
175
+ },
176
+ async get(id) {
177
+ const res = await instance.image.get(id);
178
+ if (!res.record) return null;
179
+ const r = res.record;
180
+ return new AgentHandleImpl(
181
+ {
182
+ agentId: r.imageId,
183
+ imageId: r.imageId,
184
+ containerId: r.containerId,
185
+ sessionId: r.sessionId,
186
+ },
187
+ instance
188
+ );
189
+ },
190
+ };
191
+ }
132
192
  }
package/src/index.ts CHANGED
@@ -9,7 +9,8 @@
9
9
  * import { nodePlatform } from "@agentxjs/node-platform";
10
10
  *
11
11
  * const ax = createAgentX(nodePlatform({ createDriver }));
12
- * await ax.agent.create({ imageId: "..." });
12
+ * const agent = await ax.chat.create({ name: "Aristotle", embody: { model: "claude-sonnet-4-6" } });
13
+ * await agent.send("Hello!");
13
14
  * ```
14
15
  *
15
16
  * @example Remote mode
@@ -74,28 +75,20 @@ export function createAgentX(config?: PlatformConfig): AgentXBuilder {
74
75
  return getLocalClient().events;
75
76
  },
76
77
 
77
- get container() {
78
- return getLocalClient().container;
78
+ get runtime() {
79
+ return getLocalClient().runtime;
79
80
  },
80
81
 
81
- get image() {
82
- return getLocalClient().image;
82
+ get provider() {
83
+ return getLocalClient().provider;
83
84
  },
84
85
 
85
- get agent() {
86
- return getLocalClient().agent;
86
+ get chat() {
87
+ return getLocalClient().chat;
87
88
  },
88
89
 
89
- get session() {
90
- return getLocalClient().session;
91
- },
92
-
93
- get presentation() {
94
- return getLocalClient().presentation;
95
- },
96
-
97
- get llm() {
98
- return getLocalClient().llm;
90
+ get prototype() {
91
+ return getLocalClient().prototype;
99
92
  },
100
93
 
101
94
  on(type, handler) {
@@ -196,6 +189,7 @@ export { createServer, type ServerConfig } from "./server";
196
189
  export type {
197
190
  AgentCreateResponse,
198
191
  AgentGetResponse,
192
+ AgentHandle,
199
193
  AgentInfo,
200
194
  AgentListResponse,
201
195
  AgentNamespace,
@@ -203,12 +197,14 @@ export type {
203
197
  AgentXBuilder,
204
198
  AgentXServer,
205
199
  BaseResponse,
200
+ ChatNamespace,
206
201
  ConnectOptions,
207
202
  ContainerCreateResponse,
208
203
  ContainerGetResponse,
209
204
  ContainerInfo,
210
205
  ContainerListResponse,
211
206
  ContainerNamespace,
207
+ Embodiment,
212
208
  ImageCreateResponse,
213
209
  ImageGetResponse,
214
210
  ImageListResponse,
@@ -223,6 +219,12 @@ export type {
223
219
  MaybeAsync,
224
220
  MessageSendResponse,
225
221
  PresentationNamespace,
222
+ PrototypeCreateResponse,
223
+ PrototypeGetResponse,
224
+ PrototypeListResponse,
225
+ PrototypeNamespace,
226
+ PrototypeUpdateResponse,
227
+ RuntimeNamespace,
226
228
  ServeConfig,
227
229
  SessionNamespace,
228
230
  } from "./types";
@@ -1,20 +1,25 @@
1
1
  /**
2
2
  * Presentation namespace factory
3
3
  *
4
- * Single factory for both local and remote modes
5
- * Presentation only depends on the AgentX interface.
4
+ * Single factory for both local and remote modes.
6
5
  */
7
6
 
8
7
  import { messagesToConversations, Presentation, type PresentationOptions } from "../presentation";
9
- import type { AgentX, PresentationNamespace } from "../types";
8
+ import type { AgentX, ImageNamespace, PresentationNamespace } from "../types";
10
9
 
11
10
  /**
12
- * Create presentation namespace backed by any AgentX client
11
+ * Create presentation namespace.
12
+ *
13
+ * Takes the full AgentX (for Presentation event wiring) and the ImageNamespace
14
+ * (for message history), avoiding circular access to `instance` during construction.
13
15
  */
14
- export function createPresentations(agentx: AgentX): PresentationNamespace {
16
+ export function createPresentations(
17
+ agentx: AgentX,
18
+ imageNs: ImageNamespace
19
+ ): PresentationNamespace {
15
20
  return {
16
21
  async create(agentId: string, options?: PresentationOptions): Promise<Presentation> {
17
- const messages = await agentx.session.getMessages(agentId);
22
+ const messages = await imageNs.getMessages(agentId);
18
23
  const conversations = messagesToConversations(messages);
19
24
  return new Presentation(agentx, agentId, options, conversations);
20
25
  },