agentxjs 0.0.0-dev-20260312143810

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,132 @@
1
+ /**
2
+ * RemoteClient - AgentX client for remote server
3
+ *
4
+ * Uses RpcClient from @agentxjs/core/network for JSON-RPC communication.
5
+ * This class focuses on business logic, not protocol details.
6
+ */
7
+
8
+ import type { AgentXError } from "@agentxjs/core/error";
9
+ import type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from "@agentxjs/core/event";
10
+ import { EventBusImpl } from "@agentxjs/core/event";
11
+ import { RpcClient, type RpcMethod } from "@agentxjs/core/network";
12
+ import { createLogger } from "commonxjs/logger";
13
+ import { createRemoteAgents } from "./namespaces/agents";
14
+ import { createRemoteContainers } from "./namespaces/containers";
15
+ import { createRemoteImages } from "./namespaces/images";
16
+ import { createRemoteLLM } from "./namespaces/llm";
17
+ import { createPresentations } from "./namespaces/presentations";
18
+ import { createRemoteSessions } from "./namespaces/sessions";
19
+ import type {
20
+ AgentNamespace,
21
+ AgentX,
22
+ ContainerNamespace,
23
+ ImageNamespace,
24
+ LLMNamespace,
25
+ PresentationNamespace,
26
+ RemoteClientConfig,
27
+ SessionNamespace,
28
+ } from "./types";
29
+
30
+ const logger = createLogger("agentx/RemoteClient");
31
+
32
+ /**
33
+ * RemoteClient implementation using JSON-RPC 2.0
34
+ */
35
+ export class RemoteClient implements AgentX {
36
+ private readonly config: RemoteClientConfig;
37
+ private readonly eventBus: EventBus;
38
+ private readonly rpcClient: RpcClient;
39
+
40
+ readonly container: ContainerNamespace;
41
+ readonly image: ImageNamespace;
42
+ readonly agent: AgentNamespace;
43
+ readonly session: SessionNamespace;
44
+ readonly presentation: PresentationNamespace;
45
+ readonly llm: LLMNamespace;
46
+
47
+ constructor(config: RemoteClientConfig) {
48
+ this.config = config;
49
+ this.eventBus = new EventBusImpl();
50
+
51
+ // Create RPC client (WebSocket factory from platform if available)
52
+ this.rpcClient = new RpcClient({
53
+ url: config.serverUrl,
54
+ createWebSocket: config.customPlatform?.channelClient,
55
+ timeout: config.timeout ?? 30000,
56
+ autoReconnect: config.autoReconnect ?? true,
57
+ headers: config.headers as Record<string, string> | undefined,
58
+ debug: false,
59
+ });
60
+
61
+ // Forward stream events to internal event bus
62
+ this.rpcClient.onStreamEvent((topic, event) => {
63
+ logger.debug("Received stream event", { topic, type: event.type });
64
+ this.eventBus.emit(event as BusEvent);
65
+ });
66
+
67
+ // Assemble namespaces
68
+ this.container = createRemoteContainers(this.rpcClient);
69
+ this.image = createRemoteImages(this.rpcClient, (sessionId) => this.subscribe(sessionId));
70
+ this.agent = createRemoteAgents(this.rpcClient);
71
+ this.session = createRemoteSessions(this.rpcClient);
72
+ this.presentation = createPresentations(this);
73
+ this.llm = createRemoteLLM(this.rpcClient);
74
+ }
75
+
76
+ // ==================== Properties ====================
77
+
78
+ get connected(): boolean {
79
+ return this.rpcClient.connected;
80
+ }
81
+
82
+ get events(): EventBus {
83
+ return this.eventBus;
84
+ }
85
+
86
+ // ==================== Connection ====================
87
+
88
+ async connect(): Promise<void> {
89
+ await this.rpcClient.connect();
90
+ logger.info("Connected to server", { url: this.config.serverUrl });
91
+ }
92
+
93
+ async disconnect(): Promise<void> {
94
+ this.rpcClient.disconnect();
95
+ logger.info("Disconnected from server");
96
+ }
97
+
98
+ async dispose(): Promise<void> {
99
+ this.rpcClient.dispose();
100
+ this.eventBus.destroy();
101
+ logger.info("RemoteClient disposed");
102
+ }
103
+
104
+ // ==================== Event Subscription ====================
105
+
106
+ on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe {
107
+ return this.eventBus.on(type, handler);
108
+ }
109
+
110
+ onAny(handler: BusEventHandler): Unsubscribe {
111
+ return this.eventBus.onAny(handler);
112
+ }
113
+
114
+ subscribe(sessionId: string): void {
115
+ this.rpcClient.subscribe(sessionId);
116
+ logger.debug("Subscribed to session", { sessionId });
117
+ }
118
+
119
+ // ==================== Error Handling ====================
120
+
121
+ onError(handler: (error: AgentXError) => void): Unsubscribe {
122
+ return this.eventBus.on("agentx_error", (event) => {
123
+ handler(event.data as AgentXError);
124
+ });
125
+ }
126
+
127
+ // ==================== RPC ====================
128
+
129
+ async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {
130
+ return this.rpcClient.call<T>(method as RpcMethod, params);
131
+ }
132
+ }
package/src/index.ts ADDED
@@ -0,0 +1,228 @@
1
+ /**
2
+ * agentxjs - AgentX Client SDK
3
+ *
4
+ * Fluent API supporting local, remote, and server modes.
5
+ *
6
+ * @example Local mode
7
+ * ```typescript
8
+ * import { createAgentX } from "agentxjs";
9
+ * import { nodePlatform } from "@agentxjs/node-platform";
10
+ *
11
+ * const ax = createAgentX(nodePlatform({ createDriver }));
12
+ * await ax.agent.create({ imageId: "..." });
13
+ * ```
14
+ *
15
+ * @example Remote mode
16
+ * ```typescript
17
+ * const ax = createAgentX();
18
+ * const client = await ax.connect("ws://localhost:5200");
19
+ * ```
20
+ *
21
+ * @example Server mode
22
+ * ```typescript
23
+ * const ax = createAgentX(nodePlatform({ createDriver }));
24
+ * const server = await ax.serve({ port: 5200 });
25
+ * ```
26
+ */
27
+
28
+ import type { CreateDriver } from "@agentxjs/core/driver";
29
+ import type { AgentXPlatform } from "@agentxjs/core/runtime";
30
+ import { createAgentXRuntime } from "@agentxjs/core/runtime";
31
+ import { LocalClient } from "./LocalClient";
32
+ import { RemoteClient } from "./RemoteClient";
33
+ import type { AgentX, AgentXBuilder, AgentXServer, ConnectOptions, ServeConfig } from "./types";
34
+
35
+ /**
36
+ * Platform configuration for createAgentX
37
+ */
38
+ export interface PlatformConfig {
39
+ platform: AgentXPlatform;
40
+ createDriver: CreateDriver;
41
+ }
42
+
43
+ /**
44
+ * Create an AgentX builder
45
+ *
46
+ * @param config - Platform configuration (optional). Without it, only connect() is available.
47
+ * @returns AgentXBuilder — local AgentX + connect() + serve()
48
+ */
49
+ export function createAgentX(config?: PlatformConfig): AgentXBuilder {
50
+ let localClient: LocalClient | null = null;
51
+
52
+ function getLocalClient(): LocalClient {
53
+ if (localClient) return localClient;
54
+ if (!config) {
55
+ throw new Error(
56
+ "Local mode requires a platform. Pass a PlatformConfig to createAgentX(), or use connect() for remote mode."
57
+ );
58
+ }
59
+ const runtime = createAgentXRuntime(config.platform, config.createDriver);
60
+ localClient = new LocalClient(runtime);
61
+ return localClient;
62
+ }
63
+
64
+ if (config) {
65
+ getLocalClient();
66
+ }
67
+
68
+ return {
69
+ get connected() {
70
+ return localClient?.connected ?? false;
71
+ },
72
+
73
+ get events() {
74
+ return getLocalClient().events;
75
+ },
76
+
77
+ get container() {
78
+ return getLocalClient().container;
79
+ },
80
+
81
+ get image() {
82
+ return getLocalClient().image;
83
+ },
84
+
85
+ get agent() {
86
+ return getLocalClient().agent;
87
+ },
88
+
89
+ get session() {
90
+ return getLocalClient().session;
91
+ },
92
+
93
+ get presentation() {
94
+ return getLocalClient().presentation;
95
+ },
96
+
97
+ get llm() {
98
+ return getLocalClient().llm;
99
+ },
100
+
101
+ on(type, handler) {
102
+ return getLocalClient().on(type, handler);
103
+ },
104
+
105
+ onAny(handler) {
106
+ return getLocalClient().onAny(handler);
107
+ },
108
+
109
+ subscribe(sessionId) {
110
+ getLocalClient().subscribe(sessionId);
111
+ },
112
+
113
+ onError(handler) {
114
+ return getLocalClient().onError(handler);
115
+ },
116
+
117
+ async disconnect() {
118
+ await localClient?.disconnect();
119
+ },
120
+
121
+ async dispose() {
122
+ await localClient?.dispose();
123
+ localClient = null;
124
+ },
125
+
126
+ async connect(serverUrl: string, options?: ConnectOptions): Promise<AgentX> {
127
+ const remoteClient = new RemoteClient({
128
+ serverUrl,
129
+ headers: options?.headers as Record<string, string> | undefined,
130
+ context: options?.context,
131
+ timeout: options?.timeout,
132
+ autoReconnect: options?.autoReconnect,
133
+ customPlatform: config?.platform,
134
+ });
135
+ await remoteClient.connect();
136
+ return remoteClient;
137
+ },
138
+
139
+ async serve(serveConfig?: ServeConfig): Promise<AgentXServer> {
140
+ if (!config) {
141
+ throw new Error("serve() requires a platform. Pass a PlatformConfig to createAgentX().");
142
+ }
143
+ if (!config.platform.channelServer) {
144
+ throw new Error(
145
+ "serve() requires platform.channelServer. Ensure your platform supports server mode."
146
+ );
147
+ }
148
+
149
+ const { createServer } = await import("./server");
150
+ return createServer({
151
+ platform: config.platform,
152
+ createDriver: config.createDriver,
153
+ port: serveConfig?.port,
154
+ host: serveConfig?.host,
155
+ server: serveConfig?.server as any,
156
+ wsPath: serveConfig?.wsPath,
157
+ });
158
+ },
159
+
160
+ async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {
161
+ return getLocalClient().rpc<T>(method, params);
162
+ },
163
+ };
164
+ }
165
+
166
+ export type { AgentXErrorCategory, AgentXErrorContext } from "@agentxjs/core/error";
167
+ // Re-export error types
168
+ export { AgentXError, AgentXErrorCode } from "@agentxjs/core/error";
169
+ // Re-export server
170
+ export { CommandHandler } from "./CommandHandler";
171
+ // Re-export Presentation types and classes
172
+ export type {
173
+ AssistantConversation,
174
+ Block,
175
+ Conversation,
176
+ ErrorConversation,
177
+ ImageBlock,
178
+ PresentationErrorHandler,
179
+ PresentationOptions,
180
+ PresentationState,
181
+ PresentationUpdateHandler,
182
+ TextBlock,
183
+ ToolBlock,
184
+ UserConversation,
185
+ } from "./presentation";
186
+ export {
187
+ addUserConversation,
188
+ createInitialState,
189
+ initialPresentationState,
190
+ messagesToConversations,
191
+ Presentation,
192
+ presentationReducer,
193
+ } from "./presentation";
194
+ export { createServer, type ServerConfig } from "./server";
195
+ // Re-export types
196
+ export type {
197
+ AgentCreateResponse,
198
+ AgentGetResponse,
199
+ AgentInfo,
200
+ AgentListResponse,
201
+ AgentNamespace,
202
+ AgentX,
203
+ AgentXBuilder,
204
+ AgentXServer,
205
+ BaseResponse,
206
+ ConnectOptions,
207
+ ContainerCreateResponse,
208
+ ContainerGetResponse,
209
+ ContainerInfo,
210
+ ContainerListResponse,
211
+ ContainerNamespace,
212
+ ImageCreateResponse,
213
+ ImageGetResponse,
214
+ ImageListResponse,
215
+ ImageNamespace,
216
+ ImageRecord,
217
+ LLMNamespace,
218
+ LLMProviderCreateResponse,
219
+ LLMProviderDefaultResponse,
220
+ LLMProviderGetResponse,
221
+ LLMProviderListResponse,
222
+ LLMProviderUpdateResponse,
223
+ MaybeAsync,
224
+ MessageSendResponse,
225
+ PresentationNamespace,
226
+ ServeConfig,
227
+ SessionNamespace,
228
+ } from "./types";
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Agent namespace factories
3
+ */
4
+
5
+ import type { RpcClient, RpcMethod } from "@agentxjs/core/network";
6
+ import type { AgentXRuntime } from "@agentxjs/core/runtime";
7
+ import type {
8
+ AgentCreateResponse,
9
+ AgentGetResponse,
10
+ AgentListResponse,
11
+ AgentNamespace,
12
+ BaseResponse,
13
+ } from "../types";
14
+
15
+ /**
16
+ * Create local agent namespace backed by embedded runtime
17
+ */
18
+ export function createLocalAgents(runtime: AgentXRuntime): AgentNamespace {
19
+ return {
20
+ async create(params: { imageId: string; agentId?: string }): Promise<AgentCreateResponse> {
21
+ // Reuse existing running agent for this image
22
+ const existingAgent = runtime
23
+ .getAgents()
24
+ .find((a) => a.imageId === params.imageId && a.lifecycle === "running");
25
+
26
+ if (existingAgent) {
27
+ return {
28
+ agentId: existingAgent.agentId,
29
+ imageId: existingAgent.imageId,
30
+ containerId: existingAgent.containerId,
31
+ sessionId: existingAgent.sessionId,
32
+ requestId: "",
33
+ };
34
+ }
35
+
36
+ const agent = await runtime.createAgent({
37
+ imageId: params.imageId,
38
+ agentId: params.agentId,
39
+ });
40
+
41
+ return {
42
+ agentId: agent.agentId,
43
+ imageId: agent.imageId,
44
+ containerId: agent.containerId,
45
+ sessionId: agent.sessionId,
46
+ requestId: "",
47
+ };
48
+ },
49
+
50
+ async get(agentId: string): Promise<AgentGetResponse> {
51
+ const agent = runtime.getAgent(agentId);
52
+ return {
53
+ agent: agent
54
+ ? {
55
+ agentId: agent.agentId,
56
+ imageId: agent.imageId,
57
+ containerId: agent.containerId,
58
+ sessionId: agent.sessionId,
59
+ lifecycle: agent.lifecycle,
60
+ }
61
+ : null,
62
+ exists: !!agent,
63
+ requestId: "",
64
+ };
65
+ },
66
+
67
+ async list(containerId?: string): Promise<AgentListResponse> {
68
+ const agents = containerId ? runtime.getAgentsByContainer(containerId) : runtime.getAgents();
69
+
70
+ return {
71
+ agents: agents.map((a) => ({
72
+ agentId: a.agentId,
73
+ imageId: a.imageId,
74
+ containerId: a.containerId,
75
+ sessionId: a.sessionId,
76
+ lifecycle: a.lifecycle,
77
+ })),
78
+ requestId: "",
79
+ };
80
+ },
81
+
82
+ async destroy(agentId: string): Promise<BaseResponse> {
83
+ const agent = runtime.getAgent(agentId);
84
+ if (agent) {
85
+ await runtime.destroyAgent(agentId);
86
+ }
87
+ return { requestId: "" };
88
+ },
89
+ };
90
+ }
91
+
92
+ /**
93
+ * Create remote agent namespace backed by RPC client
94
+ */
95
+ export function createRemoteAgents(rpcClient: RpcClient): AgentNamespace {
96
+ return {
97
+ async create(params: { imageId: string; agentId?: string }): Promise<AgentCreateResponse> {
98
+ // Agent creation via image.run RPC
99
+ const result = await rpcClient.call<AgentCreateResponse>("image.run" as RpcMethod, {
100
+ imageId: params.imageId,
101
+ agentId: params.agentId,
102
+ });
103
+ return { ...result, requestId: "" };
104
+ },
105
+
106
+ async get(agentId: string): Promise<AgentGetResponse> {
107
+ const result = await rpcClient.call<AgentGetResponse>("agent.get", { agentId });
108
+ return { ...result, requestId: "" };
109
+ },
110
+
111
+ async list(containerId?: string): Promise<AgentListResponse> {
112
+ const result = await rpcClient.call<AgentListResponse>("agent.list", { containerId });
113
+ return { ...result, requestId: "" };
114
+ },
115
+
116
+ async destroy(agentId: string): Promise<BaseResponse> {
117
+ const result = await rpcClient.call<BaseResponse>("agent.destroy", { agentId });
118
+ return { ...result, requestId: "" };
119
+ },
120
+ };
121
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Container namespace factories
3
+ */
4
+
5
+ import type { RpcClient } from "@agentxjs/core/network";
6
+ import type { AgentXPlatform } from "@agentxjs/core/runtime";
7
+ import type {
8
+ ContainerCreateResponse,
9
+ ContainerGetResponse,
10
+ ContainerListResponse,
11
+ ContainerNamespace,
12
+ } from "../types";
13
+
14
+ /**
15
+ * Create local container namespace backed by embedded runtime
16
+ */
17
+ export function createLocalContainers(platform: AgentXPlatform): ContainerNamespace {
18
+ return {
19
+ async create(containerId: string): Promise<ContainerCreateResponse> {
20
+ const { getOrCreateContainer } = await import("@agentxjs/core/container");
21
+ const { containerRepository, imageRepository, sessionRepository } = platform;
22
+
23
+ const container = await getOrCreateContainer(containerId, {
24
+ containerRepository,
25
+ imageRepository,
26
+ sessionRepository,
27
+ });
28
+
29
+ return { containerId: container.containerId, requestId: "" };
30
+ },
31
+
32
+ async get(containerId: string): Promise<ContainerGetResponse> {
33
+ const exists = await platform.containerRepository.containerExists(containerId);
34
+ return { containerId, exists, requestId: "" };
35
+ },
36
+
37
+ async list(): Promise<ContainerListResponse> {
38
+ const containers = await platform.containerRepository.findAllContainers();
39
+ return { containerIds: containers.map((c) => c.containerId), requestId: "" };
40
+ },
41
+ };
42
+ }
43
+
44
+ /**
45
+ * Create remote container namespace backed by RPC client
46
+ */
47
+ export function createRemoteContainers(rpcClient: RpcClient): ContainerNamespace {
48
+ return {
49
+ async create(containerId: string): Promise<ContainerCreateResponse> {
50
+ const result = await rpcClient.call<ContainerCreateResponse>("container.create", {
51
+ containerId,
52
+ });
53
+ return { ...result, requestId: "" };
54
+ },
55
+
56
+ async get(containerId: string): Promise<ContainerGetResponse> {
57
+ const result = await rpcClient.call<ContainerGetResponse>("container.get", {
58
+ containerId,
59
+ });
60
+ return { ...result, requestId: "" };
61
+ },
62
+
63
+ async list(): Promise<ContainerListResponse> {
64
+ const result = await rpcClient.call<ContainerListResponse>("container.list", {});
65
+ return { ...result, requestId: "" };
66
+ },
67
+ };
68
+ }