@agentxjs/core 2.0.1 → 3.0.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/dist/network/index.d.ts +2 -220
- package/dist/network/index.js.map +1 -1
- package/dist/platform/index.d.ts +11 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/{RpcClient-CMdhJxjS.d.ts → types-CTV8Z9PI.d.ts} +224 -6
- package/package.json +1 -1
- package/src/network/RpcClient.ts +5 -5
- package/src/network/index.ts +1 -1
- package/src/platform/types.ts +13 -3
package/dist/network/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as ControlAckParams, N as NotificationMethod,
|
|
1
|
+
export { A as ChannelClient, w as ChannelClientFactory, B as ChannelClientOptions, D as ChannelClientProvider, E as ChannelConnection, F as ChannelServer, G as ChannelServerOptions, H as ChannelServerProvider, I as ConnectionState, C as ControlAckParams, M as MinimalHTTPServer, N as NotificationMethod, z as RpcClient, x as RpcClientConfig, y as RpcClientState, u as RpcErrorCodes, R as RpcErrorResponse, a as RpcMethod, b as RpcNotification, c as RpcRequest, d as RpcSuccessResponse, J as SendReliableOptions, S as StreamEventParams, U as Unsubscribe, e as createAckNotification, f as createErrorResponse, g as createNotification, h as createRequest, i as createStreamEvent, j as createSuccessResponse, k as eventTypeToRpcMethod, l as isControlAck, m as isErrorResponse, n as isInvalid, o as isNotification, p as isRequest, q as isStreamEvent, r as isSuccessResponse, s as parseMessage, t as parseMessageObject, v as rpcMethodToResponseType } from '../types-CTV8Z9PI.js';
|
|
2
2
|
export { JsonRpcError } from 'jsonrpc-lite';
|
|
3
3
|
import '../base-m40r3Qgu.js';
|
|
4
4
|
|
|
@@ -58,222 +58,4 @@ declare function unwrapMessage(wrapper: ReliableWrapper): string;
|
|
|
58
58
|
*/
|
|
59
59
|
declare function generateMessageId(): string;
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
* Network Types - Channel interfaces for client-server communication
|
|
63
|
-
*
|
|
64
|
-
* Provides transport-agnostic interfaces that can be implemented with:
|
|
65
|
-
* - WebSocket (Node.js, Browser)
|
|
66
|
-
* - Durable Objects WebSocket (Cloudflare Workers)
|
|
67
|
-
* - HTTP/2, gRPC, etc.
|
|
68
|
-
*/
|
|
69
|
-
/**
|
|
70
|
-
* Unsubscribe function type
|
|
71
|
-
*/
|
|
72
|
-
type Unsubscribe = () => void;
|
|
73
|
-
/**
|
|
74
|
-
* Minimal HTTP server interface for attaching WebSocket
|
|
75
|
-
* Avoids Node.js dependency in types package
|
|
76
|
-
*/
|
|
77
|
-
interface MinimalHTTPServer {
|
|
78
|
-
on(event: "upgrade", listener: (request: unknown, socket: unknown, head: unknown) => void): void;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Options for reliable message sending
|
|
82
|
-
*/
|
|
83
|
-
interface SendReliableOptions {
|
|
84
|
-
/**
|
|
85
|
-
* Callback when client acknowledges receipt
|
|
86
|
-
*/
|
|
87
|
-
onAck?: () => void;
|
|
88
|
-
/**
|
|
89
|
-
* Timeout in milliseconds (default: 5000)
|
|
90
|
-
*/
|
|
91
|
-
timeout?: number;
|
|
92
|
-
/**
|
|
93
|
-
* Callback when ACK times out
|
|
94
|
-
*/
|
|
95
|
-
onTimeout?: () => void;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* ChannelConnection - Server-side representation of a client connection
|
|
99
|
-
*/
|
|
100
|
-
interface ChannelConnection {
|
|
101
|
-
/**
|
|
102
|
-
* Unique connection ID
|
|
103
|
-
*/
|
|
104
|
-
readonly id: string;
|
|
105
|
-
/**
|
|
106
|
-
* Send message to this client (fire-and-forget)
|
|
107
|
-
*/
|
|
108
|
-
send(message: string): void;
|
|
109
|
-
/**
|
|
110
|
-
* Send message with acknowledgment
|
|
111
|
-
*
|
|
112
|
-
* The message is wrapped with a unique ID. Client automatically sends ACK
|
|
113
|
-
* when received. Server triggers onAck callback upon receiving ACK.
|
|
114
|
-
*
|
|
115
|
-
* This is handled transparently by the Network layer.
|
|
116
|
-
*/
|
|
117
|
-
sendReliable(message: string, options?: SendReliableOptions): void;
|
|
118
|
-
/**
|
|
119
|
-
* Register message handler
|
|
120
|
-
*/
|
|
121
|
-
onMessage(handler: (message: string) => void): Unsubscribe;
|
|
122
|
-
/**
|
|
123
|
-
* Register close handler
|
|
124
|
-
*/
|
|
125
|
-
onClose(handler: () => void): Unsubscribe;
|
|
126
|
-
/**
|
|
127
|
-
* Register error handler
|
|
128
|
-
*/
|
|
129
|
-
onError(handler: (error: Error) => void): Unsubscribe;
|
|
130
|
-
/**
|
|
131
|
-
* Close this connection
|
|
132
|
-
*/
|
|
133
|
-
close(): void;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* ChannelServer - Accepts client connections
|
|
137
|
-
*/
|
|
138
|
-
interface ChannelServer {
|
|
139
|
-
/**
|
|
140
|
-
* Start listening on a port (standalone mode)
|
|
141
|
-
*/
|
|
142
|
-
listen(port: number, host?: string): Promise<void>;
|
|
143
|
-
/**
|
|
144
|
-
* Attach to an existing HTTP server
|
|
145
|
-
*/
|
|
146
|
-
attach(server: MinimalHTTPServer, path?: string): void;
|
|
147
|
-
/**
|
|
148
|
-
* Register connection handler
|
|
149
|
-
*/
|
|
150
|
-
onConnection(handler: (connection: ChannelConnection) => void): Unsubscribe;
|
|
151
|
-
/**
|
|
152
|
-
* Broadcast message to all connected clients
|
|
153
|
-
*/
|
|
154
|
-
broadcast(message: string): void;
|
|
155
|
-
/**
|
|
156
|
-
* Close server and all connections
|
|
157
|
-
*/
|
|
158
|
-
close(): Promise<void>;
|
|
159
|
-
/**
|
|
160
|
-
* Dispose resources
|
|
161
|
-
*/
|
|
162
|
-
dispose(): Promise<void>;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* ChannelServerOptions - Server configuration
|
|
166
|
-
*/
|
|
167
|
-
interface ChannelServerOptions {
|
|
168
|
-
/**
|
|
169
|
-
* Enable heartbeat/ping-pong (default: true)
|
|
170
|
-
*/
|
|
171
|
-
heartbeat?: boolean;
|
|
172
|
-
/**
|
|
173
|
-
* Heartbeat interval in ms (default: 30000)
|
|
174
|
-
*/
|
|
175
|
-
heartbeatInterval?: number;
|
|
176
|
-
/**
|
|
177
|
-
* Enable debug logging (default: false)
|
|
178
|
-
*/
|
|
179
|
-
debug?: boolean;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Connection state
|
|
183
|
-
*/
|
|
184
|
-
type ConnectionState = "connecting" | "open" | "closing" | "closed";
|
|
185
|
-
/**
|
|
186
|
-
* ChannelClient - Connects to server
|
|
187
|
-
*/
|
|
188
|
-
interface ChannelClient {
|
|
189
|
-
/**
|
|
190
|
-
* Connection state
|
|
191
|
-
*/
|
|
192
|
-
readonly readyState: ConnectionState;
|
|
193
|
-
/**
|
|
194
|
-
* Connect to server
|
|
195
|
-
*/
|
|
196
|
-
connect(): Promise<void>;
|
|
197
|
-
/**
|
|
198
|
-
* Send message to server
|
|
199
|
-
*/
|
|
200
|
-
send(message: string): void;
|
|
201
|
-
/**
|
|
202
|
-
* Register message handler
|
|
203
|
-
*/
|
|
204
|
-
onMessage(handler: (message: string) => void): Unsubscribe;
|
|
205
|
-
/**
|
|
206
|
-
* Register open handler
|
|
207
|
-
*/
|
|
208
|
-
onOpen(handler: () => void): Unsubscribe;
|
|
209
|
-
/**
|
|
210
|
-
* Register close handler
|
|
211
|
-
*/
|
|
212
|
-
onClose(handler: () => void): Unsubscribe;
|
|
213
|
-
/**
|
|
214
|
-
* Register error handler
|
|
215
|
-
*/
|
|
216
|
-
onError(handler: (error: Error) => void): Unsubscribe;
|
|
217
|
-
/**
|
|
218
|
-
* Close connection
|
|
219
|
-
*/
|
|
220
|
-
close(): void;
|
|
221
|
-
/**
|
|
222
|
-
* Dispose resources
|
|
223
|
-
*/
|
|
224
|
-
dispose(): void;
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* ChannelClientOptions - Client configuration
|
|
228
|
-
*/
|
|
229
|
-
interface ChannelClientOptions {
|
|
230
|
-
/**
|
|
231
|
-
* Server URL
|
|
232
|
-
*/
|
|
233
|
-
serverUrl: string;
|
|
234
|
-
/**
|
|
235
|
-
* Enable auto-reconnect (default: true in browser, false in Node.js)
|
|
236
|
-
*/
|
|
237
|
-
autoReconnect?: boolean;
|
|
238
|
-
/**
|
|
239
|
-
* Min reconnection delay in ms (default: 1000)
|
|
240
|
-
*/
|
|
241
|
-
minReconnectionDelay?: number;
|
|
242
|
-
/**
|
|
243
|
-
* Max reconnection delay in ms (default: 10000)
|
|
244
|
-
*/
|
|
245
|
-
maxReconnectionDelay?: number;
|
|
246
|
-
/**
|
|
247
|
-
* Max retry attempts (default: Infinity)
|
|
248
|
-
*/
|
|
249
|
-
maxRetries?: number;
|
|
250
|
-
/**
|
|
251
|
-
* Connection timeout in ms (default: 4000)
|
|
252
|
-
*/
|
|
253
|
-
connectionTimeout?: number;
|
|
254
|
-
/**
|
|
255
|
-
* Enable debug logging (default: false)
|
|
256
|
-
*/
|
|
257
|
-
debug?: boolean;
|
|
258
|
-
/**
|
|
259
|
-
* Custom headers for WebSocket connection
|
|
260
|
-
*
|
|
261
|
-
* - Node.js: Headers are sent during WebSocket handshake
|
|
262
|
-
* - Browser: Headers are sent in first authentication message
|
|
263
|
-
*/
|
|
264
|
-
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* ChannelServerProvider - Factory for creating ChannelServer instances
|
|
268
|
-
*/
|
|
269
|
-
interface ChannelServerProvider {
|
|
270
|
-
createServer(options?: ChannelServerOptions): ChannelServer;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* ChannelClientProvider - Factory for creating ChannelClient instances
|
|
274
|
-
*/
|
|
275
|
-
interface ChannelClientProvider {
|
|
276
|
-
createClient(options: ChannelClientOptions): ChannelClient;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
export { type AckMessage, type ChannelClient, type ChannelClientOptions, type ChannelClientProvider, type ChannelConnection, type ChannelServer, type ChannelServerOptions, type ChannelServerProvider, type ConnectionState, type MinimalHTTPServer, type ReliableWrapper, type SendReliableOptions, type Unsubscribe, createAck, generateMessageId, isAckMessage, isReliableWrapper, unwrapMessage, wrapMessage };
|
|
61
|
+
export { type AckMessage, type ReliableWrapper, createAck, generateMessageId, isAckMessage, isReliableWrapper, unwrapMessage, wrapMessage };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/network/jsonrpc.ts","../../src/network/protocol.ts","../../src/network/RpcClient.ts"],"sourcesContent":["/**\n * JSON-RPC 2.0 Protocol for AgentX Network Communication\n *\n * Uses jsonrpc-lite for message parsing/serialization.\n *\n * Message Types:\n * - Request: Client → Server (has id, expects response)\n * - Response: Server → Client (success or error)\n * - Notification: Server → Client (no id, stream events)\n *\n * @see https://www.jsonrpc.org/specification\n */\n\nimport type { IParsedObject, JsonRpc } from \"jsonrpc-lite\";\nimport {\n JsonRpcError,\n error as jsonrpcError,\n notification as jsonrpcNotification,\n parse as jsonrpcParse,\n parseObject as jsonrpcParseObject,\n request as jsonrpcRequest,\n success as jsonrpcSuccess,\n} from \"jsonrpc-lite\";\nimport type { SystemEvent } from \"../event/types/base\";\n\n// ============================================================================\n// Re-export jsonrpc-lite types and functions\n// ============================================================================\n\nexport { JsonRpcError };\nexport type { IParsedObject, JsonRpc };\n\n// ============================================================================\n// RPC Method Names\n// ============================================================================\n\n/**\n * All RPC method names supported by AgentX\n */\nexport type RpcMethod =\n // Container\n | \"container.create\"\n | \"container.get\"\n | \"container.list\"\n // Image\n | \"image.create\"\n | \"image.get\"\n | \"image.list\"\n | \"image.delete\"\n | \"image.run\"\n | \"image.stop\"\n | \"image.update\"\n | \"image.messages\"\n // Agent\n | \"agent.get\"\n | \"agent.list\"\n | \"agent.destroy\"\n | \"agent.destroyAll\"\n | \"agent.interrupt\"\n // Message\n | \"message.send\";\n\n/**\n * Notification method names (server push)\n */\nexport type NotificationMethod =\n | \"stream.event\" // Stream events (text_delta, tool_call, etc.)\n | \"control.ack\"; // ACK for reliable delivery\n\n// ============================================================================\n// Request/Response Type Definitions\n// ============================================================================\n\n/**\n * JSON-RPC Request structure\n */\nexport interface RpcRequest<M extends RpcMethod = RpcMethod, P = unknown> {\n jsonrpc: \"2.0\";\n method: M;\n params: P;\n id: string | number;\n}\n\n/**\n * JSON-RPC Success Response structure\n */\nexport interface RpcSuccessResponse<R = unknown> {\n jsonrpc: \"2.0\";\n result: R;\n id: string | number;\n}\n\n/**\n * JSON-RPC Error Response structure\n */\nexport interface RpcErrorResponse {\n jsonrpc: \"2.0\";\n error: {\n code: number;\n message: string;\n data?: unknown;\n };\n id: string | number | null;\n}\n\n/**\n * JSON-RPC Notification structure (no id, no response expected)\n */\nexport interface RpcNotification<M extends NotificationMethod = NotificationMethod, P = unknown> {\n jsonrpc: \"2.0\";\n method: M;\n params: P;\n}\n\n/**\n * Stream event notification params\n */\nexport interface StreamEventParams {\n topic: string;\n event: SystemEvent;\n}\n\n/**\n * Control ACK notification params\n */\nexport interface ControlAckParams {\n msgId: string;\n}\n\n// ============================================================================\n// Standard JSON-RPC Error Codes\n// ============================================================================\n\nexport const RpcErrorCodes = {\n // Standard JSON-RPC errors\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n // Server errors (reserved: -32000 to -32099)\n SERVER_ERROR: -32000,\n // Application errors (custom)\n NOT_FOUND: 404,\n UNAUTHORIZED: 401,\n FORBIDDEN: 403,\n TIMEOUT: 408,\n} as const;\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create a JSON-RPC request\n */\nexport function createRequest(\n id: string | number,\n method: RpcMethod | string,\n params: unknown\n): JsonRpc {\n return jsonrpcRequest(id, method, params as Record<string, unknown>);\n}\n\n/**\n * Create a JSON-RPC notification (no response expected)\n */\nexport function createNotification(method: NotificationMethod | string, params: unknown): JsonRpc {\n return jsonrpcNotification(method, params as Record<string, unknown>);\n}\n\n/**\n * Create a stream event notification\n */\nexport function createStreamEvent(topic: string, event: SystemEvent): JsonRpc {\n return jsonrpcNotification(\"stream.event\", { topic, event });\n}\n\n/**\n * Create an ACK notification\n */\nexport function createAckNotification(msgId: string): JsonRpc {\n return jsonrpcNotification(\"control.ack\", { msgId });\n}\n\n/**\n * Create a success response\n */\nexport function createSuccessResponse(id: string | number, result: unknown): JsonRpc {\n return jsonrpcSuccess(id, result as Record<string, unknown>);\n}\n\n/**\n * Create an error response\n */\nexport function createErrorResponse(\n id: string | number | null,\n code: number,\n message: string,\n data?: unknown\n): JsonRpc {\n return jsonrpcError(id, new JsonRpcError(message, code, data));\n}\n\n/**\n * Parse a JSON-RPC message string\n */\nexport function parseMessage(message: string): IParsedObject | IParsedObject[] {\n return jsonrpcParse(message);\n}\n\n/**\n * Parse a JSON-RPC message object\n */\nexport function parseMessageObject(obj: unknown): IParsedObject {\n return jsonrpcParseObject(obj);\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Check if parsed message is a request\n */\nexport function isRequest(parsed: IParsedObject): boolean {\n return parsed.type === \"request\";\n}\n\n/**\n * Check if parsed message is a notification\n */\nexport function isNotification(parsed: IParsedObject): boolean {\n return parsed.type === \"notification\";\n}\n\n/**\n * Check if parsed message is a success response\n */\nexport function isSuccessResponse(parsed: IParsedObject): boolean {\n return parsed.type === \"success\";\n}\n\n/**\n * Check if parsed message is an error response\n */\nexport function isErrorResponse(parsed: IParsedObject): boolean {\n return parsed.type === \"error\";\n}\n\n/**\n * Check if parsed message is invalid\n */\nexport function isInvalid(parsed: IParsedObject): boolean {\n return parsed.type === \"invalid\";\n}\n\n/**\n * Check if notification is a stream event\n */\nexport function isStreamEvent(parsed: IParsedObject): parsed is IParsedObject & {\n payload: RpcNotification<\"stream.event\", StreamEventParams>;\n} {\n if (parsed.type !== \"notification\") return false;\n const payload = parsed.payload as RpcNotification;\n return payload.method === \"stream.event\";\n}\n\n/**\n * Check if notification is a control ACK\n */\nexport function isControlAck(parsed: IParsedObject): parsed is IParsedObject & {\n payload: RpcNotification<\"control.ack\", ControlAckParams>;\n} {\n if (parsed.type !== \"notification\") return false;\n const payload = parsed.payload as RpcNotification;\n return payload.method === \"control.ack\";\n}\n\n// ============================================================================\n// Method Name Mapping (for backward compatibility)\n// ============================================================================\n\n/**\n * Map old event type names to new RPC method names\n */\nexport const eventTypeToRpcMethod: Record<string, RpcMethod> = {\n // Container\n container_create_request: \"container.create\",\n container_get_request: \"container.get\",\n container_list_request: \"container.list\",\n // Image\n image_create_request: \"image.create\",\n image_get_request: \"image.get\",\n image_list_request: \"image.list\",\n image_delete_request: \"image.delete\",\n image_run_request: \"image.run\",\n image_stop_request: \"image.stop\",\n image_update_request: \"image.update\",\n image_messages_request: \"image.messages\",\n // Agent\n agent_get_request: \"agent.get\",\n agent_list_request: \"agent.list\",\n agent_destroy_request: \"agent.destroy\",\n agent_destroy_all_request: \"agent.destroyAll\",\n agent_interrupt_request: \"agent.interrupt\",\n // Message\n message_send_request: \"message.send\",\n};\n\n/**\n * Map RPC method names back to response event types\n */\nexport const rpcMethodToResponseType: Record<RpcMethod, string> = {\n // Container\n \"container.create\": \"container_create_response\",\n \"container.get\": \"container_get_response\",\n \"container.list\": \"container_list_response\",\n // Image\n \"image.create\": \"image_create_response\",\n \"image.get\": \"image_get_response\",\n \"image.list\": \"image_list_response\",\n \"image.delete\": \"image_delete_response\",\n \"image.run\": \"image_run_response\",\n \"image.stop\": \"image_stop_response\",\n \"image.update\": \"image_update_response\",\n \"image.messages\": \"image_messages_response\",\n // Agent\n \"agent.get\": \"agent_get_response\",\n \"agent.list\": \"agent_list_response\",\n \"agent.destroy\": \"agent_destroy_response\",\n \"agent.destroyAll\": \"agent_destroy_all_response\",\n \"agent.interrupt\": \"agent_interrupt_response\",\n // Message\n \"message.send\": \"message_send_response\",\n};\n","/**\n * Reliable Message Protocol\n *\n * Internal protocol for message acknowledgment between server and client.\n * This is transparent to the application layer.\n *\n * Flow:\n * 1. Server sends: { __msgId: \"xxx\", __payload: \"actual message\" }\n * 2. Client receives, extracts payload, sends: { __ack: \"xxx\" }\n * 3. Server receives ACK, triggers onAck callback\n */\n\n// ============================================================================\n// Protocol Types\n// ============================================================================\n\n/**\n * ReliableWrapper - Wrapper for reliable messages (server → client)\n *\n * Contains the original message payload with a unique ID for tracking.\n */\nexport interface ReliableWrapper {\n /** Unique message ID for tracking */\n __msgId: string;\n /** Original message payload */\n __payload: string;\n}\n\n/**\n * AckMessage - Acknowledgment message (client → server)\n *\n * Sent automatically by client when receiving a reliable message.\n */\nexport interface AckMessage {\n /** Message ID being acknowledged */\n __ack: string;\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Check if data is a ReliableWrapper\n */\nexport function isReliableWrapper(data: unknown): data is ReliableWrapper {\n return typeof data === \"object\" && data !== null && \"__msgId\" in data && \"__payload\" in data;\n}\n\n/**\n * Check if data is an AckMessage\n */\nexport function isAckMessage(data: unknown): data is AckMessage {\n return typeof data === \"object\" && data !== null && \"__ack\" in data;\n}\n\n// ============================================================================\n// Protocol Helpers\n// ============================================================================\n\n/**\n * Wrap a message for reliable delivery\n */\nexport function wrapMessage(msgId: string, payload: string): ReliableWrapper {\n return { __msgId: msgId, __payload: payload };\n}\n\n/**\n * Create an ACK message\n */\nexport function createAck(msgId: string): AckMessage {\n return { __ack: msgId };\n}\n\n/**\n * Unwrap a reliable message, returning the original payload\n */\nexport function unwrapMessage(wrapper: ReliableWrapper): string {\n return wrapper.__payload;\n}\n\n/**\n * Generate a unique message ID\n */\nexport function generateMessageId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n","/**\n * RpcClient - JSON-RPC 2.0 Client over WebSocket\n *\n * Provides:\n * - Request/Response with automatic ID matching\n * - Notification handling (stream events)\n * - Timeout management\n * - Reconnection support\n *\n * @example\n * ```typescript\n * const client = new RpcClient({ url: \"ws://localhost:5200\" });\n * await client.connect();\n *\n * // RPC call\n * const result = await client.call(\"container.list\", {});\n *\n * // Stream events\n * client.onNotification(\"stream.event\", (params) => {\n * console.log(\"Event:\", params.event);\n * });\n *\n * // Subscribe to topic\n * client.notify(\"subscribe\", { topic: \"session-123\" });\n * ```\n */\n\nimport type { SystemEvent } from \"../event/types/base\";\nimport {\n createNotification,\n createRequest,\n isErrorResponse,\n isNotification,\n isStreamEvent,\n isSuccessResponse,\n type NotificationMethod,\n parseMessage,\n type RpcMethod,\n type StreamEventParams,\n} from \"./jsonrpc\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Factory function for creating WebSocket instances.\n * Platform layer provides the implementation:\n * - Browser: native WebSocket (default)\n * - Node.js: ws library (via @agentxjs/node-platform)\n */\nexport type WebSocketFactory = (url: string) => WebSocket;\n\n/**\n * RpcClient configuration\n */\nexport interface RpcClientConfig {\n /**\n * WebSocket URL\n */\n url: string;\n\n /**\n * Factory for creating WebSocket instances.\n * If not provided, falls back to the global WebSocket constructor.\n */\n createWebSocket?: WebSocketFactory;\n\n /**\n * Request timeout in milliseconds (default: 30000)\n */\n timeout?: number;\n\n /**\n * Auto reconnect on disconnect (default: true)\n */\n autoReconnect?: boolean;\n\n /**\n * Reconnect delay in milliseconds (default: 3000)\n */\n reconnectDelay?: number;\n\n /**\n * Headers for authentication (sent in first message after connection)\n */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n\n /**\n * Debug logging\n */\n debug?: boolean;\n}\n\n/**\n * Pending request state\n */\ninterface PendingRequest {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\n/**\n * Notification handler\n */\ntype NotificationHandler = (method: string, params: unknown) => void;\n\n/**\n * Stream event handler\n */\ntype StreamEventHandler = (topic: string, event: SystemEvent) => void;\n\n/**\n * Connection state\n */\nexport type RpcClientState = \"disconnected\" | \"connecting\" | \"connected\";\n\n// ============================================================================\n// RpcClient Implementation\n// ============================================================================\n\n/**\n * JSON-RPC 2.0 Client\n */\nexport class RpcClient {\n private readonly config: RpcClientConfig;\n private readonly timeout: number;\n private readonly pendingRequests = new Map<string | number, PendingRequest>();\n private readonly notificationHandlers = new Set<NotificationHandler>();\n private readonly streamEventHandlers = new Set<StreamEventHandler>();\n\n private ws: WebSocket | null = null;\n private state: RpcClientState = \"disconnected\";\n private requestId = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private disposed = false;\n\n constructor(config: RpcClientConfig) {\n this.config = config;\n this.timeout = config.timeout ?? 30000;\n }\n\n // ==================== Properties ====================\n\n /**\n * Current connection state\n */\n get connectionState(): RpcClientState {\n return this.state;\n }\n\n /**\n * Whether client is connected\n */\n get connected(): boolean {\n return this.state === \"connected\";\n }\n\n // ==================== Connection ====================\n\n /**\n * Connect to server\n */\n async connect(): Promise<void> {\n if (this.disposed) {\n throw new Error(\"Client has been disposed\");\n }\n\n if (this.state === \"connected\") {\n return;\n }\n\n this.state = \"connecting\";\n\n const url = this.config.url;\n\n // Create WebSocket via injected factory or global WebSocket\n const factory = this.config.createWebSocket ?? ((u: string) => new WebSocket(u));\n const ws = factory(url);\n\n this.ws = ws;\n\n return new Promise((resolve, reject) => {\n ws.onopen = async () => {\n this.state = \"connected\";\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Connected to\", url);\n }\n\n // Send auth headers after connection (for environments where\n // WebSocket constructor doesn't support headers, e.g. browser)\n if (this.config.headers) {\n const headers =\n typeof this.config.headers === \"function\"\n ? await this.config.headers()\n : this.config.headers;\n this.notify(\"auth\" as NotificationMethod, { headers });\n }\n\n resolve();\n };\n\n ws.onclose = () => {\n this.state = \"disconnected\";\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Disconnected\");\n }\n\n // Auto reconnect\n if (!this.disposed && this.config.autoReconnect !== false) {\n this.scheduleReconnect();\n }\n };\n\n ws.onerror = (err) => {\n if (this.config.debug) {\n console.error(\"[RpcClient] WebSocket error:\", err);\n }\n\n if (this.state === \"connecting\") {\n this.state = \"disconnected\";\n reject(new Error(\"Failed to connect to server\"));\n }\n };\n\n ws.onmessage = (event) => {\n this.handleMessage(event.data as string);\n };\n });\n }\n\n /**\n * Disconnect from server\n */\n disconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.state = \"disconnected\";\n }\n\n /**\n * Dispose client and clean up resources\n */\n dispose(): void {\n this.disposed = true;\n\n // Reject all pending requests\n for (const [id, pending] of this.pendingRequests) {\n clearTimeout(pending.timer);\n pending.reject(new Error(\"Client disposed\"));\n this.pendingRequests.delete(id);\n }\n\n this.disconnect();\n this.notificationHandlers.clear();\n this.streamEventHandlers.clear();\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Disposed\");\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return;\n\n const delay = this.config.reconnectDelay ?? 3000;\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null;\n\n if (!this.disposed && this.state === \"disconnected\") {\n if (this.config.debug) {\n console.log(\"[RpcClient] Attempting to reconnect...\");\n }\n\n try {\n await this.connect();\n } catch {\n this.scheduleReconnect();\n }\n }\n }, delay);\n }\n\n // ==================== RPC Methods ====================\n\n /**\n * Call an RPC method and wait for response\n */\n async call<T = unknown>(method: RpcMethod, params: unknown): Promise<T> {\n if (!this.connected || !this.ws) {\n throw new Error(\"Not connected to server\");\n }\n\n const id = ++this.requestId;\n const request = createRequest(id, method, params);\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Request timeout: ${method}`));\n }, this.timeout);\n\n this.pendingRequests.set(id, {\n resolve: resolve as (result: unknown) => void,\n reject,\n timer,\n });\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Sending request:\", method, params);\n }\n\n this.ws!.send(JSON.stringify(request));\n });\n }\n\n /**\n * Send a notification (no response expected)\n */\n notify(method: NotificationMethod | string, params: unknown): void {\n if (!this.connected || !this.ws) {\n if (this.config.debug) {\n console.warn(\"[RpcClient] Cannot send notification: not connected\");\n }\n return;\n }\n\n const notification = createNotification(method as NotificationMethod, params);\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Sending notification:\", method, params);\n }\n\n this.ws.send(JSON.stringify(notification));\n }\n\n /**\n * Subscribe to a topic (convenience method)\n */\n subscribe(topic: string): void {\n this.notify(\"subscribe\", { topic });\n }\n\n /**\n * Unsubscribe from a topic (convenience method)\n */\n unsubscribe(topic: string): void {\n this.notify(\"unsubscribe\", { topic });\n }\n\n // ==================== Event Handlers ====================\n\n /**\n * Register handler for all notifications\n */\n onNotification(handler: NotificationHandler): () => void {\n this.notificationHandlers.add(handler);\n return () => this.notificationHandlers.delete(handler);\n }\n\n /**\n * Register handler for stream events\n */\n onStreamEvent(handler: StreamEventHandler): () => void {\n this.streamEventHandlers.add(handler);\n return () => this.streamEventHandlers.delete(handler);\n }\n\n // ==================== Message Handling ====================\n\n private handleMessage(data: string): void {\n try {\n const parsed = parseMessage(data);\n\n // Handle single message\n if (!Array.isArray(parsed)) {\n this.handleParsedMessage(parsed);\n } else {\n // Batch response (rare)\n for (const item of parsed) {\n this.handleParsedMessage(item);\n }\n }\n } catch (err) {\n if (this.config.debug) {\n console.error(\"[RpcClient] Failed to parse message:\", err);\n }\n }\n }\n\n private handleParsedMessage(parsed: import(\"jsonrpc-lite\").IParsedObject): void {\n if (isSuccessResponse(parsed)) {\n // Success response - resolve pending request\n const payload = parsed.payload as { id: string | number; result: unknown };\n const pending = this.pendingRequests.get(payload.id);\n\n if (pending) {\n this.pendingRequests.delete(payload.id);\n clearTimeout(pending.timer);\n pending.resolve(payload.result);\n }\n } else if (isErrorResponse(parsed)) {\n // Error response - reject pending request\n const payload = parsed.payload as {\n id: string | number | null;\n error: { code: number; message: string; data?: unknown };\n };\n\n if (payload.id !== null) {\n const pending = this.pendingRequests.get(payload.id);\n\n if (pending) {\n this.pendingRequests.delete(payload.id);\n clearTimeout(pending.timer);\n pending.reject(new Error(payload.error.message));\n }\n }\n } else if (isNotification(parsed)) {\n // Notification - stream event or control message\n const payload = parsed.payload as { method: string; params: unknown };\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Received notification:\", payload.method);\n }\n\n // Notify all handlers\n for (const handler of this.notificationHandlers) {\n handler(payload.method, payload.params);\n }\n\n // Handle stream events specially\n if (isStreamEvent(parsed)) {\n const streamPayload = parsed.payload as { params: StreamEventParams };\n const { topic, event } = streamPayload.params;\n\n for (const handler of this.streamEventHandlers) {\n handler(topic, event);\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/network/jsonrpc.ts","../../src/network/protocol.ts","../../src/network/RpcClient.ts"],"sourcesContent":["/**\n * JSON-RPC 2.0 Protocol for AgentX Network Communication\n *\n * Uses jsonrpc-lite for message parsing/serialization.\n *\n * Message Types:\n * - Request: Client → Server (has id, expects response)\n * - Response: Server → Client (success or error)\n * - Notification: Server → Client (no id, stream events)\n *\n * @see https://www.jsonrpc.org/specification\n */\n\nimport type { IParsedObject, JsonRpc } from \"jsonrpc-lite\";\nimport {\n JsonRpcError,\n error as jsonrpcError,\n notification as jsonrpcNotification,\n parse as jsonrpcParse,\n parseObject as jsonrpcParseObject,\n request as jsonrpcRequest,\n success as jsonrpcSuccess,\n} from \"jsonrpc-lite\";\nimport type { SystemEvent } from \"../event/types/base\";\n\n// ============================================================================\n// Re-export jsonrpc-lite types and functions\n// ============================================================================\n\nexport { JsonRpcError };\nexport type { IParsedObject, JsonRpc };\n\n// ============================================================================\n// RPC Method Names\n// ============================================================================\n\n/**\n * All RPC method names supported by AgentX\n */\nexport type RpcMethod =\n // Container\n | \"container.create\"\n | \"container.get\"\n | \"container.list\"\n // Image\n | \"image.create\"\n | \"image.get\"\n | \"image.list\"\n | \"image.delete\"\n | \"image.run\"\n | \"image.stop\"\n | \"image.update\"\n | \"image.messages\"\n // Agent\n | \"agent.get\"\n | \"agent.list\"\n | \"agent.destroy\"\n | \"agent.destroyAll\"\n | \"agent.interrupt\"\n // Message\n | \"message.send\";\n\n/**\n * Notification method names (server push)\n */\nexport type NotificationMethod =\n | \"stream.event\" // Stream events (text_delta, tool_call, etc.)\n | \"control.ack\"; // ACK for reliable delivery\n\n// ============================================================================\n// Request/Response Type Definitions\n// ============================================================================\n\n/**\n * JSON-RPC Request structure\n */\nexport interface RpcRequest<M extends RpcMethod = RpcMethod, P = unknown> {\n jsonrpc: \"2.0\";\n method: M;\n params: P;\n id: string | number;\n}\n\n/**\n * JSON-RPC Success Response structure\n */\nexport interface RpcSuccessResponse<R = unknown> {\n jsonrpc: \"2.0\";\n result: R;\n id: string | number;\n}\n\n/**\n * JSON-RPC Error Response structure\n */\nexport interface RpcErrorResponse {\n jsonrpc: \"2.0\";\n error: {\n code: number;\n message: string;\n data?: unknown;\n };\n id: string | number | null;\n}\n\n/**\n * JSON-RPC Notification structure (no id, no response expected)\n */\nexport interface RpcNotification<M extends NotificationMethod = NotificationMethod, P = unknown> {\n jsonrpc: \"2.0\";\n method: M;\n params: P;\n}\n\n/**\n * Stream event notification params\n */\nexport interface StreamEventParams {\n topic: string;\n event: SystemEvent;\n}\n\n/**\n * Control ACK notification params\n */\nexport interface ControlAckParams {\n msgId: string;\n}\n\n// ============================================================================\n// Standard JSON-RPC Error Codes\n// ============================================================================\n\nexport const RpcErrorCodes = {\n // Standard JSON-RPC errors\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n // Server errors (reserved: -32000 to -32099)\n SERVER_ERROR: -32000,\n // Application errors (custom)\n NOT_FOUND: 404,\n UNAUTHORIZED: 401,\n FORBIDDEN: 403,\n TIMEOUT: 408,\n} as const;\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create a JSON-RPC request\n */\nexport function createRequest(\n id: string | number,\n method: RpcMethod | string,\n params: unknown\n): JsonRpc {\n return jsonrpcRequest(id, method, params as Record<string, unknown>);\n}\n\n/**\n * Create a JSON-RPC notification (no response expected)\n */\nexport function createNotification(method: NotificationMethod | string, params: unknown): JsonRpc {\n return jsonrpcNotification(method, params as Record<string, unknown>);\n}\n\n/**\n * Create a stream event notification\n */\nexport function createStreamEvent(topic: string, event: SystemEvent): JsonRpc {\n return jsonrpcNotification(\"stream.event\", { topic, event });\n}\n\n/**\n * Create an ACK notification\n */\nexport function createAckNotification(msgId: string): JsonRpc {\n return jsonrpcNotification(\"control.ack\", { msgId });\n}\n\n/**\n * Create a success response\n */\nexport function createSuccessResponse(id: string | number, result: unknown): JsonRpc {\n return jsonrpcSuccess(id, result as Record<string, unknown>);\n}\n\n/**\n * Create an error response\n */\nexport function createErrorResponse(\n id: string | number | null,\n code: number,\n message: string,\n data?: unknown\n): JsonRpc {\n return jsonrpcError(id, new JsonRpcError(message, code, data));\n}\n\n/**\n * Parse a JSON-RPC message string\n */\nexport function parseMessage(message: string): IParsedObject | IParsedObject[] {\n return jsonrpcParse(message);\n}\n\n/**\n * Parse a JSON-RPC message object\n */\nexport function parseMessageObject(obj: unknown): IParsedObject {\n return jsonrpcParseObject(obj);\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Check if parsed message is a request\n */\nexport function isRequest(parsed: IParsedObject): boolean {\n return parsed.type === \"request\";\n}\n\n/**\n * Check if parsed message is a notification\n */\nexport function isNotification(parsed: IParsedObject): boolean {\n return parsed.type === \"notification\";\n}\n\n/**\n * Check if parsed message is a success response\n */\nexport function isSuccessResponse(parsed: IParsedObject): boolean {\n return parsed.type === \"success\";\n}\n\n/**\n * Check if parsed message is an error response\n */\nexport function isErrorResponse(parsed: IParsedObject): boolean {\n return parsed.type === \"error\";\n}\n\n/**\n * Check if parsed message is invalid\n */\nexport function isInvalid(parsed: IParsedObject): boolean {\n return parsed.type === \"invalid\";\n}\n\n/**\n * Check if notification is a stream event\n */\nexport function isStreamEvent(parsed: IParsedObject): parsed is IParsedObject & {\n payload: RpcNotification<\"stream.event\", StreamEventParams>;\n} {\n if (parsed.type !== \"notification\") return false;\n const payload = parsed.payload as RpcNotification;\n return payload.method === \"stream.event\";\n}\n\n/**\n * Check if notification is a control ACK\n */\nexport function isControlAck(parsed: IParsedObject): parsed is IParsedObject & {\n payload: RpcNotification<\"control.ack\", ControlAckParams>;\n} {\n if (parsed.type !== \"notification\") return false;\n const payload = parsed.payload as RpcNotification;\n return payload.method === \"control.ack\";\n}\n\n// ============================================================================\n// Method Name Mapping (for backward compatibility)\n// ============================================================================\n\n/**\n * Map old event type names to new RPC method names\n */\nexport const eventTypeToRpcMethod: Record<string, RpcMethod> = {\n // Container\n container_create_request: \"container.create\",\n container_get_request: \"container.get\",\n container_list_request: \"container.list\",\n // Image\n image_create_request: \"image.create\",\n image_get_request: \"image.get\",\n image_list_request: \"image.list\",\n image_delete_request: \"image.delete\",\n image_run_request: \"image.run\",\n image_stop_request: \"image.stop\",\n image_update_request: \"image.update\",\n image_messages_request: \"image.messages\",\n // Agent\n agent_get_request: \"agent.get\",\n agent_list_request: \"agent.list\",\n agent_destroy_request: \"agent.destroy\",\n agent_destroy_all_request: \"agent.destroyAll\",\n agent_interrupt_request: \"agent.interrupt\",\n // Message\n message_send_request: \"message.send\",\n};\n\n/**\n * Map RPC method names back to response event types\n */\nexport const rpcMethodToResponseType: Record<RpcMethod, string> = {\n // Container\n \"container.create\": \"container_create_response\",\n \"container.get\": \"container_get_response\",\n \"container.list\": \"container_list_response\",\n // Image\n \"image.create\": \"image_create_response\",\n \"image.get\": \"image_get_response\",\n \"image.list\": \"image_list_response\",\n \"image.delete\": \"image_delete_response\",\n \"image.run\": \"image_run_response\",\n \"image.stop\": \"image_stop_response\",\n \"image.update\": \"image_update_response\",\n \"image.messages\": \"image_messages_response\",\n // Agent\n \"agent.get\": \"agent_get_response\",\n \"agent.list\": \"agent_list_response\",\n \"agent.destroy\": \"agent_destroy_response\",\n \"agent.destroyAll\": \"agent_destroy_all_response\",\n \"agent.interrupt\": \"agent_interrupt_response\",\n // Message\n \"message.send\": \"message_send_response\",\n};\n","/**\n * Reliable Message Protocol\n *\n * Internal protocol for message acknowledgment between server and client.\n * This is transparent to the application layer.\n *\n * Flow:\n * 1. Server sends: { __msgId: \"xxx\", __payload: \"actual message\" }\n * 2. Client receives, extracts payload, sends: { __ack: \"xxx\" }\n * 3. Server receives ACK, triggers onAck callback\n */\n\n// ============================================================================\n// Protocol Types\n// ============================================================================\n\n/**\n * ReliableWrapper - Wrapper for reliable messages (server → client)\n *\n * Contains the original message payload with a unique ID for tracking.\n */\nexport interface ReliableWrapper {\n /** Unique message ID for tracking */\n __msgId: string;\n /** Original message payload */\n __payload: string;\n}\n\n/**\n * AckMessage - Acknowledgment message (client → server)\n *\n * Sent automatically by client when receiving a reliable message.\n */\nexport interface AckMessage {\n /** Message ID being acknowledged */\n __ack: string;\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Check if data is a ReliableWrapper\n */\nexport function isReliableWrapper(data: unknown): data is ReliableWrapper {\n return typeof data === \"object\" && data !== null && \"__msgId\" in data && \"__payload\" in data;\n}\n\n/**\n * Check if data is an AckMessage\n */\nexport function isAckMessage(data: unknown): data is AckMessage {\n return typeof data === \"object\" && data !== null && \"__ack\" in data;\n}\n\n// ============================================================================\n// Protocol Helpers\n// ============================================================================\n\n/**\n * Wrap a message for reliable delivery\n */\nexport function wrapMessage(msgId: string, payload: string): ReliableWrapper {\n return { __msgId: msgId, __payload: payload };\n}\n\n/**\n * Create an ACK message\n */\nexport function createAck(msgId: string): AckMessage {\n return { __ack: msgId };\n}\n\n/**\n * Unwrap a reliable message, returning the original payload\n */\nexport function unwrapMessage(wrapper: ReliableWrapper): string {\n return wrapper.__payload;\n}\n\n/**\n * Generate a unique message ID\n */\nexport function generateMessageId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n","/**\n * RpcClient - JSON-RPC 2.0 Client over WebSocket\n *\n * Provides:\n * - Request/Response with automatic ID matching\n * - Notification handling (stream events)\n * - Timeout management\n * - Reconnection support\n *\n * @example\n * ```typescript\n * const client = new RpcClient({ url: \"ws://localhost:5200\" });\n * await client.connect();\n *\n * // RPC call\n * const result = await client.call(\"container.list\", {});\n *\n * // Stream events\n * client.onNotification(\"stream.event\", (params) => {\n * console.log(\"Event:\", params.event);\n * });\n *\n * // Subscribe to topic\n * client.notify(\"subscribe\", { topic: \"session-123\" });\n * ```\n */\n\nimport type { SystemEvent } from \"../event/types/base\";\nimport {\n createNotification,\n createRequest,\n isErrorResponse,\n isNotification,\n isStreamEvent,\n isSuccessResponse,\n type NotificationMethod,\n parseMessage,\n type RpcMethod,\n type StreamEventParams,\n} from \"./jsonrpc\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Factory for creating client-side WebSocket connections.\n * Injected via Platform:\n * - Browser: native WebSocket (default fallback)\n * - Node.js: ws library (via @agentxjs/node-platform)\n */\nexport type ChannelClientFactory = (url: string) => WebSocket;\n\n/**\n * RpcClient configuration\n */\nexport interface RpcClientConfig {\n /**\n * WebSocket URL\n */\n url: string;\n\n /**\n * Factory for creating WebSocket instances.\n * If not provided, falls back to the global WebSocket constructor.\n */\n createWebSocket?: ChannelClientFactory;\n\n /**\n * Request timeout in milliseconds (default: 30000)\n */\n timeout?: number;\n\n /**\n * Auto reconnect on disconnect (default: true)\n */\n autoReconnect?: boolean;\n\n /**\n * Reconnect delay in milliseconds (default: 3000)\n */\n reconnectDelay?: number;\n\n /**\n * Headers for authentication (sent in first message after connection)\n */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n\n /**\n * Debug logging\n */\n debug?: boolean;\n}\n\n/**\n * Pending request state\n */\ninterface PendingRequest {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\n/**\n * Notification handler\n */\ntype NotificationHandler = (method: string, params: unknown) => void;\n\n/**\n * Stream event handler\n */\ntype StreamEventHandler = (topic: string, event: SystemEvent) => void;\n\n/**\n * Connection state\n */\nexport type RpcClientState = \"disconnected\" | \"connecting\" | \"connected\";\n\n// ============================================================================\n// RpcClient Implementation\n// ============================================================================\n\n/**\n * JSON-RPC 2.0 Client\n */\nexport class RpcClient {\n private readonly config: RpcClientConfig;\n private readonly timeout: number;\n private readonly pendingRequests = new Map<string | number, PendingRequest>();\n private readonly notificationHandlers = new Set<NotificationHandler>();\n private readonly streamEventHandlers = new Set<StreamEventHandler>();\n\n private ws: WebSocket | null = null;\n private state: RpcClientState = \"disconnected\";\n private requestId = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private disposed = false;\n\n constructor(config: RpcClientConfig) {\n this.config = config;\n this.timeout = config.timeout ?? 30000;\n }\n\n // ==================== Properties ====================\n\n /**\n * Current connection state\n */\n get connectionState(): RpcClientState {\n return this.state;\n }\n\n /**\n * Whether client is connected\n */\n get connected(): boolean {\n return this.state === \"connected\";\n }\n\n // ==================== Connection ====================\n\n /**\n * Connect to server\n */\n async connect(): Promise<void> {\n if (this.disposed) {\n throw new Error(\"Client has been disposed\");\n }\n\n if (this.state === \"connected\") {\n return;\n }\n\n this.state = \"connecting\";\n\n const url = this.config.url;\n\n // Create WebSocket via injected factory or global WebSocket\n const factory = this.config.createWebSocket ?? ((u: string) => new WebSocket(u));\n const ws = factory(url);\n\n this.ws = ws;\n\n return new Promise((resolve, reject) => {\n ws.onopen = async () => {\n this.state = \"connected\";\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Connected to\", url);\n }\n\n // Send auth headers after connection (for environments where\n // WebSocket constructor doesn't support headers, e.g. browser)\n if (this.config.headers) {\n const headers =\n typeof this.config.headers === \"function\"\n ? await this.config.headers()\n : this.config.headers;\n this.notify(\"auth\" as NotificationMethod, { headers });\n }\n\n resolve();\n };\n\n ws.onclose = () => {\n this.state = \"disconnected\";\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Disconnected\");\n }\n\n // Auto reconnect\n if (!this.disposed && this.config.autoReconnect !== false) {\n this.scheduleReconnect();\n }\n };\n\n ws.onerror = (err) => {\n if (this.config.debug) {\n console.error(\"[RpcClient] WebSocket error:\", err);\n }\n\n if (this.state === \"connecting\") {\n this.state = \"disconnected\";\n reject(new Error(\"Failed to connect to server\"));\n }\n };\n\n ws.onmessage = (event) => {\n this.handleMessage(event.data as string);\n };\n });\n }\n\n /**\n * Disconnect from server\n */\n disconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.state = \"disconnected\";\n }\n\n /**\n * Dispose client and clean up resources\n */\n dispose(): void {\n this.disposed = true;\n\n // Reject all pending requests\n for (const [id, pending] of this.pendingRequests) {\n clearTimeout(pending.timer);\n pending.reject(new Error(\"Client disposed\"));\n this.pendingRequests.delete(id);\n }\n\n this.disconnect();\n this.notificationHandlers.clear();\n this.streamEventHandlers.clear();\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Disposed\");\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return;\n\n const delay = this.config.reconnectDelay ?? 3000;\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null;\n\n if (!this.disposed && this.state === \"disconnected\") {\n if (this.config.debug) {\n console.log(\"[RpcClient] Attempting to reconnect...\");\n }\n\n try {\n await this.connect();\n } catch {\n this.scheduleReconnect();\n }\n }\n }, delay);\n }\n\n // ==================== RPC Methods ====================\n\n /**\n * Call an RPC method and wait for response\n */\n async call<T = unknown>(method: RpcMethod, params: unknown): Promise<T> {\n if (!this.connected || !this.ws) {\n throw new Error(\"Not connected to server\");\n }\n\n const id = ++this.requestId;\n const request = createRequest(id, method, params);\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Request timeout: ${method}`));\n }, this.timeout);\n\n this.pendingRequests.set(id, {\n resolve: resolve as (result: unknown) => void,\n reject,\n timer,\n });\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Sending request:\", method, params);\n }\n\n this.ws!.send(JSON.stringify(request));\n });\n }\n\n /**\n * Send a notification (no response expected)\n */\n notify(method: NotificationMethod | string, params: unknown): void {\n if (!this.connected || !this.ws) {\n if (this.config.debug) {\n console.warn(\"[RpcClient] Cannot send notification: not connected\");\n }\n return;\n }\n\n const notification = createNotification(method as NotificationMethod, params);\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Sending notification:\", method, params);\n }\n\n this.ws.send(JSON.stringify(notification));\n }\n\n /**\n * Subscribe to a topic (convenience method)\n */\n subscribe(topic: string): void {\n this.notify(\"subscribe\", { topic });\n }\n\n /**\n * Unsubscribe from a topic (convenience method)\n */\n unsubscribe(topic: string): void {\n this.notify(\"unsubscribe\", { topic });\n }\n\n // ==================== Event Handlers ====================\n\n /**\n * Register handler for all notifications\n */\n onNotification(handler: NotificationHandler): () => void {\n this.notificationHandlers.add(handler);\n return () => this.notificationHandlers.delete(handler);\n }\n\n /**\n * Register handler for stream events\n */\n onStreamEvent(handler: StreamEventHandler): () => void {\n this.streamEventHandlers.add(handler);\n return () => this.streamEventHandlers.delete(handler);\n }\n\n // ==================== Message Handling ====================\n\n private handleMessage(data: string): void {\n try {\n const parsed = parseMessage(data);\n\n // Handle single message\n if (!Array.isArray(parsed)) {\n this.handleParsedMessage(parsed);\n } else {\n // Batch response (rare)\n for (const item of parsed) {\n this.handleParsedMessage(item);\n }\n }\n } catch (err) {\n if (this.config.debug) {\n console.error(\"[RpcClient] Failed to parse message:\", err);\n }\n }\n }\n\n private handleParsedMessage(parsed: import(\"jsonrpc-lite\").IParsedObject): void {\n if (isSuccessResponse(parsed)) {\n // Success response - resolve pending request\n const payload = parsed.payload as { id: string | number; result: unknown };\n const pending = this.pendingRequests.get(payload.id);\n\n if (pending) {\n this.pendingRequests.delete(payload.id);\n clearTimeout(pending.timer);\n pending.resolve(payload.result);\n }\n } else if (isErrorResponse(parsed)) {\n // Error response - reject pending request\n const payload = parsed.payload as {\n id: string | number | null;\n error: { code: number; message: string; data?: unknown };\n };\n\n if (payload.id !== null) {\n const pending = this.pendingRequests.get(payload.id);\n\n if (pending) {\n this.pendingRequests.delete(payload.id);\n clearTimeout(pending.timer);\n pending.reject(new Error(payload.error.message));\n }\n }\n } else if (isNotification(parsed)) {\n // Notification - stream event or control message\n const payload = parsed.payload as { method: string; params: unknown };\n\n if (this.config.debug) {\n console.log(\"[RpcClient] Received notification:\", payload.method);\n }\n\n // Notify all handlers\n for (const handler of this.notificationHandlers) {\n handler(payload.method, payload.params);\n }\n\n // Handle stream events specially\n if (isStreamEvent(parsed)) {\n const streamPayload = parsed.payload as { params: StreamEventParams };\n const { topic, event } = streamPayload.params;\n\n for (const handler of this.streamEventHandlers) {\n handler(topic, event);\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/platform/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { B as BashProvider } from '../types-Cb8tKM6Y.js';
|
|
2
2
|
import { d as ContainerRepository, I as ImageRepository, c as SessionRepository } from '../index--gxNpY5W.js';
|
|
3
3
|
import { E as EventBus } from '../bus-C9FLWIu8.js';
|
|
4
|
-
import {
|
|
4
|
+
import { F as ChannelServer, w as ChannelClientFactory } from '../types-CTV8Z9PI.js';
|
|
5
5
|
import '../message-Dn-I2vr0.js';
|
|
6
6
|
import '../base-m40r3Qgu.js';
|
|
7
7
|
import 'jsonrpc-lite';
|
|
@@ -65,12 +65,20 @@ interface AgentXPlatform {
|
|
|
65
65
|
*/
|
|
66
66
|
readonly bashProvider?: BashProvider;
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
68
|
+
* Channel server for accepting client connections (server-side)
|
|
69
|
+
*
|
|
70
|
+
* Optional — only needed for server scenarios.
|
|
71
|
+
* Node.js platform provides ws-based implementation.
|
|
72
|
+
* Cloudflare platform provides DO Hibernation API implementation.
|
|
73
|
+
*/
|
|
74
|
+
readonly channelServer?: ChannelServer;
|
|
75
|
+
/**
|
|
76
|
+
* Channel client factory for creating connections (client-side)
|
|
69
77
|
*
|
|
70
78
|
* Optional — browser uses native WebSocket by default.
|
|
71
79
|
* Node.js platform provides ws-based implementation.
|
|
72
80
|
*/
|
|
73
|
-
readonly
|
|
81
|
+
readonly channelClient?: ChannelClientFactory;
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
export type { AgentXPlatform };
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { B as BusEvent } from '../base-m40r3Qgu.js';
|
|
|
4
4
|
import { AgentXPlatform } from '../platform/index.js';
|
|
5
5
|
import '../types-Cb8tKM6Y.js';
|
|
6
6
|
import '../bus-C9FLWIu8.js';
|
|
7
|
-
import '../
|
|
7
|
+
import '../types-CTV8Z9PI.js';
|
|
8
8
|
import 'jsonrpc-lite';
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -185,12 +185,12 @@ declare const rpcMethodToResponseType: Record<RpcMethod, string>;
|
|
|
185
185
|
*/
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
|
-
* Factory
|
|
189
|
-
*
|
|
190
|
-
* - Browser: native WebSocket (default)
|
|
188
|
+
* Factory for creating client-side WebSocket connections.
|
|
189
|
+
* Injected via Platform:
|
|
190
|
+
* - Browser: native WebSocket (default fallback)
|
|
191
191
|
* - Node.js: ws library (via @agentxjs/node-platform)
|
|
192
192
|
*/
|
|
193
|
-
type
|
|
193
|
+
type ChannelClientFactory = (url: string) => WebSocket;
|
|
194
194
|
/**
|
|
195
195
|
* RpcClient configuration
|
|
196
196
|
*/
|
|
@@ -203,7 +203,7 @@ interface RpcClientConfig {
|
|
|
203
203
|
* Factory for creating WebSocket instances.
|
|
204
204
|
* If not provided, falls back to the global WebSocket constructor.
|
|
205
205
|
*/
|
|
206
|
-
createWebSocket?:
|
|
206
|
+
createWebSocket?: ChannelClientFactory;
|
|
207
207
|
/**
|
|
208
208
|
* Request timeout in milliseconds (default: 30000)
|
|
209
209
|
*/
|
|
@@ -301,4 +301,222 @@ declare class RpcClient {
|
|
|
301
301
|
private handleParsedMessage;
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Network Types - Channel interfaces for client-server communication
|
|
306
|
+
*
|
|
307
|
+
* Provides transport-agnostic interfaces that can be implemented with:
|
|
308
|
+
* - WebSocket (Node.js, Browser)
|
|
309
|
+
* - Durable Objects WebSocket (Cloudflare Workers)
|
|
310
|
+
* - HTTP/2, gRPC, etc.
|
|
311
|
+
*/
|
|
312
|
+
/**
|
|
313
|
+
* Unsubscribe function type
|
|
314
|
+
*/
|
|
315
|
+
type Unsubscribe = () => void;
|
|
316
|
+
/**
|
|
317
|
+
* Minimal HTTP server interface for attaching WebSocket
|
|
318
|
+
* Avoids Node.js dependency in types package
|
|
319
|
+
*/
|
|
320
|
+
interface MinimalHTTPServer {
|
|
321
|
+
on(event: "upgrade", listener: (request: unknown, socket: unknown, head: unknown) => void): void;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Options for reliable message sending
|
|
325
|
+
*/
|
|
326
|
+
interface SendReliableOptions {
|
|
327
|
+
/**
|
|
328
|
+
* Callback when client acknowledges receipt
|
|
329
|
+
*/
|
|
330
|
+
onAck?: () => void;
|
|
331
|
+
/**
|
|
332
|
+
* Timeout in milliseconds (default: 5000)
|
|
333
|
+
*/
|
|
334
|
+
timeout?: number;
|
|
335
|
+
/**
|
|
336
|
+
* Callback when ACK times out
|
|
337
|
+
*/
|
|
338
|
+
onTimeout?: () => void;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* ChannelConnection - Server-side representation of a client connection
|
|
342
|
+
*/
|
|
343
|
+
interface ChannelConnection {
|
|
344
|
+
/**
|
|
345
|
+
* Unique connection ID
|
|
346
|
+
*/
|
|
347
|
+
readonly id: string;
|
|
348
|
+
/**
|
|
349
|
+
* Send message to this client (fire-and-forget)
|
|
350
|
+
*/
|
|
351
|
+
send(message: string): void;
|
|
352
|
+
/**
|
|
353
|
+
* Send message with acknowledgment
|
|
354
|
+
*
|
|
355
|
+
* The message is wrapped with a unique ID. Client automatically sends ACK
|
|
356
|
+
* when received. Server triggers onAck callback upon receiving ACK.
|
|
357
|
+
*
|
|
358
|
+
* This is handled transparently by the Network layer.
|
|
359
|
+
*/
|
|
360
|
+
sendReliable(message: string, options?: SendReliableOptions): void;
|
|
361
|
+
/**
|
|
362
|
+
* Register message handler
|
|
363
|
+
*/
|
|
364
|
+
onMessage(handler: (message: string) => void): Unsubscribe;
|
|
365
|
+
/**
|
|
366
|
+
* Register close handler
|
|
367
|
+
*/
|
|
368
|
+
onClose(handler: () => void): Unsubscribe;
|
|
369
|
+
/**
|
|
370
|
+
* Register error handler
|
|
371
|
+
*/
|
|
372
|
+
onError(handler: (error: Error) => void): Unsubscribe;
|
|
373
|
+
/**
|
|
374
|
+
* Close this connection
|
|
375
|
+
*/
|
|
376
|
+
close(): void;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* ChannelServer - Accepts client connections
|
|
380
|
+
*/
|
|
381
|
+
interface ChannelServer {
|
|
382
|
+
/**
|
|
383
|
+
* Start listening on a port (standalone mode)
|
|
384
|
+
*/
|
|
385
|
+
listen(port: number, host?: string): Promise<void>;
|
|
386
|
+
/**
|
|
387
|
+
* Attach to an existing HTTP server
|
|
388
|
+
*/
|
|
389
|
+
attach(server: MinimalHTTPServer, path?: string): void;
|
|
390
|
+
/**
|
|
391
|
+
* Register connection handler
|
|
392
|
+
*/
|
|
393
|
+
onConnection(handler: (connection: ChannelConnection) => void): Unsubscribe;
|
|
394
|
+
/**
|
|
395
|
+
* Broadcast message to all connected clients
|
|
396
|
+
*/
|
|
397
|
+
broadcast(message: string): void;
|
|
398
|
+
/**
|
|
399
|
+
* Close server and all connections
|
|
400
|
+
*/
|
|
401
|
+
close(): Promise<void>;
|
|
402
|
+
/**
|
|
403
|
+
* Dispose resources
|
|
404
|
+
*/
|
|
405
|
+
dispose(): Promise<void>;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* ChannelServerOptions - Server configuration
|
|
409
|
+
*/
|
|
410
|
+
interface ChannelServerOptions {
|
|
411
|
+
/**
|
|
412
|
+
* Enable heartbeat/ping-pong (default: true)
|
|
413
|
+
*/
|
|
414
|
+
heartbeat?: boolean;
|
|
415
|
+
/**
|
|
416
|
+
* Heartbeat interval in ms (default: 30000)
|
|
417
|
+
*/
|
|
418
|
+
heartbeatInterval?: number;
|
|
419
|
+
/**
|
|
420
|
+
* Enable debug logging (default: false)
|
|
421
|
+
*/
|
|
422
|
+
debug?: boolean;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Connection state
|
|
426
|
+
*/
|
|
427
|
+
type ConnectionState = "connecting" | "open" | "closing" | "closed";
|
|
428
|
+
/**
|
|
429
|
+
* ChannelClient - Connects to server
|
|
430
|
+
*/
|
|
431
|
+
interface ChannelClient {
|
|
432
|
+
/**
|
|
433
|
+
* Connection state
|
|
434
|
+
*/
|
|
435
|
+
readonly readyState: ConnectionState;
|
|
436
|
+
/**
|
|
437
|
+
* Connect to server
|
|
438
|
+
*/
|
|
439
|
+
connect(): Promise<void>;
|
|
440
|
+
/**
|
|
441
|
+
* Send message to server
|
|
442
|
+
*/
|
|
443
|
+
send(message: string): void;
|
|
444
|
+
/**
|
|
445
|
+
* Register message handler
|
|
446
|
+
*/
|
|
447
|
+
onMessage(handler: (message: string) => void): Unsubscribe;
|
|
448
|
+
/**
|
|
449
|
+
* Register open handler
|
|
450
|
+
*/
|
|
451
|
+
onOpen(handler: () => void): Unsubscribe;
|
|
452
|
+
/**
|
|
453
|
+
* Register close handler
|
|
454
|
+
*/
|
|
455
|
+
onClose(handler: () => void): Unsubscribe;
|
|
456
|
+
/**
|
|
457
|
+
* Register error handler
|
|
458
|
+
*/
|
|
459
|
+
onError(handler: (error: Error) => void): Unsubscribe;
|
|
460
|
+
/**
|
|
461
|
+
* Close connection
|
|
462
|
+
*/
|
|
463
|
+
close(): void;
|
|
464
|
+
/**
|
|
465
|
+
* Dispose resources
|
|
466
|
+
*/
|
|
467
|
+
dispose(): void;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* ChannelClientOptions - Client configuration
|
|
471
|
+
*/
|
|
472
|
+
interface ChannelClientOptions {
|
|
473
|
+
/**
|
|
474
|
+
* Server URL
|
|
475
|
+
*/
|
|
476
|
+
serverUrl: string;
|
|
477
|
+
/**
|
|
478
|
+
* Enable auto-reconnect (default: true in browser, false in Node.js)
|
|
479
|
+
*/
|
|
480
|
+
autoReconnect?: boolean;
|
|
481
|
+
/**
|
|
482
|
+
* Min reconnection delay in ms (default: 1000)
|
|
483
|
+
*/
|
|
484
|
+
minReconnectionDelay?: number;
|
|
485
|
+
/**
|
|
486
|
+
* Max reconnection delay in ms (default: 10000)
|
|
487
|
+
*/
|
|
488
|
+
maxReconnectionDelay?: number;
|
|
489
|
+
/**
|
|
490
|
+
* Max retry attempts (default: Infinity)
|
|
491
|
+
*/
|
|
492
|
+
maxRetries?: number;
|
|
493
|
+
/**
|
|
494
|
+
* Connection timeout in ms (default: 4000)
|
|
495
|
+
*/
|
|
496
|
+
connectionTimeout?: number;
|
|
497
|
+
/**
|
|
498
|
+
* Enable debug logging (default: false)
|
|
499
|
+
*/
|
|
500
|
+
debug?: boolean;
|
|
501
|
+
/**
|
|
502
|
+
* Custom headers for WebSocket connection
|
|
503
|
+
*
|
|
504
|
+
* - Node.js: Headers are sent during WebSocket handshake
|
|
505
|
+
* - Browser: Headers are sent in first authentication message
|
|
506
|
+
*/
|
|
507
|
+
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* ChannelServerProvider - Factory for creating ChannelServer instances
|
|
511
|
+
*/
|
|
512
|
+
interface ChannelServerProvider {
|
|
513
|
+
createServer(options?: ChannelServerOptions): ChannelServer;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* ChannelClientProvider - Factory for creating ChannelClient instances
|
|
517
|
+
*/
|
|
518
|
+
interface ChannelClientProvider {
|
|
519
|
+
createClient(options: ChannelClientOptions): ChannelClient;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export { type ChannelClient as A, type ChannelClientOptions as B, type ControlAckParams as C, type ChannelClientProvider as D, type ChannelConnection as E, type ChannelServer as F, type ChannelServerOptions as G, type ChannelServerProvider as H, type ConnectionState as I, type SendReliableOptions as J, type MinimalHTTPServer as M, type NotificationMethod as N, type RpcErrorResponse as R, type StreamEventParams as S, type Unsubscribe as U, type RpcMethod as a, type RpcNotification as b, type RpcRequest as c, type RpcSuccessResponse as d, createAckNotification as e, createErrorResponse as f, createNotification as g, createRequest as h, createStreamEvent as i, createSuccessResponse as j, eventTypeToRpcMethod as k, isControlAck as l, isErrorResponse as m, isInvalid as n, isNotification as o, isRequest as p, isStreamEvent as q, isSuccessResponse as r, parseMessage as s, parseMessageObject as t, RpcErrorCodes as u, rpcMethodToResponseType as v, type ChannelClientFactory as w, type RpcClientConfig as x, type RpcClientState as y, RpcClient as z };
|
package/package.json
CHANGED
package/src/network/RpcClient.ts
CHANGED
|
@@ -44,12 +44,12 @@ import {
|
|
|
44
44
|
// ============================================================================
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* Factory
|
|
48
|
-
*
|
|
49
|
-
* - Browser: native WebSocket (default)
|
|
47
|
+
* Factory for creating client-side WebSocket connections.
|
|
48
|
+
* Injected via Platform:
|
|
49
|
+
* - Browser: native WebSocket (default fallback)
|
|
50
50
|
* - Node.js: ws library (via @agentxjs/node-platform)
|
|
51
51
|
*/
|
|
52
|
-
export type
|
|
52
|
+
export type ChannelClientFactory = (url: string) => WebSocket;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* RpcClient configuration
|
|
@@ -64,7 +64,7 @@ export interface RpcClientConfig {
|
|
|
64
64
|
* Factory for creating WebSocket instances.
|
|
65
65
|
* If not provided, falls back to the global WebSocket constructor.
|
|
66
66
|
*/
|
|
67
|
-
createWebSocket?:
|
|
67
|
+
createWebSocket?: ChannelClientFactory;
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Request timeout in milliseconds (default: 30000)
|
package/src/network/index.ts
CHANGED
|
@@ -55,7 +55,7 @@ export {
|
|
|
55
55
|
wrapMessage,
|
|
56
56
|
} from "./protocol";
|
|
57
57
|
// RPC Client
|
|
58
|
-
export type { RpcClientConfig, RpcClientState
|
|
58
|
+
export type { ChannelClientFactory, RpcClientConfig, RpcClientState } from "./RpcClient";
|
|
59
59
|
export { RpcClient } from "./RpcClient";
|
|
60
60
|
// Types
|
|
61
61
|
export type {
|
package/src/platform/types.ts
CHANGED
|
@@ -23,7 +23,8 @@ import type { BashProvider } from "../bash/types";
|
|
|
23
23
|
import type { ContainerRepository } from "../container/types";
|
|
24
24
|
import type { EventBus } from "../event/types";
|
|
25
25
|
import type { ImageRepository } from "../image/types";
|
|
26
|
-
import type {
|
|
26
|
+
import type { ChannelClientFactory } from "../network/RpcClient";
|
|
27
|
+
import type { ChannelServer } from "../network/types";
|
|
27
28
|
import type { SessionRepository } from "../session/types";
|
|
28
29
|
|
|
29
30
|
// ============================================================================
|
|
@@ -75,10 +76,19 @@ export interface AgentXPlatform {
|
|
|
75
76
|
readonly bashProvider?: BashProvider;
|
|
76
77
|
|
|
77
78
|
/**
|
|
78
|
-
*
|
|
79
|
+
* Channel server for accepting client connections (server-side)
|
|
80
|
+
*
|
|
81
|
+
* Optional — only needed for server scenarios.
|
|
82
|
+
* Node.js platform provides ws-based implementation.
|
|
83
|
+
* Cloudflare platform provides DO Hibernation API implementation.
|
|
84
|
+
*/
|
|
85
|
+
readonly channelServer?: ChannelServer;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Channel client factory for creating connections (client-side)
|
|
79
89
|
*
|
|
80
90
|
* Optional — browser uses native WebSocket by default.
|
|
81
91
|
* Node.js platform provides ws-based implementation.
|
|
82
92
|
*/
|
|
83
|
-
readonly
|
|
93
|
+
readonly channelClient?: ChannelClientFactory;
|
|
84
94
|
}
|