agentxjs 1.9.0 → 1.9.2-dev

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/build.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Build script for agentxjs
3
+ *
4
+ * Generates dist/ with JS and .d.ts files
5
+ */
6
+
7
+ import { $ } from "bun";
8
+
9
+ console.log("Building agentxjs...");
10
+
11
+ // Clean dist
12
+ await $`rm -rf dist`;
13
+
14
+ // Generate .d.ts using tsc
15
+ await $`tsc --emitDeclarationOnly --outDir dist`;
16
+
17
+ // Build with bun
18
+ await Bun.build({
19
+ entrypoints: ["./src/index.ts"],
20
+ outdir: "./dist",
21
+ format: "esm",
22
+ target: "node",
23
+ sourcemap: "external",
24
+ });
25
+
26
+ console.log("Build complete!");
package/package.json CHANGED
@@ -1,49 +1,30 @@
1
1
  {
2
2
  "name": "agentxjs",
3
- "version": "1.9.0",
4
- "description": "Unified API for AI Agents - Server and Browser",
3
+ "version": "1.9.2-dev",
4
+ "description": "AgentX Client SDK - Connect to AgentX servers",
5
5
  "license": "MIT",
6
- "engines": {
7
- "node": ">=22.0.0"
8
- },
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/Deepractice/AgentX.git"
12
- },
13
- "homepage": "https://github.com/Deepractice/AgentX",
14
6
  "type": "module",
15
7
  "main": "./dist/index.js",
16
8
  "types": "./dist/index.d.ts",
17
9
  "exports": {
18
10
  ".": {
19
- "browser": "./dist/browser.js",
20
- "node": "./dist/index.js",
21
- "types": "./dist/index.d.ts",
22
- "default": "./dist/index.js"
11
+ "types": "./src/index.ts",
12
+ "default": "./src/index.ts"
23
13
  }
24
14
  },
25
- "files": [
26
- "dist"
27
- ],
28
15
  "scripts": {
29
16
  "build": "bun run build.ts",
30
- "clean": "rm -rf dist test-results",
31
- "lint": "eslint .",
32
17
  "typecheck": "tsc --noEmit",
33
- "test": "bun test",
34
- "test:watch": "bun test --watch"
18
+ "test": "bun test"
35
19
  },
36
20
  "dependencies": {
37
- "@agentxjs/common": "^1.9.0",
38
- "@agentxjs/network": "^1.9.0",
39
- "@agentxjs/types": "^1.9.0",
21
+ "@agentxjs/core": "workspace:*",
40
22
  "reconnecting-websocket": "^4.4.0",
41
23
  "ws": "^8.18.0"
42
24
  },
43
25
  "devDependencies": {
44
- "@agentxjs/persistence": "^1.9.0",
45
- "@agentxjs/queue": "^1.9.0",
46
- "@agentxjs/runtime": "^1.9.0"
26
+ "@types/ws": "^8.5.10",
27
+ "typescript": "^5.3.3"
47
28
  },
