agentxjs 2.6.1 → 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.
- package/README.md +44 -1
- package/dist/chunk-JUZULVWQ.js +388 -0
- package/dist/chunk-JUZULVWQ.js.map +1 -0
- package/dist/index.d.ts +59 -289
- package/dist/index.js +124 -304
- package/dist/index.js.map +1 -1
- package/dist/server-MVOHQ5ZM.js +184 -0
- package/dist/server-MVOHQ5ZM.js.map +1 -0
- package/package.json +3 -3
- package/src/AgentHandle.ts +16 -14
- package/src/CommandHandler.ts +89 -204
- package/src/LocalClient.ts +21 -51
- package/src/RemoteClient.ts +20 -45
- package/src/index.ts +12 -26
- package/src/namespaces/agents.ts +34 -28
- package/src/namespaces/images.ts +21 -29
- package/src/namespaces/llm.ts +16 -10
- package/src/namespaces/presentations.ts +7 -7
- package/src/namespaces/sessions.ts +16 -14
- package/src/presentation/Presentation.ts +11 -11
- package/src/types.ts +64 -206
- package/dist/chunk-JTHR3AK6.js +0 -652
- package/dist/chunk-JTHR3AK6.js.map +0 -1
- package/dist/server-UCQISBKH.js +0 -7
- package/dist/server-UCQISBKH.js.map +0 -1
- package/src/namespaces/containers.ts +0 -68
- package/src/namespaces/prototypes.ts +0 -136
|
@@ -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.
|
|
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.
|
|
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.
|
|
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"
|
package/src/AgentHandle.ts
CHANGED
|
@@ -7,15 +7,15 @@
|
|
|
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";
|
|
16
16
|
|
|
17
17
|
export class AgentHandleImpl implements AgentHandle {
|
|
18
|
-
readonly
|
|
18
|
+
readonly instanceId: string;
|
|
19
19
|
readonly imageId: string;
|
|
20
20
|
readonly containerId: string;
|
|
21
21
|
readonly sessionId: string;
|
|
@@ -23,10 +23,10 @@ export class AgentHandleImpl implements AgentHandle {
|
|
|
23
23
|
private readonly ns: RuntimeNamespace;
|
|
24
24
|
|
|
25
25
|
constructor(
|
|
26
|
-
ids: {
|
|
26
|
+
ids: { instanceId: string; imageId: string; containerId: string; sessionId: string },
|
|
27
27
|
ns: RuntimeNamespace
|
|
28
28
|
) {
|
|
29
|
-
this.
|
|
29
|
+
this.instanceId = ids.instanceId;
|
|
30
30
|
this.imageId = ids.imageId;
|
|
31
31
|
this.containerId = ids.containerId;
|
|
32
32
|
this.sessionId = ids.sessionId;
|
|
@@ -34,11 +34,11 @@ export class AgentHandleImpl implements AgentHandle {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
async send(content: string | unknown[]): Promise<MessageSendResponse> {
|
|
37
|
-
return this.ns.session.send(this.
|
|
37
|
+
return this.ns.session.send(this.instanceId, content);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
async interrupt(): Promise<BaseResponse> {
|
|
41
|
-
return this.ns.session.interrupt(this.
|
|
41
|
+
return this.ns.session.interrupt(this.instanceId);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
async history(): Promise<Message[]> {
|
|
@@ -46,20 +46,22 @@ export class AgentHandleImpl implements AgentHandle {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
async present(options?: PresentationOptions): Promise<Presentation> {
|
|
49
|
-
return this.ns.present.create(this.
|
|
49
|
+
return this.ns.present.create(this.instanceId, options);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
async update(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
|
61
63
|
async delete(): Promise<void> {
|
|
62
|
-
await this.ns.
|
|
64
|
+
await this.ns.instance.destroy(this.instanceId);
|
|
63
65
|
await this.ns.image.delete(this.imageId);
|
|
64
66
|
}
|
|
65
67
|
}
|
package/src/CommandHandler.ts
CHANGED
|
@@ -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);
|
|
@@ -89,34 +82,22 @@ export class CommandHandler {
|
|
|
89
82
|
case "image.messages":
|
|
90
83
|
return await this.handleImageMessages(params);
|
|
91
84
|
|
|
92
|
-
//
|
|
93
|
-
case "
|
|
85
|
+
// Instance
|
|
86
|
+
case "instance.get":
|
|
94
87
|
return await this.handleAgentGet(params);
|
|
95
|
-
case "
|
|
88
|
+
case "instance.list":
|
|
96
89
|
return await this.handleAgentList(params);
|
|
97
|
-
case "
|
|
90
|
+
case "instance.destroy":
|
|
98
91
|
return await this.handleAgentDestroy(params);
|
|
99
|
-
case "
|
|
92
|
+
case "instance.destroyAll":
|
|
100
93
|
return await this.handleAgentDestroyAll(params);
|
|
101
|
-
case "
|
|
94
|
+
case "instance.interrupt":
|
|
102
95
|
return await this.handleAgentInterrupt(params);
|
|
103
96
|
|
|
104
97
|
// Message
|
|
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 {
|
|
174
|
-
containerId:
|
|
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
|
-
|
|
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
|
|
|
@@ -228,9 +198,9 @@ export class CommandHandler {
|
|
|
228
198
|
}
|
|
229
199
|
|
|
230
200
|
private async handleImageRun(params: unknown): Promise<RpcResponse> {
|
|
231
|
-
const { imageId,
|
|
201
|
+
const { imageId, instanceId: requestedInstanceId } = params as {
|
|
232
202
|
imageId: string;
|
|
233
|
-
|
|
203
|
+
instanceId?: string;
|
|
234
204
|
};
|
|
235
205
|
|
|
236
206
|
// Check if already have a running agent for this image
|
|
@@ -241,30 +211,30 @@ export class CommandHandler {
|
|
|
241
211
|
if (existingAgent) {
|
|
242
212
|
logger.debug("Reusing existing agent for image", {
|
|
243
213
|
imageId,
|
|
244
|
-
|
|
214
|
+
instanceId: existingAgent.instanceId,
|
|
245
215
|
});
|
|
246
216
|
return ok({
|
|
247
217
|
imageId,
|
|
248
|
-
|
|
218
|
+
instanceId: existingAgent.instanceId,
|
|
249
219
|
sessionId: existingAgent.sessionId,
|
|
250
220
|
containerId: existingAgent.containerId,
|
|
251
221
|
reused: true,
|
|
252
222
|
});
|
|
253
223
|
}
|
|
254
224
|
|
|
255
|
-
// Create new agent (with optional custom
|
|
225
|
+
// Create new agent (with optional custom instanceId)
|
|
256
226
|
const agent = await this.runtime.createAgent({
|
|
257
227
|
imageId,
|
|
258
|
-
|
|
228
|
+
instanceId: requestedInstanceId,
|
|
259
229
|
});
|
|
260
230
|
logger.info("Created new agent for image", {
|
|
261
231
|
imageId,
|
|
262
|
-
|
|
232
|
+
instanceId: agent.instanceId,
|
|
263
233
|
});
|
|
264
234
|
|
|
265
235
|
return ok({
|
|
266
236
|
imageId,
|
|
267
|
-
|
|
237
|
+
instanceId: agent.instanceId,
|
|
268
238
|
sessionId: agent.sessionId,
|
|
269
239
|
containerId: agent.containerId,
|
|
270
240
|
reused: false,
|
|
@@ -280,8 +250,8 @@ export class CommandHandler {
|
|
|
280
250
|
.find((a) => a.imageId === imageId && a.lifecycle === "running");
|
|
281
251
|
|
|
282
252
|
if (agent) {
|
|
283
|
-
await this.runtime.stopAgent(agent.
|
|
284
|
-
logger.info("Stopped agent for image", { imageId,
|
|
253
|
+
await this.runtime.stopAgent(agent.instanceId);
|
|
254
|
+
logger.info("Stopped agent for image", { imageId, instanceId: agent.instanceId });
|
|
285
255
|
} else {
|
|
286
256
|
logger.debug("No running agent found for image", { imageId });
|
|
287
257
|
}
|
|
@@ -295,7 +265,9 @@ export class CommandHandler {
|
|
|
295
265
|
updates: {
|
|
296
266
|
name?: string;
|
|
297
267
|
description?: string;
|
|
298
|
-
|
|
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
|
-
//
|
|
310
|
-
const {
|
|
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
|
|
296
|
+
embody: embodyUpdates,
|
|
315
297
|
updatedAt: Date.now(),
|
|
316
298
|
};
|
|
317
299
|
|
|
@@ -344,13 +326,13 @@ export class CommandHandler {
|
|
|
344
326
|
// ==================== Agent Commands ====================
|
|
345
327
|
|
|
346
328
|
private async handleAgentGet(params: unknown): Promise<RpcResponse> {
|
|
347
|
-
const {
|
|
348
|
-
const agent = this.runtime.getAgent(
|
|
329
|
+
const { instanceId } = params as { instanceId: string };
|
|
330
|
+
const agent = this.runtime.getAgent(instanceId);
|
|
349
331
|
|
|
350
332
|
return ok({
|
|
351
333
|
agent: agent
|
|
352
334
|
? {
|
|
353
|
-
|
|
335
|
+
instanceId: agent.instanceId,
|
|
354
336
|
imageId: agent.imageId,
|
|
355
337
|
containerId: agent.containerId,
|
|
356
338
|
sessionId: agent.sessionId,
|
|
@@ -369,7 +351,7 @@ export class CommandHandler {
|
|
|
369
351
|
|
|
370
352
|
return ok({
|
|
371
353
|
agents: agents.map((a) => ({
|
|
372
|
-
|
|
354
|
+
instanceId: a.instanceId,
|
|
373
355
|
imageId: a.imageId,
|
|
374
356
|
containerId: a.containerId,
|
|
375
357
|
sessionId: a.sessionId,
|
|
@@ -379,47 +361,47 @@ export class CommandHandler {
|
|
|
379
361
|
}
|
|
380
362
|
|
|
381
363
|
private async handleAgentDestroy(params: unknown): Promise<RpcResponse> {
|
|
382
|
-
const {
|
|
364
|
+
const { instanceId } = params as { instanceId: string };
|
|
383
365
|
|
|
384
366
|
// Check if agent exists first
|
|
385
|
-
const agent = this.runtime.getAgent(
|
|
367
|
+
const agent = this.runtime.getAgent(instanceId);
|
|
386
368
|
if (!agent) {
|
|
387
|
-
return ok({
|
|
369
|
+
return ok({ instanceId, success: false });
|
|
388
370
|
}
|
|
389
371
|
|
|
390
|
-
await this.runtime.destroyAgent(
|
|
391
|
-
return ok({
|
|
372
|
+
await this.runtime.destroyAgent(instanceId);
|
|
373
|
+
return ok({ instanceId, success: true });
|
|
392
374
|
}
|
|
393
375
|
|
|
394
376
|
private async handleAgentDestroyAll(params: unknown): Promise<RpcResponse> {
|
|
395
377
|
const { containerId } = params as { containerId: string };
|
|
396
378
|
const agents = this.runtime.getAgentsByContainer(containerId);
|
|
397
379
|
for (const agent of agents) {
|
|
398
|
-
await this.runtime.destroyAgent(agent.
|
|
380
|
+
await this.runtime.destroyAgent(agent.instanceId);
|
|
399
381
|
}
|
|
400
382
|
return ok({ containerId });
|
|
401
383
|
}
|
|
402
384
|
|
|
403
385
|
private async handleAgentInterrupt(params: unknown): Promise<RpcResponse> {
|
|
404
|
-
const {
|
|
405
|
-
this.runtime.interrupt(
|
|
406
|
-
return ok({
|
|
386
|
+
const { instanceId } = params as { instanceId: string };
|
|
387
|
+
this.runtime.interrupt(instanceId);
|
|
388
|
+
return ok({ instanceId });
|
|
407
389
|
}
|
|
408
390
|
|
|
409
391
|
// ==================== Message Commands ====================
|
|
410
392
|
|
|
411
393
|
private async handleMessageSend(params: unknown): Promise<RpcResponse> {
|
|
412
|
-
const {
|
|
413
|
-
|
|
394
|
+
const { instanceId, imageId, content } = params as {
|
|
395
|
+
instanceId?: string;
|
|
414
396
|
imageId?: string;
|
|
415
397
|
content: string | UserContentPart[];
|
|
416
398
|
};
|
|
417
399
|
|
|
418
|
-
let
|
|
400
|
+
let targetInstanceId: string;
|
|
419
401
|
|
|
420
|
-
if (
|
|
402
|
+
if (instanceId) {
|
|
421
403
|
// Direct agent reference
|
|
422
|
-
|
|
404
|
+
targetInstanceId = instanceId;
|
|
423
405
|
} else if (imageId) {
|
|
424
406
|
// Auto-activate image: find or create agent
|
|
425
407
|
const existingAgent = this.runtime
|
|
@@ -427,138 +409,41 @@ export class CommandHandler {
|
|
|
427
409
|
.find((a) => a.imageId === imageId && a.lifecycle === "running");
|
|
428
410
|
|
|
429
411
|
if (existingAgent) {
|
|
430
|
-
|
|
412
|
+
targetInstanceId = existingAgent.instanceId;
|
|
431
413
|
logger.debug("Using existing agent for message", {
|
|
432
414
|
imageId,
|
|
433
|
-
|
|
415
|
+
instanceId: targetInstanceId,
|
|
434
416
|
});
|
|
435
417
|
} else {
|
|
436
418
|
// Create new agent for this image
|
|
437
419
|
const agent = await this.runtime.createAgent({ imageId });
|
|
438
|
-
|
|
420
|
+
targetInstanceId = agent.instanceId;
|
|
439
421
|
logger.info("Auto-created agent for message", {
|
|
440
422
|
imageId,
|
|
441
|
-
|
|
423
|
+
instanceId: targetInstanceId,
|
|
442
424
|
});
|
|
443
425
|
}
|
|
444
426
|
} else {
|
|
445
|
-
return err(-32602, "Either
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
await this.runtime.receive(targetAgentId, content);
|
|
449
|
-
return ok({ agentId: targetAgentId, imageId });
|
|
450
|
-
}
|
|
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}`);
|
|
427
|
+
return err(-32602, "Either instanceId or imageId is required");
|
|
532
428
|
}
|
|
533
429
|
|
|
534
|
-
|
|
535
|
-
|
|
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 });
|
|
430
|
+
await this.runtime.receive(targetInstanceId, content);
|
|
431
|
+
return ok({ instanceId: targetInstanceId, imageId });
|
|
555
432
|
}
|
|
556
433
|
|
|
557
434
|
// ==================== LLM Provider Commands ====================
|
|
558
435
|
|
|
559
436
|
private async handleLLMCreate(params: unknown): Promise<RpcResponse> {
|
|
560
|
-
const {
|
|
561
|
-
containerId:
|
|
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",
|