agentxjs 2.0.3 → 2.0.5
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/dist/chunk-ZFL27HK7.js +467 -0
- package/dist/chunk-ZFL27HK7.js.map +1 -0
- package/dist/index.d.ts +185 -140
- package/dist/index.js +124 -84
- package/dist/index.js.map +1 -1
- package/dist/server-IFVYHIJF.js +7 -0
- package/dist/server-IFVYHIJF.js.map +1 -0
- package/package.json +4 -6
- package/src/CommandHandler.ts +424 -0
- package/src/LocalClient.ts +10 -10
- package/src/RemoteClient.ts +14 -14
- package/src/index.ts +125 -110
- package/src/namespaces/images.ts +12 -0
- package/src/namespaces/presentations.ts +1 -1
- package/src/presentation/Presentation.ts +2 -2
- package/src/server.ts +346 -0
- package/src/types.ts +89 -137
package/src/server.ts
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentX Server Implementation (JSON-RPC 2.0)
|
|
3
|
+
*
|
|
4
|
+
* Creates a WebSocket server that:
|
|
5
|
+
* 1. Accepts client connections
|
|
6
|
+
* 2. Handles JSON-RPC requests directly via CommandHandler
|
|
7
|
+
* 3. Broadcasts stream events as JSON-RPC notifications
|
|
8
|
+
*
|
|
9
|
+
* Message Types:
|
|
10
|
+
* - RPC Request (has id): Client → Server → Client (direct response)
|
|
11
|
+
* - RPC Notification (no id): Server → Client (stream events)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { CreateDriver } from "@agentxjs/core/driver";
|
|
15
|
+
import type { BusEvent, SystemEvent } from "@agentxjs/core/event";
|
|
16
|
+
import type { ChannelConnection } from "@agentxjs/core/network";
|
|
17
|
+
import {
|
|
18
|
+
createErrorResponse,
|
|
19
|
+
createStreamEvent,
|
|
20
|
+
createSuccessResponse,
|
|
21
|
+
isNotification,
|
|
22
|
+
isRequest,
|
|
23
|
+
parseMessage,
|
|
24
|
+
RpcErrorCodes,
|
|
25
|
+
type RpcMethod,
|
|
26
|
+
} from "@agentxjs/core/network";
|
|
27
|
+
import type { AgentXPlatform } from "@agentxjs/core/runtime";
|
|
28
|
+
import { createAgentXRuntime } from "@agentxjs/core/runtime";
|
|
29
|
+
import { createLogger } from "@deepracticex/logger";
|
|
30
|
+
import { CommandHandler } from "./CommandHandler";
|
|
31
|
+
import type { AgentXServer } from "./types";
|
|
32
|
+
|
|
33
|
+
const logger = createLogger("server/Server");
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Connection state
|
|
37
|
+
*/
|
|
38
|
+
interface ConnectionState {
|
|
39
|
+
connection: ChannelConnection;
|
|
40
|
+
subscribedTopics: Set<string>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Server configuration (supports both immediate and deferred platforms)
|
|
45
|
+
*/
|
|
46
|
+
export interface ServerConfig {
|
|
47
|
+
/**
|
|
48
|
+
* AgentX Platform — must provide `channelServer` for accepting WebSocket connections.
|
|
49
|
+
*/
|
|
50
|
+
platform: AgentXPlatform;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* LLM Driver factory function - creates Driver per Agent
|
|
54
|
+
*/
|
|
55
|
+
createDriver: CreateDriver;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Port to listen on (standalone mode)
|
|
59
|
+
*/
|
|
60
|
+
port?: number;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Host to bind to (default: "0.0.0.0")
|
|
64
|
+
*/
|
|
65
|
+
host?: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Existing HTTP server to attach to (attached mode)
|
|
69
|
+
*/
|
|
70
|
+
server?: import("@agentxjs/core/network").MinimalHTTPServer;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* WebSocket path when attached (default: "/ws")
|
|
74
|
+
*/
|
|
75
|
+
wsPath?: string;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Enable debug logging
|
|
79
|
+
*/
|
|
80
|
+
debug?: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create an AgentX server
|
|
85
|
+
*/
|
|
86
|
+
export async function createServer(config: ServerConfig): Promise<AgentXServer> {
|
|
87
|
+
const { wsPath = "/ws" } = config;
|
|
88
|
+
const platform = config.platform;
|
|
89
|
+
|
|
90
|
+
// Create runtime from platform + driver
|
|
91
|
+
const runtime = createAgentXRuntime(platform, config.createDriver);
|
|
92
|
+
|
|
93
|
+
// Get channel server from platform
|
|
94
|
+
const wsServer = platform.channelServer;
|
|
95
|
+
if (!wsServer) {
|
|
96
|
+
throw new Error("Platform must provide channelServer for server mode");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Create command handler (no longer needs eventBus)
|
|
100
|
+
const commandHandler = new CommandHandler(runtime);
|
|
101
|
+
|
|
102
|
+
// Track connections
|
|
103
|
+
const connections = new Map<string, ConnectionState>();
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Subscribe connection to a topic
|
|
107
|
+
*/
|
|
108
|
+
function subscribeToTopic(connectionId: string, topic: string): void {
|
|
109
|
+
const state = connections.get(connectionId);
|
|
110
|
+
if (!state || state.subscribedTopics.has(topic)) return;
|
|
111
|
+
|
|
112
|
+
state.subscribedTopics.add(topic);
|
|
113
|
+
logger.debug("Connection subscribed to topic", { connectionId, topic });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if event should be sent to connection based on subscriptions
|
|
118
|
+
*/
|
|
119
|
+
function shouldSendToConnection(state: ConnectionState, event: BusEvent): boolean {
|
|
120
|
+
// Skip internal driver events
|
|
121
|
+
if (event.source === "driver" && event.intent !== "notification") {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Skip command events (they are handled via RPC, not broadcast)
|
|
126
|
+
if (event.source === "command") {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check if subscribed to event's session
|
|
131
|
+
const eventWithContext = event as BusEvent & { context?: { sessionId?: string } };
|
|
132
|
+
const sessionId = eventWithContext.context?.sessionId;
|
|
133
|
+
if (sessionId && state.subscribedTopics.has(sessionId)) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Send to global subscribers
|
|
138
|
+
return state.subscribedTopics.has("global");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Send JSON-RPC response to a specific connection
|
|
143
|
+
*/
|
|
144
|
+
function sendResponse(connection: ChannelConnection, id: string | number, result: unknown): void {
|
|
145
|
+
const response = createSuccessResponse(id, result);
|
|
146
|
+
connection.send(JSON.stringify(response));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Send JSON-RPC error to a specific connection
|
|
151
|
+
*/
|
|
152
|
+
function sendError(
|
|
153
|
+
connection: ChannelConnection,
|
|
154
|
+
id: string | number | null,
|
|
155
|
+
code: number,
|
|
156
|
+
message: string
|
|
157
|
+
): void {
|
|
158
|
+
const response = createErrorResponse(id, code, message);
|
|
159
|
+
connection.send(JSON.stringify(response));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Handle new connections
|
|
163
|
+
wsServer.onConnection((connection) => {
|
|
164
|
+
const state: ConnectionState = {
|
|
165
|
+
connection,
|
|
166
|
+
subscribedTopics: new Set(["global"]),
|
|
167
|
+
};
|
|
168
|
+
connections.set(connection.id, state);
|
|
169
|
+
|
|
170
|
+
logger.info("Client connected", {
|
|
171
|
+
connectionId: connection.id,
|
|
172
|
+
totalConnections: connections.size,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Handle messages from client
|
|
176
|
+
connection.onMessage(async (message) => {
|
|
177
|
+
try {
|
|
178
|
+
const parsed = parseMessage(message);
|
|
179
|
+
|
|
180
|
+
// Handle single message (not batch)
|
|
181
|
+
if (!Array.isArray(parsed)) {
|
|
182
|
+
await handleParsedMessage(connection, state, parsed);
|
|
183
|
+
} else {
|
|
184
|
+
// Handle batch (not common, but supported by JSON-RPC 2.0)
|
|
185
|
+
for (const item of parsed) {
|
|
186
|
+
await handleParsedMessage(connection, state, item);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
logger.error("Failed to parse message", { error: (err as Error).message });
|
|
191
|
+
sendError(connection, null, RpcErrorCodes.PARSE_ERROR, "Parse error");
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Cleanup on disconnect
|
|
196
|
+
connection.onClose(() => {
|
|
197
|
+
connections.delete(connection.id);
|
|
198
|
+
logger.info("Client disconnected", {
|
|
199
|
+
connectionId: connection.id,
|
|
200
|
+
totalConnections: connections.size,
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Handle a parsed JSON-RPC message
|
|
207
|
+
*/
|
|
208
|
+
async function handleParsedMessage(
|
|
209
|
+
connection: ChannelConnection,
|
|
210
|
+
state: ConnectionState,
|
|
211
|
+
parsed: import("jsonrpc-lite").IParsedObject
|
|
212
|
+
): Promise<void> {
|
|
213
|
+
if (isRequest(parsed)) {
|
|
214
|
+
// JSON-RPC Request - handle and respond directly
|
|
215
|
+
const payload = parsed.payload as {
|
|
216
|
+
id: string | number;
|
|
217
|
+
method: string;
|
|
218
|
+
params: unknown;
|
|
219
|
+
};
|
|
220
|
+
const { id, method, params } = payload;
|
|
221
|
+
|
|
222
|
+
logger.debug("Received RPC request", { id, method });
|
|
223
|
+
|
|
224
|
+
// Call command handler
|
|
225
|
+
const result = await commandHandler.handle(method as RpcMethod, params);
|
|
226
|
+
|
|
227
|
+
if (result.success) {
|
|
228
|
+
sendResponse(connection, id, result.data);
|
|
229
|
+
} else {
|
|
230
|
+
sendError(connection, id, result.code, result.message);
|
|
231
|
+
}
|
|
232
|
+
} else if (isNotification(parsed)) {
|
|
233
|
+
// JSON-RPC Notification - control messages
|
|
234
|
+
const payload = parsed.payload as {
|
|
235
|
+
method: string;
|
|
236
|
+
params: unknown;
|
|
237
|
+
};
|
|
238
|
+
const { method, params } = payload;
|
|
239
|
+
|
|
240
|
+
logger.debug("Received notification", { method });
|
|
241
|
+
|
|
242
|
+
if (method === "subscribe") {
|
|
243
|
+
const { topic } = params as { topic: string };
|
|
244
|
+
subscribeToTopic(connection.id, topic);
|
|
245
|
+
} else if (method === "unsubscribe") {
|
|
246
|
+
const { topic } = params as { topic: string };
|
|
247
|
+
state.subscribedTopics.delete(topic);
|
|
248
|
+
logger.debug("Connection unsubscribed from topic", { connectionId: connection.id, topic });
|
|
249
|
+
} else if (method === "control.ack") {
|
|
250
|
+
// ACK for reliable delivery - handled by network layer
|
|
251
|
+
logger.debug("Received ACK notification");
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
// Invalid message
|
|
255
|
+
logger.warn("Received invalid JSON-RPC message");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Route internal events to connected clients as JSON-RPC notifications
|
|
260
|
+
platform.eventBus.onAny((event) => {
|
|
261
|
+
// Only broadcast broadcastable events
|
|
262
|
+
if (!shouldBroadcastEvent(event)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Get topic from event context
|
|
267
|
+
const eventWithContext = event as BusEvent & { context?: { sessionId?: string } };
|
|
268
|
+
const topic = eventWithContext.context?.sessionId || "global";
|
|
269
|
+
|
|
270
|
+
// Wrap as JSON-RPC notification
|
|
271
|
+
const notification = createStreamEvent(topic, event as SystemEvent);
|
|
272
|
+
const message = JSON.stringify(notification);
|
|
273
|
+
|
|
274
|
+
for (const [connectionId, state] of connections) {
|
|
275
|
+
if (shouldSendToConnection(state, event)) {
|
|
276
|
+
state.connection.sendReliable(message, {
|
|
277
|
+
timeout: 10000,
|
|
278
|
+
onTimeout: () => {
|
|
279
|
+
logger.warn("Event ACK timeout", {
|
|
280
|
+
connectionId,
|
|
281
|
+
eventType: event.type,
|
|
282
|
+
});
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Check if event should be broadcast
|
|
291
|
+
*/
|
|
292
|
+
function shouldBroadcastEvent(event: BusEvent): boolean {
|
|
293
|
+
// Skip internal driver events
|
|
294
|
+
if (event.source === "driver" && event.intent !== "notification") {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Skip command events (handled via RPC)
|
|
299
|
+
if (event.source === "command") {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Check broadcastable flag
|
|
304
|
+
const systemEvent = event as SystemEvent;
|
|
305
|
+
if (systemEvent.broadcastable === false) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Attach to existing server if provided
|
|
313
|
+
if (config.server) {
|
|
314
|
+
wsServer.attach(config.server, wsPath);
|
|
315
|
+
logger.info("WebSocket attached to existing server", { path: wsPath });
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
async listen(port?: number, host?: string) {
|
|
320
|
+
if (config.server) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
"Cannot listen when attached to existing server. The server should call listen() instead."
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const listenPort = port ?? config.port ?? 5200;
|
|
327
|
+
const listenHost = host ?? config.host ?? "0.0.0.0";
|
|
328
|
+
|
|
329
|
+
await wsServer.listen(listenPort, listenHost);
|
|
330
|
+
logger.info("Server listening", { port: listenPort, host: listenHost });
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
async close() {
|
|
334
|
+
await wsServer.close();
|
|
335
|
+
logger.info("Server closed");
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
async dispose() {
|
|
339
|
+
// Cleanup in order
|
|
340
|
+
await wsServer.dispose();
|
|
341
|
+
commandHandler.dispose();
|
|
342
|
+
await runtime.shutdown();
|
|
343
|
+
logger.info("Server disposed");
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { Message } from "@agentxjs/core/agent";
|
|
6
|
-
import type { CreateDriver } from "@agentxjs/core/driver";
|
|
7
6
|
import type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from "@agentxjs/core/event";
|
|
8
7
|
import type { AgentXPlatform } from "@agentxjs/core/runtime";
|
|
9
8
|
import type { Presentation, PresentationOptions } from "./presentation";
|
|
@@ -18,105 +17,16 @@ import type { Presentation, PresentationOptions } from "./presentation";
|
|
|
18
17
|
export type MaybeAsync<T> = T | (() => T) | (() => Promise<T>);
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
|
-
*
|
|
20
|
+
* Internal config passed to RemoteClient
|
|
21
|
+
* @internal
|
|
22
22
|
*/
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* AgentX unified configuration
|
|
27
|
-
*
|
|
28
|
-
* Supports two modes:
|
|
29
|
-
* - **Local mode**: `apiKey` present → embedded Runtime + MonoDriver
|
|
30
|
-
* - **Remote mode**: `serverUrl` present → WebSocket client
|
|
31
|
-
*/
|
|
32
|
-
export interface AgentXConfig {
|
|
33
|
-
// ===== Local Mode =====
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* API key for LLM provider (local mode)
|
|
37
|
-
* If present, enables local mode with embedded Runtime
|
|
38
|
-
*/
|
|
39
|
-
apiKey?: string;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* LLM provider (local mode)
|
|
43
|
-
* @default "anthropic"
|
|
44
|
-
*/
|
|
45
|
-
provider?: LLMProvider;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Model ID (local mode)
|
|
49
|
-
*/
|
|
50
|
-
model?: string;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Base URL for API endpoint (local mode, for proxy/private deployments)
|
|
54
|
-
*/
|
|
55
|
-
baseUrl?: string;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Data storage path (local mode)
|
|
59
|
-
* @default ":memory:" (in-memory storage)
|
|
60
|
-
*/
|
|
61
|
-
dataPath?: string;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Custom CreateDriver factory (local mode, advanced)
|
|
65
|
-
* If provided, overrides the default MonoDriver
|
|
66
|
-
*/
|
|
67
|
-
createDriver?: CreateDriver;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Custom AgentXPlatform (local mode, advanced)
|
|
71
|
-
* If provided, overrides the default NodePlatform
|
|
72
|
-
*/
|
|
73
|
-
customPlatform?: AgentXPlatform;
|
|
74
|
-
|
|
75
|
-
// ===== Remote Mode =====
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* WebSocket server URL (remote mode)
|
|
79
|
-
* If present, enables remote mode
|
|
80
|
-
*/
|
|
81
|
-
serverUrl?: string;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Headers for authentication (remote mode, static or dynamic)
|
|
85
|
-
* In Node.js: sent during WebSocket handshake
|
|
86
|
-
* In browsers: sent as first auth message (WebSocket API limitation)
|
|
87
|
-
*/
|
|
23
|
+
export interface RemoteClientConfig {
|
|
24
|
+
serverUrl: string;
|
|
88
25
|
headers?: MaybeAsync<Record<string, string>>;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Business context injected into all requests (remote mode)
|
|
92
|
-
* Useful for passing userId, tenantId, permissions, etc.
|
|
93
|
-
*/
|
|
94
26
|
context?: MaybeAsync<Record<string, unknown>>;
|
|
95
|
-
|
|
96
|
-
// ===== Common =====
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Log level for AgentX runtime
|
|
100
|
-
* Controls verbosity of console/file logging.
|
|
101
|
-
* @default "info"
|
|
102
|
-
*/
|
|
103
|
-
logLevel?: "debug" | "info" | "warn" | "error" | "silent";
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Request timeout in milliseconds (default: 30000)
|
|
107
|
-
*/
|
|
108
27
|
timeout?: number;
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Enable debug logging
|
|
112
|
-
* @deprecated Use `logLevel: "debug"` instead
|
|
113
|
-
*/
|
|
114
|
-
debug?: boolean;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Auto reconnect on connection loss (default: true, remote mode only)
|
|
118
|
-
*/
|
|
119
28
|
autoReconnect?: boolean;
|
|
29
|
+
customPlatform?: AgentXPlatform;
|
|
120
30
|
}
|
|
121
31
|
|
|
122
32
|
// ============================================================================
|
|
@@ -319,6 +229,11 @@ export interface ImageNamespace {
|
|
|
319
229
|
* Delete image
|
|
320
230
|
*/
|
|
321
231
|
delete(imageId: string): Promise<BaseResponse>;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get message history for an image
|
|
235
|
+
*/
|
|
236
|
+
getMessages(imageId: string): Promise<Message[]>;
|
|
322
237
|
}
|
|
323
238
|
|
|
324
239
|
/**
|
|
@@ -375,7 +290,7 @@ export interface PresentationNamespace {
|
|
|
375
290
|
*
|
|
376
291
|
* @example
|
|
377
292
|
* ```typescript
|
|
378
|
-
* const pres = agentx.
|
|
293
|
+
* const pres = agentx.presentation.create(agentId, {
|
|
379
294
|
* onUpdate: (state) => renderUI(state),
|
|
380
295
|
* onError: (error) => console.error(error),
|
|
381
296
|
* });
|
|
@@ -392,11 +307,11 @@ export interface PresentationNamespace {
|
|
|
392
307
|
// ============================================================================
|
|
393
308
|
|
|
394
309
|
/**
|
|
395
|
-
* AgentX Client SDK
|
|
310
|
+
* AgentX Client SDK — unified interface for local, remote, and server modes
|
|
396
311
|
*/
|
|
397
312
|
export interface AgentX {
|
|
398
313
|
/**
|
|
399
|
-
* Check if connected
|
|
314
|
+
* Check if connected/active
|
|
400
315
|
*/
|
|
401
316
|
readonly connected: boolean;
|
|
402
317
|
|
|
@@ -407,59 +322,96 @@ export interface AgentX {
|
|
|
407
322
|
|
|
408
323
|
// ==================== Namespaced Operations ====================
|
|
409
324
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
readonly
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Image operations
|
|
417
|
-
*/
|
|
418
|
-
readonly images: ImageNamespace;
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Agent operations
|
|
422
|
-
*/
|
|
423
|
-
readonly agents: AgentNamespace;
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* Session operations (messaging)
|
|
427
|
-
*/
|
|
428
|
-
readonly sessions: SessionNamespace;
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Presentation operations (UI integration)
|
|
432
|
-
*/
|
|
433
|
-
readonly presentations: PresentationNamespace;
|
|
325
|
+
readonly container: ContainerNamespace;
|
|
326
|
+
readonly image: ImageNamespace;
|
|
327
|
+
readonly agent: AgentNamespace;
|
|
328
|
+
readonly session: SessionNamespace;
|
|
329
|
+
readonly presentation: PresentationNamespace;
|
|
434
330
|
|
|
435
331
|
// ==================== Event Subscription ====================
|
|
436
332
|
|
|
437
|
-
/**
|
|
438
|
-
* Subscribe to specific event type
|
|
439
|
-
*/
|
|
440
333
|
on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe;
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Subscribe to all events
|
|
444
|
-
*/
|
|
445
334
|
onAny(handler: BusEventHandler): Unsubscribe;
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Subscribe to session events
|
|
449
|
-
*/
|
|
450
335
|
subscribe(sessionId: string): void;
|
|
451
336
|
|
|
452
337
|
// ==================== Lifecycle ====================
|
|
453
338
|
|
|
339
|
+
disconnect(): Promise<void>;
|
|
340
|
+
dispose(): Promise<void>;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ============================================================================
|
|
344
|
+
// Fluent Builder Interface
|
|
345
|
+
// ============================================================================
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Options for connecting to a remote AgentX server
|
|
349
|
+
*/
|
|
350
|
+
export interface ConnectOptions {
|
|
351
|
+
/** Authentication headers */
|
|
352
|
+
headers?: MaybeAsync<Record<string, string>>;
|
|
353
|
+
/** Business context injected into requests */
|
|
354
|
+
context?: MaybeAsync<Record<string, unknown>>;
|
|
355
|
+
/** Request timeout in ms (default: 30000) */
|
|
356
|
+
timeout?: number;
|
|
357
|
+
/** Auto reconnect on disconnect (default: true) */
|
|
358
|
+
autoReconnect?: boolean;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Configuration for serving as an AgentX server
|
|
363
|
+
*/
|
|
364
|
+
export interface ServeConfig {
|
|
365
|
+
/** Port to listen on (default: 5200) */
|
|
366
|
+
port?: number;
|
|
367
|
+
/** Host to bind to (default: "0.0.0.0") */
|
|
368
|
+
host?: string;
|
|
369
|
+
/** Existing HTTP server to attach to */
|
|
370
|
+
server?: unknown;
|
|
371
|
+
/** WebSocket path when attached (default: "/ws") */
|
|
372
|
+
wsPath?: string;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Server instance returned by serve()
|
|
377
|
+
*/
|
|
378
|
+
export interface AgentXServer {
|
|
379
|
+
listen(port?: number, host?: string): Promise<void>;
|
|
380
|
+
close(): Promise<void>;
|
|
381
|
+
dispose(): Promise<void>;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* AgentXBuilder — fluent API entry point
|
|
386
|
+
*
|
|
387
|
+
* Created by `createAgentX(platform?)`. The builder itself is an AgentX
|
|
388
|
+
* instance (local mode). Call `.connect()` to get a remote client,
|
|
389
|
+
* or `.serve()` to start a server.
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* const ax = createAgentX(node({ createDriver }))
|
|
394
|
+
*
|
|
395
|
+
* // Local use
|
|
396
|
+
* await ax.agent.create({ imageId: "..." })
|
|
397
|
+
*
|
|
398
|
+
* // Connect to remote server
|
|
399
|
+
* const client = await ax.connect("wss://...")
|
|
400
|
+
*
|
|
401
|
+
* // Serve as server
|
|
402
|
+
* const server = await ax.serve({ port: 3100 })
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
export interface AgentXBuilder extends AgentX {
|
|
454
406
|
/**
|
|
455
|
-
*
|
|
407
|
+
* Connect to a remote AgentX server
|
|
456
408
|
*/
|
|
457
|
-
|
|
409
|
+
connect(serverUrl: string, options?: ConnectOptions): Promise<AgentX>;
|
|
458
410
|
|
|
459
411
|
/**
|
|
460
|
-
*
|
|
412
|
+
* Start serving as an AgentX server
|
|
461
413
|
*/
|
|
462
|
-
|
|
414
|
+
serve(config?: ServeConfig): Promise<AgentXServer>;
|
|
463
415
|
}
|
|
464
416
|
|
|
465
417
|
// ============================================================================
|