agentxjs 2.3.0 → 2.3.1

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.
Files changed (2) hide show
  1. package/README.md +57 -19
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -178,25 +178,54 @@ const response = await ax.rpc(request.method, request.params);
178
178
 
179
179
  ### Error Handling
180
180
 
181
- Top-level error handler — receives structured `AgentXError` from all layers (driver, persistence, connection, runtime). Independent of stream events and Presentation API.
181
+ AgentX has two layers of error handling, serving different purposes:
182
+
183
+ | Layer | Purpose | Who uses it | How errors arrive |
184
+ | ----- | ------- | ----------- | ----------------- |
185
+ | **Presentation** | Show errors to end users in chat | UI developers | `ErrorConversation` in `state.conversations` |
186
+ | **`ax.onError`** | Programmatic monitoring & alerting | Platform operators | `AgentXError` callback |
187
+
188
+ Most applications only need the Presentation layer. `ax.onError` is for advanced scenarios like Sentry integration or custom circuit-breaker logic.
189
+
190
+ #### Presentation Errors (recommended)
191
+
192
+ When an LLM call fails (e.g., 403 Forbidden, network timeout), the error automatically appears in `state.conversations` as an `ErrorConversation`:
182
193
 
183
194
  ```typescript
184
- import { AgentXError } from "agentxjs";
195
+ const presentation = await ax.presentation.create(agentId, {
196
+ onUpdate: (state) => {
197
+ for (const conv of state.conversations) {
198
+ if (conv.role === "user") {
199
+ renderUserMessage(conv);
200
+ } else if (conv.role === "assistant") {
201
+ renderAssistantMessage(conv);
202
+ } else if (conv.role === "error") {
203
+ // LLM errors show up here automatically
204
+ renderErrorMessage(conv.message);
205
+ // e.g. "403 Forbidden: Invalid API key"
206
+ }
207
+ }
208
+ },
209
+ });
210
+ ```
185
211
 
186
- ax.onError((error) => {
187
- console.error(`[${error.category}] ${error.code}: ${error.message}`);
212
+ The flow is fully automatic — no extra code needed:
188
213
 
189
- if (error.code === "CIRCUIT_OPEN") {
190
- // Too many consecutive LLM failures stop sending requests
191
- }
214
+ ```
215
+ LLM API fails Driver emits error Engine creates ErrorConversation
216
+ → Presentation state updates → onUpdate fires → UI renders error
217
+ ```
218
+
219
+ `state.streaming` resets to `null` and `state.status` returns to `"idle"`, so the UI naturally stops showing loading indicators.
192
220
 
193
- if (error.code === "PERSISTENCE_FAILED") {
194
- // Message failed to save — conversation continues but data may be lost
195
- }
221
+ #### `ax.onError` (advanced)
196
222
 
197
- if (!error.recoverable) {
198
- // Fatal error — consider restarting the agent
199
- }
223
+ For monitoring, logging, or custom recovery logic. Receives structured `AgentXError` from all layers (driver, persistence, connection). Independent of Presentation — fires even without a Presentation instance.
224
+
225
+ ```typescript
226
+ ax.onError((error) => {
227
+ reportToSentry(error);
228
+ console.error(`[${error.category}] ${error.code}: ${error.message}`);
200
229
  });
201
230
  ```
202
231
 
@@ -204,13 +233,13 @@ ax.onError((error) => {
204
233
 
205
234
  | Property | Type | Description |
206
235
  | ------------- | -------- | ------------------------------------ |
207
- | `code` | string | Error code (e.g. `PERSISTENCE_FAILED`) |
236
+ | `code` | string | `DRIVER_ERROR`, `CIRCUIT_OPEN`, `PERSISTENCE_FAILED`, `CONNECTION_FAILED` |
208
237
  | `category` | string | `"driver"` \| `"persistence"` \| `"connection"` \| `"runtime"` |
209
238
  | `recoverable` | boolean | Whether the caller should retry |
210
239
  | `context` | object | `{ agentId?, sessionId?, imageId? }` |
211
240
  | `cause` | Error? | Original error |
212
241
 
213
- **Built-in circuit breaker:** After 5 consecutive driver failures, the circuit opens and rejects new requests. After 30s cooldown, one probe request is allowed through. Success closes the circuit.
242
+ **Built-in circuit breaker:** After 5 consecutive driver failures, the circuit opens and rejects new requests for 30s. This is automatic no code required.
214
243
 
215
244
  ### Stream Events
216
245
 
@@ -222,21 +251,22 @@ ax.onError((error) => {
222
251
  | `input_json_delta` | `{ partialJson }` | Incremental tool input |
223
252
  | `tool_result` | `{ toolCallId, result }` | Tool execution result |
224
253
  | `message_stop` | `{ stopReason }` | Response complete |
225
- | `error` | `{ message }` | Error occurred |
254
+ | `error` | `{ message }` | Error during streaming |
255
+
256
+ > **Note:** If you use the Presentation API, you don't need to handle the `error` stream event — it is automatically converted to an `ErrorConversation` in `state.conversations`.
226
257
 
227
258
  ### Presentation API
228
259
 
229
- High-level UI state management. Aggregates raw stream events into structured conversation state.
260
+ High-level UI state management. Aggregates raw stream events into structured conversation state — the recommended way to build chat UIs.
230
261
 
231
262
  ```typescript
232
263
  const presentation = await ax.presentation.create(agentId, {
233
264
  onUpdate: (state) => {
234
- // state.conversations — completed messages (includes history)
265
+ // state.conversations — completed messages (user, assistant, and error)
235
266
  // state.streaming — current streaming response (or null)
236
267
  // state.status — "idle" | "thinking" | "responding" | "executing"
237
268
  renderUI(state);
238
269
  },
239
- onError: (error) => console.error(error),
240
270
  });
241
271
 
242
272
  await presentation.send("What is the weather?");
@@ -244,6 +274,14 @@ const state = presentation.getState();
244
274
  presentation.dispose();
245
275
  ```
246
276
 
277
+ **Conversation types in `state.conversations`:**
278
+
279
+ | `role` | Type | Content |
280
+ | ------ | ---- | ------- |
281
+ | `"user"` | `UserConversation` | `blocks: [{ type: "text", content }]` |
282
+ | `"assistant"` | `AssistantConversation` | `blocks: [{ type: "text", content }, { type: "tool_use", ... }]` |
283
+ | `"error"` | `ErrorConversation` | `message: string` — the error description |
284
+
247
285
  For custom state management, use the exported reducer:
248
286
 
249
287
  ```typescript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxjs",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "AgentX Client SDK - Local and remote AI agent management",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,12 +23,12 @@
23
23
  "test": "bun test bdd/"
24
24
  },
25
25
  "dependencies": {
26
- "@agentxjs/core": "^2.3.0",
26
+ "@agentxjs/core": "^2.3.1",
27
27
  "@deepracticex/id": "^0.2.0",
28
28
  "@deepracticex/logger": "^1.2.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@agentxjs/devtools": "^2.3.0",
31
+ "@agentxjs/devtools": "^2.3.1",
32
32
  "@deepracticex/bdd": "^0.3.0",
33
33
  "tsx": "^4.19.0",
34
34
  "typescript": "^5.3.3"