48
29
  "publishConfig": {
49
30
  "access": "public"
@@ -0,0 +1,221 @@
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 { BusEvent, EventBus, BusEventHandler, Unsubscribe } from "@agentxjs/core/event";
9
+ import { EventBusImpl } from "@agentxjs/core/event";
10
+ import { RpcClient, type RpcMethod } from "@agentxjs/core/network";
11
+ import { createLogger } from "commonxjs/logger";
12
+ import type {
13
+ AgentX,
14
+ AgentXConfig,
15
+ AgentCreateResponse,
16
+ AgentGetResponse,
17
+ AgentListResponse,
18
+ ImageCreateResponse,
19
+ ImageGetResponse,
20
+ ImageListResponse,
21
+ ContainerCreateResponse,
22
+ ContainerGetResponse,
23
+ ContainerListResponse,
24
+ MessageSendResponse,
25
+ BaseResponse,
26
+ } from "./types";
27
+ import { Presentation, type PresentationOptions } from "./presentation";
28
+
29
+ const logger = createLogger("agentx/RemoteClient");
30
+
31
+ /**
32
+ * RemoteClient implementation using JSON-RPC 2.0
33
+ */
34
+ export class RemoteClient implements AgentX {
35
+ private readonly config: AgentXConfig;
36
+ private readonly eventBus: EventBus;
37
+ private readonly rpcClient: RpcClient;
38
+
39
+ constructor(config: AgentXConfig) {
40
+ this.config = config;
41
+ this.eventBus = new EventBusImpl();
42
+
43
+ // Create RPC client
44
+ this.rpcClient = new RpcClient({
45
+ url: config.serverUrl,
46
+ timeout: config.timeout ?? 30000,
47
+ autoReconnect: config.autoReconnect ?? true,
48
+ headers: config.headers as Record<string, string> | undefined,
49
+ debug: false,
50
+ });
51
+
52
+ // Forward stream events to internal event bus
53
+ this.rpcClient.onStreamEvent((topic, event) => {
54
+ logger.debug("Received stream event", { topic, type: event.type });
55
+ this.eventBus.emit(event as BusEvent);
56
+ });
57
+ }
58
+
59
+ // ==================== Properties ====================
60
+
61
+ get connected(): boolean {
62
+ return this.rpcClient.connected;
63
+ }
64
+
65
+ get events(): EventBus {
66
+ return this.eventBus;
67
+ }
68
+
69
+ // ==================== Connection ====================
70
+
71
+ async connect(): Promise<void> {
72
+ await this.rpcClient.connect();
73
+ logger.info("Connected to server", { url: this.config.serverUrl });
74
+ }
75
+
76
+ async disconnect(): Promise<void> {
77
+ this.rpcClient.disconnect();
78
+ logger.info("Disconnected from server");
79
+ }
80
+
81
+ async dispose(): Promise<void> {
82
+ this.rpcClient.dispose();
83
+ this.eventBus.destroy();
84
+ logger.info("RemoteClient disposed");
85
+ }
86
+
87
+ // ==================== Container Operations ====================
88
+
89
+ async createContainer(containerId: string): Promise<ContainerCreateResponse> {
90
+ const result = await this.rpcClient.call<ContainerCreateResponse>("container.create", {
91
+ containerId,
92
+ });
93
+ return { ...result, requestId: "" };
94
+ }
95
+
96
+ async getContainer(containerId: string): Promise<ContainerGetResponse> {
97
+ const result = await this.rpcClient.call<ContainerGetResponse>("container.get", {
98
+ containerId,
99
+ });
100
+ return { ...result, requestId: "" };
101
+ }
102
+
103
+ async listContainers(): Promise<ContainerListResponse> {
104
+ const result = await this.rpcClient.call<ContainerListResponse>("container.list", {});
105
+ return { ...result, requestId: "" };
106
+ }
107
+
108
+ // ==================== Image Operations ====================
109
+
110
+ async createImage(params: {
111
+ containerId: string;
112
+ name?: string;
113
+ description?: string;
114
+ systemPrompt?: string;
115
+ mcpServers?: Record<string, unknown>;
116
+ }): Promise<ImageCreateResponse> {
117
+ const result = await this.rpcClient.call<ImageCreateResponse>("image.create", params);
118
+
119
+ // Auto subscribe to session events
120
+ if (result.__subscriptions) {
121
+ for (const sessionId of result.__subscriptions) {
122
+ this.subscribe(sessionId);
123
+ }
124
+ }
125
+
126
+ return { ...result, requestId: "" };
127
+ }
128
+
129
+ async getImage(imageId: string): Promise<ImageGetResponse> {
130
+ const result = await this.rpcClient.call<ImageGetResponse>("image.get", { imageId });
131
+
132
+ // Auto subscribe
133
+ if (result.__subscriptions) {
134
+ for (const sessionId of result.__subscriptions) {
135
+ this.subscribe(sessionId);
136
+ }
137
+ }
138
+
139
+ return { ...result, requestId: "" };
140
+ }
141
+
142
+ async listImages(containerId?: string): Promise<ImageListResponse> {
143
+ const result = await this.rpcClient.call<ImageListResponse>("image.list", { containerId });
144
+
145
+ // Auto subscribe
146
+ if (result.__subscriptions) {
147
+ for (const sessionId of result.__subscriptions) {
148
+ this.subscribe(sessionId);
149
+ }
150
+ }
151
+
152
+ return { ...result, requestId: "" };
153
+ }
154
+
155
+ async deleteImage(imageId: string): Promise<BaseResponse> {
156
+ const result = await this.rpcClient.call<BaseResponse>("image.delete", { imageId });
157
+ return { ...result, requestId: "" };
158
+ }
159
+
160
+ // ==================== Agent Operations ====================
161
+
162
+ async createAgent(params: { imageId: string; agentId?: string }): Promise<AgentCreateResponse> {
163
+ // Agent creation via image.run RPC
164
+ const result = await this.rpcClient.call<AgentCreateResponse>("image.run" as RpcMethod, {
165
+ imageId: params.imageId,
166
+ agentId: params.agentId,
167
+ });
168
+ return { ...result, requestId: "" };
169
+ }
170
+
171
+ async getAgent(agentId: string): Promise<AgentGetResponse> {
172
+ const result = await this.rpcClient.call<AgentGetResponse>("agent.get", { agentId });
173
+ return { ...result, requestId: "" };
174
+ }
175
+
176
+ async listAgents(containerId?: string): Promise<AgentListResponse> {
177
+ const result = await this.rpcClient.call<AgentListResponse>("agent.list", { containerId });
178
+ return { ...result, requestId: "" };
179
+ }
180
+
181
+ async destroyAgent(agentId: string): Promise<BaseResponse> {
182
+ const result = await this.rpcClient.call<BaseResponse>("agent.destroy", { agentId });
183
+ return { ...result, requestId: "" };
184
+ }
185
+
186
+ // ==================== Message Operations ====================
187
+
188
+ async sendMessage(agentId: string, content: string | unknown[]): Promise<MessageSendResponse> {
189
+ const result = await this.rpcClient.call<MessageSendResponse>("message.send", {
190
+ agentId,
191
+ content,
192
+ });
193
+ return { ...result, requestId: "" };
194
+ }
195
+
196
+ async interrupt(agentId: string): Promise<BaseResponse> {
197
+ const result = await this.rpcClient.call<BaseResponse>("agent.interrupt", { agentId });
198
+ return { ...result, requestId: "" };
199
+ }
200
+
201
+ // ==================== Event Subscription ====================
202
+
203
+ on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe {
204
+ return this.eventBus.on(type, handler);
205
+ }
206
+
207
+ onAny(handler: BusEventHandler): Unsubscribe {
208
+ return this.eventBus.onAny(handler);
209
+ }
210
+
211
+ subscribe(sessionId: string): void {
212
+ this.rpcClient.subscribe(sessionId);
213
+ logger.debug("Subscribed to session", { sessionId });
214
+ }
215
+
216
+ // ==================== Presentation ====================
217
+
218
+ presentation(agentId: string, options?: PresentationOptions): Presentation {
219
+ return new Presentation(this, agentId, options);
220
+ }
221
+ }
package/src/index.ts ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * agentxjs - AgentX Client SDK
3
+ *
4
+ * Connect to AgentX servers from Node.js and browsers.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { createAgentX } from "agentxjs";
9
+ *
10
+ * // Connect to server
11
+ * const agentx = await createAgentX({
12
+ * serverUrl: "ws://localhost:5200",
13
+ * headers: { Authorization: "Bearer sk-xxx" },
14
+ * context: { userId: "123", tenantId: "abc" },
15
+ * });
16
+ *
17
+ * // Create container and image
18
+ * await agentx.createContainer("my-container");
19
+ * const { record: image } = await agentx.createImage({
20
+ * containerId: "my-container",
21
+ * name: "Assistant",
22
+ * systemPrompt: "You are a helpful assistant",
23
+ * });
24
+ *
25
+ * // Create agent and send message
26
+ * const { agentId } = await agentx.createAgent({ imageId: image.imageId });
27
+ *
28
+ * // Subscribe to events
29
+ * agentx.on("text_delta", (event) => {
30
+ * process.stdout.write(event.data.text);
31
+ * });
32
+ *
33
+ * agentx.on("assistant_message", (event) => {
34
+ * console.log("Complete:", event.data.content);
35
+ * });
36
+ *
37
+ * // Send message
38
+ * await agentx.sendMessage(agentId, "Hello!");
39
+ *
40
+ * // Cleanup
41
+ * await agentx.dispose();
42
+ * ```
43
+ *
44
+ * @example Dynamic headers and context
45
+ * ```typescript
46
+ * const agentx = await createAgentX({
47
+ * serverUrl: "ws://localhost:5200",
48
+ * headers: () => ({ Authorization: `Bearer ${getToken()}` }),
49
+ * context: async () => ({
50
+ * userId: await getUserId(),
51
+ * permissions: await getPermissions(),
52
+ * }),
53
+ * });
54
+ * ```
55
+ */
56
+
57
+ import { RemoteClient } from "./RemoteClient";
58
+ import type { AgentX, AgentXConfig } from "./types";
59
+
60
+ /**
61
+ * Create an AgentX client
62
+ *
63
+ * @param config - Client configuration
64
+ * @returns Connected AgentX client
65
+ */
66
+ export async function createAgentX(config: AgentXConfig): Promise<AgentX> {
67
+ const client = new RemoteClient(config);
68
+ await client.connect();
69
+ return client;
70
+ }
71
+
72
+ // Re-export types
73
+ export type {
74
+ AgentX,
75
+ AgentXConfig,
76
+ MaybeAsync,
77
+ AgentInfo,
78
+ ImageRecord,
79
+ ContainerInfo,
80
+ AgentCreateResponse,
81
+ AgentGetResponse,
82
+ AgentListResponse,
83
+ ImageCreateResponse,
84
+ ImageGetResponse,
85
+ ImageListResponse,
86
+ ContainerCreateResponse,
87
+ ContainerGetResponse,
88
+ ContainerListResponse,
89
+ MessageSendResponse,
90
+ BaseResponse,
91
+ } from "./types";
92
+
93
+ // Re-export RemoteClient for advanced use
94
+ export { RemoteClient } from "./RemoteClient";
95
+
96
+ // Re-export Presentation types and classes
97
+ export type {
98
+ Block,
99
+ TextBlock,
100
+ ToolBlock,
101
+ ImageBlock,
102
+ Conversation,
103
+ UserConversation,
104
+ AssistantConversation,
105
+ ErrorConversation,
106
+ PresentationState,
107
+ PresentationOptions,
108
+ PresentationUpdateHandler,
109
+ PresentationErrorHandler,
110
+ } from "./presentation";
111
+
112
+ export {
113
+ Presentation,
114
+ presentationReducer,
115
+ addUserConversation,
116
+ createInitialState,
117
+ initialPresentationState,
118
+ } from "./presentation";
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Presentation Class
3
+ *
4
+ * High-level API for UI integration.
5
+ * Wraps AgentX client and provides presentation state management.
6
+ */
7
+
8
+ import type { AgentX } from "../types";
9
+ import type { Unsubscribe, BusEvent } from "@agentxjs/core/event";
10
+ import type { PresentationState } from "./types";
11
+ import {
12
+ presentationReducer,
13
+ addUserConversation,
14
+ createInitialState,
15
+ } from "./reducer";
16
+
17
+ /**
18
+ * Presentation update handler
19
+ */
20
+ export type PresentationUpdateHandler = (state: PresentationState) => void;
21
+
22
+ /**
23
+ * Presentation error handler
24
+ */
25
+ export type PresentationErrorHandler = (error: Error) => void;
26
+
27
+ /**
28
+ * Presentation options
29
+ */
30
+ export interface PresentationOptions {
31
+ /**
32
+ * Called on every state update
33
+ */
34
+ onUpdate?: PresentationUpdateHandler;
35
+
36
+ /**
37
+ * Called on errors
38
+ */
39
+ onError?: PresentationErrorHandler;
40
+ }
41
+
42
+ /**
43
+ * Presentation - UI-friendly wrapper for AgentX
44
+ */
45
+ export class Presentation {
46
+ private agentx: AgentX;
47
+ private agentId: string;
48
+ private state: PresentationState;
49
+ private updateHandlers: Set<PresentationUpdateHandler> = new Set();
50
+ private errorHandlers: Set<PresentationErrorHandler> = new Set();
51
+ private eventUnsubscribe: Unsubscribe | null = null;
52
+
53
+ constructor(agentx: AgentX, agentId: string, options?: PresentationOptions) {
54
+ this.agentx = agentx;
55
+ this.agentId = agentId;
56
+ this.state = createInitialState();
57
+
58
+ // Register initial handlers
59
+ if (options?.onUpdate) {
60
+ this.updateHandlers.add(options.onUpdate);
61
+ }
62
+ if (options?.onError) {
63
+ this.errorHandlers.add(options.onError);
64
+ }
65
+
66
+ // Subscribe to all events
67
+ this.subscribeToEvents();
68
+ }
69
+
70
+ /**
71
+ * Get current state
72
+ */
73
+ getState(): PresentationState {
74
+ return this.state;
75
+ }
76
+
77
+ /**
78
+ * Subscribe to state updates
79
+ */
80
+ onUpdate(handler: PresentationUpdateHandler): Unsubscribe {
81
+ this.updateHandlers.add(handler);
82
+ // Immediately call with current state
83
+ handler(this.state);
84
+ return () => {
85
+ this.updateHandlers.delete(handler);
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Subscribe to errors
91
+ */
92
+ onError(handler: PresentationErrorHandler): Unsubscribe {
93
+ this.errorHandlers.add(handler);
94
+ return () => {
95
+ this.errorHandlers.delete(handler);
96
+ };
97
+ }
98
+
99
+ /**
100
+ * Send a message
101
+ */
102
+ async send(content: string): Promise<void> {
103
+ // Add user conversation
104
+ this.state = addUserConversation(this.state, content);
105
+ this.notify();
106
+
107
+ try {
108
+ // Send message via agentx
109
+ await this.agentx.sendMessage(this.agentId, content);
110
+ } catch (error) {
111
+ this.notifyError(error instanceof Error ? error : new Error(String(error)));
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Interrupt current response
117
+ */
118
+ async interrupt(): Promise<void> {
119
+ try {
120
+ await this.agentx.interrupt(this.agentId);
121
+ } catch (error) {
122
+ this.notifyError(error instanceof Error ? error : new Error(String(error)));
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Reset state
128
+ */
129
+ reset(): void {
130
+ this.state = createInitialState();
131
+ this.notify();
132
+ }
133
+
134
+ /**
135
+ * Dispose and cleanup
136
+ */
137
+ dispose(): void {
138
+ if (this.eventUnsubscribe) {
139
+ this.eventUnsubscribe();
140
+ this.eventUnsubscribe = null;
141
+ }
142
+ this.updateHandlers.clear();
143
+ this.errorHandlers.clear();
144
+ }
145
+
146
+ // ==================== Private ====================
147
+
148
+ private subscribeToEvents(): void {
149
+ // Subscribe to all events and filter by agentId
150
+ this.eventUnsubscribe = this.agentx.onAny((event: BusEvent) => {
151
+ // Filter events for this agent (if context is available)
152
+ // Note: Events from server may or may not include context with agentId
153
+ const eventWithContext = event as BusEvent & { context?: { agentId?: string } };
154
+ const eventAgentId = eventWithContext.context?.agentId;
155
+
156
+ // Only filter if event has agentId and it doesn't match
157
+ if (eventAgentId && eventAgentId !== this.agentId) {
158
+ return;
159
+ }
160
+
161
+ // Reduce event into state
162
+ const newState = presentationReducer(this.state, event);
163
+ if (newState !== this.state) {
164
+ this.state = newState;
165
+ this.notify();
166
+ }
167
+ });
168
+ }
169
+
170
+ private notify(): void {
171
+ for (const handler of this.updateHandlers) {
172
+ try {
173
+ handler(this.state);
174
+ } catch (error) {
175
+ console.error("Presentation update handler error:", error);
176
+ }
177
+ }
178
+ }
179
+
180
+ private notifyError(error: Error): void {
181
+ for (const handler of this.errorHandlers) {
182
+ try {
183
+ handler(error);
184
+ } catch (e) {
185
+ console.error("Presentation error handler error:", e);
186
+ }
187
+ }
188
+ }
189
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Presentation Module
3
+ *
4
+ * UI-friendly data model and state management.
5
+ */
6
+
7
+ export type {
8
+ Block,
9
+ TextBlock,
10
+ ToolBlock,
11
+ ImageBlock,
12
+ Conversation,
13
+ UserConversation,
14
+ AssistantConversation,
15
+ ErrorConversation,
16
+ PresentationState,
17
+ } from "./types";
18
+
19
+ export { initialPresentationState } from "./types";
20
+
21
+ export {
22
+ presentationReducer,
23
+ addUserConversation,
24
+ createInitialState,
25
+ } from "./reducer";
26
+
27
+ export {
28
+ Presentation,
29
+ type PresentationOptions,
30
+ type PresentationUpdateHandler,
31
+ type PresentationErrorHandler,
32
+ } from "./Presentation";