@antipopp/agno-client 0.7.0 → 0.9.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/README.md +101 -0
- package/dist/index.d.mts +32 -8
- package/dist/index.d.ts +32 -8
- package/dist/index.js +190 -25
- package/dist/index.mjs +190 -25
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -68,6 +68,8 @@ new AgnoClient(config: AgnoClientConfig)
|
|
|
68
68
|
- `dbId` (string, optional) - Database ID
|
|
69
69
|
- `sessionId` (string, optional) - Current session ID
|
|
70
70
|
- `userId` (string, optional) - User ID to link sessions to a specific user
|
|
71
|
+
- `headers` (Record<string, string>, optional) - Global custom headers for all API requests
|
|
72
|
+
- `params` (Record<string, string>, optional) - Global query parameters for all API requests
|
|
71
73
|
|
|
72
74
|
### Methods
|
|
73
75
|
|
|
@@ -88,6 +90,17 @@ await client.sendMessage(formData);
|
|
|
88
90
|
await client.sendMessage('Hello!', {
|
|
89
91
|
headers: { 'X-Custom-Header': 'value' }
|
|
90
92
|
});
|
|
93
|
+
|
|
94
|
+
// With query parameters
|
|
95
|
+
await client.sendMessage('Hello!', {
|
|
96
|
+
params: { temperature: '0.7', max_tokens: '500' }
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// With both headers and params
|
|
100
|
+
await client.sendMessage('Hello!', {
|
|
101
|
+
headers: { 'X-Request-ID': '12345' },
|
|
102
|
+
params: { debug: 'true' }
|
|
103
|
+
});
|
|
91
104
|
```
|
|
92
105
|
|
|
93
106
|
#### `getMessages()`
|
|
@@ -241,6 +254,94 @@ try {
|
|
|
241
254
|
}
|
|
242
255
|
```
|
|
243
256
|
|
|
257
|
+
### Custom Headers and Query Parameters
|
|
258
|
+
|
|
259
|
+
The client supports both global and per-request headers and query parameters.
|
|
260
|
+
|
|
261
|
+
#### Global Configuration
|
|
262
|
+
|
|
263
|
+
Set headers and params in the client config to apply them to all API requests:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
const client = new AgnoClient({
|
|
267
|
+
endpoint: 'http://localhost:7777',
|
|
268
|
+
agentId: 'agent-123',
|
|
269
|
+
headers: {
|
|
270
|
+
'X-API-Version': 'v2',
|
|
271
|
+
'X-Client-ID': 'my-app'
|
|
272
|
+
},
|
|
273
|
+
params: {
|
|
274
|
+
locale: 'en-US',
|
|
275
|
+
environment: 'production'
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
#### Per-Request Options
|
|
281
|
+
|
|
282
|
+
Override or add headers/params for specific requests:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Per-request overrides global settings
|
|
286
|
+
await client.sendMessage('Hello!', {
|
|
287
|
+
headers: { 'X-Request-ID': '12345' },
|
|
288
|
+
params: { temperature: '0.7' }
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// All methods support headers and params
|
|
292
|
+
await client.loadSession('session-123', {
|
|
293
|
+
params: { include_metadata: 'true' }
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
await client.fetchSessions({
|
|
297
|
+
params: { limit: '50', status: 'active' }
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
await client.continueRun(tools, {
|
|
301
|
+
headers: { 'X-Trace-ID': 'abc123' },
|
|
302
|
+
params: { debug: 'true' }
|
|
303
|
+
});
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### Merge Behavior
|
|
307
|
+
|
|
308
|
+
**Headers:**
|
|
309
|
+
1. Global headers from `config.headers` (lowest precedence)
|
|
310
|
+
2. Per-request headers (overrides global)
|
|
311
|
+
3. Authorization header from `authToken` (highest precedence - always overrides)
|
|
312
|
+
|
|
313
|
+
**Query Parameters:**
|
|
314
|
+
1. Global params from `config.params` (lowest precedence)
|
|
315
|
+
2. Per-request params (highest precedence - overrides global)
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
const client = new AgnoClient({
|
|
319
|
+
endpoint: 'http://localhost:7777',
|
|
320
|
+
agentId: 'agent-123',
|
|
321
|
+
params: { version: 'v1', locale: 'en-US' }
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// This request will have: version=v2 (overridden), locale=en-US (from global), debug=true (added)
|
|
325
|
+
await client.sendMessage('Hello!', {
|
|
326
|
+
params: { version: 'v2', debug: 'true' }
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
#### Common Use Cases
|
|
331
|
+
|
|
332
|
+
**Headers:**
|
|
333
|
+
- Request tracking: `{ 'X-Request-ID': uuid() }`
|
|
334
|
+
- API versioning: `{ 'X-API-Version': 'v2' }`
|
|
335
|
+
- Client identification: `{ 'X-Client-ID': 'mobile-app' }`
|
|
336
|
+
- Custom auth: `{ 'X-Custom-Auth': 'token' }`
|
|
337
|
+
|
|
338
|
+
**Query Parameters:**
|
|
339
|
+
- Model configuration: `{ temperature: '0.7', max_tokens: '500' }`
|
|
340
|
+
- Feature flags: `{ enable_streaming: 'true' }`
|
|
341
|
+
- Locale/language: `{ locale: 'en-US', timezone: 'America/New_York' }`
|
|
342
|
+
- Debugging: `{ debug: 'true', trace_id: 'xyz' }`
|
|
343
|
+
- Pagination: `{ page: '1', limit: '50' }`
|
|
344
|
+
|
|
244
345
|
### Request Cancellation
|
|
245
346
|
|
|
246
347
|
Use `AbortController` to cancel ongoing requests. This is essential for preventing memory leaks when components unmount or users navigate away during streaming:
|
package/dist/index.d.mts
CHANGED
|
@@ -13,6 +13,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
13
13
|
private eventProcessor;
|
|
14
14
|
private state;
|
|
15
15
|
private pendingUISpecs;
|
|
16
|
+
private runCompletedSuccessfully;
|
|
16
17
|
constructor(config: AgnoClientConfig);
|
|
17
18
|
/**
|
|
18
19
|
* Get current messages
|
|
@@ -39,6 +40,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
39
40
|
*/
|
|
40
41
|
sendMessage(message: string | FormData, options?: {
|
|
41
42
|
headers?: Record<string, string>;
|
|
43
|
+
params?: Record<string, string>;
|
|
42
44
|
}): Promise<void>;
|
|
43
45
|
/**
|
|
44
46
|
* Handle streaming chunk
|
|
@@ -48,18 +50,31 @@ declare class AgnoClient extends EventEmitter {
|
|
|
48
50
|
* Handle error
|
|
49
51
|
*/
|
|
50
52
|
private handleError;
|
|
53
|
+
/**
|
|
54
|
+
* Refresh messages from the session API after run completion.
|
|
55
|
+
* Replaces streamed messages with authoritative session data.
|
|
56
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
private refreshSessionMessages;
|
|
51
60
|
/**
|
|
52
61
|
* Load a session
|
|
53
62
|
*/
|
|
54
|
-
loadSession(sessionId: string
|
|
63
|
+
loadSession(sessionId: string, options?: {
|
|
64
|
+
params?: Record<string, string>;
|
|
65
|
+
}): Promise<ChatMessage[]>;
|
|
55
66
|
/**
|
|
56
67
|
* Fetch all sessions
|
|
57
68
|
*/
|
|
58
|
-
fetchSessions(
|
|
69
|
+
fetchSessions(options?: {
|
|
70
|
+
params?: Record<string, string>;
|
|
71
|
+
}): Promise<SessionEntry[]>;
|
|
59
72
|
/**
|
|
60
73
|
* Delete a session
|
|
61
74
|
*/
|
|
62
|
-
deleteSession(sessionId: string
|
|
75
|
+
deleteSession(sessionId: string, options?: {
|
|
76
|
+
params?: Record<string, string>;
|
|
77
|
+
}): Promise<void>;
|
|
63
78
|
/**
|
|
64
79
|
* Add tool calls to the last message
|
|
65
80
|
* Used by frontend execution to add tool calls that were executed locally
|
|
@@ -83,30 +98,39 @@ declare class AgnoClient extends EventEmitter {
|
|
|
83
98
|
* Teams do not support the continue endpoint.
|
|
84
99
|
*
|
|
85
100
|
* @param tools - Array of tool calls with execution results
|
|
86
|
-
* @param options - Optional request headers
|
|
101
|
+
* @param options - Optional request headers and query parameters
|
|
87
102
|
* @throws Error if no paused run exists
|
|
88
103
|
* @throws Error if called with team mode (teams don't support HITL)
|
|
89
104
|
*/
|
|
90
105
|
continueRun(tools: ToolCall[], options?: {
|
|
91
106
|
headers?: Record<string, string>;
|
|
107
|
+
params?: Record<string, string>;
|
|
92
108
|
}): Promise<void>;
|
|
93
109
|
/**
|
|
94
110
|
* Check endpoint status
|
|
95
111
|
*/
|
|
96
|
-
checkStatus(
|
|
112
|
+
checkStatus(options?: {
|
|
113
|
+
params?: Record<string, string>;
|
|
114
|
+
}): Promise<boolean>;
|
|
97
115
|
/**
|
|
98
116
|
* Fetch agents from endpoint
|
|
99
117
|
*/
|
|
100
|
-
fetchAgents(
|
|
118
|
+
fetchAgents(options?: {
|
|
119
|
+
params?: Record<string, string>;
|
|
120
|
+
}): Promise<AgentDetails[]>;
|
|
101
121
|
/**
|
|
102
122
|
* Fetch teams from endpoint
|
|
103
123
|
*/
|
|
104
|
-
fetchTeams(
|
|
124
|
+
fetchTeams(options?: {
|
|
125
|
+
params?: Record<string, string>;
|
|
126
|
+
}): Promise<TeamDetails[]>;
|
|
105
127
|
/**
|
|
106
128
|
* Initialize client (check status and fetch agents/teams)
|
|
107
129
|
* Automatically selects the first available agent or team if none is configured
|
|
108
130
|
*/
|
|
109
|
-
initialize(
|
|
131
|
+
initialize(options?: {
|
|
132
|
+
params?: Record<string, string>;
|
|
133
|
+
}): Promise<{
|
|
110
134
|
agents: AgentDetails[];
|
|
111
135
|
teams: TeamDetails[];
|
|
112
136
|
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
13
13
|
private eventProcessor;
|
|
14
14
|
private state;
|
|
15
15
|
private pendingUISpecs;
|
|
16
|
+
private runCompletedSuccessfully;
|
|
16
17
|
constructor(config: AgnoClientConfig);
|
|
17
18
|
/**
|
|
18
19
|
* Get current messages
|
|
@@ -39,6 +40,7 @@ declare class AgnoClient extends EventEmitter {
|
|
|
39
40
|
*/
|
|
40
41
|
sendMessage(message: string | FormData, options?: {
|
|
41
42
|
headers?: Record<string, string>;
|
|
43
|
+
params?: Record<string, string>;
|
|
42
44
|
}): Promise<void>;
|
|
43
45
|
/**
|
|
44
46
|
* Handle streaming chunk
|
|
@@ -48,18 +50,31 @@ declare class AgnoClient extends EventEmitter {
|
|
|
48
50
|
* Handle error
|
|
49
51
|
*/
|
|
50
52
|
private handleError;
|
|
53
|
+
/**
|
|
54
|
+
* Refresh messages from the session API after run completion.
|
|
55
|
+
* Replaces streamed messages with authoritative session data.
|
|
56
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
private refreshSessionMessages;
|
|
51
60
|
/**
|
|
52
61
|
* Load a session
|
|
53
62
|
*/
|
|
54
|
-
loadSession(sessionId: string
|
|
63
|
+
loadSession(sessionId: string, options?: {
|
|
64
|
+
params?: Record<string, string>;
|
|
65
|
+
}): Promise<ChatMessage[]>;
|
|
55
66
|
/**
|
|
56
67
|
* Fetch all sessions
|
|
57
68
|
*/
|
|
58
|
-
fetchSessions(
|
|
69
|
+
fetchSessions(options?: {
|
|
70
|
+
params?: Record<string, string>;
|
|
71
|
+
}): Promise<SessionEntry[]>;
|
|
59
72
|
/**
|
|
60
73
|
* Delete a session
|
|
61
74
|
*/
|
|
62
|
-
deleteSession(sessionId: string
|
|
75
|
+
deleteSession(sessionId: string, options?: {
|
|
76
|
+
params?: Record<string, string>;
|
|
77
|
+
}): Promise<void>;
|
|
63
78
|
/**
|
|
64
79
|
* Add tool calls to the last message
|
|
65
80
|
* Used by frontend execution to add tool calls that were executed locally
|
|
@@ -83,30 +98,39 @@ declare class AgnoClient extends EventEmitter {
|
|
|
83
98
|
* Teams do not support the continue endpoint.
|
|
84
99
|
*
|
|
85
100
|
* @param tools - Array of tool calls with execution results
|
|
86
|
-
* @param options - Optional request headers
|
|
101
|
+
* @param options - Optional request headers and query parameters
|
|
87
102
|
* @throws Error if no paused run exists
|
|
88
103
|
* @throws Error if called with team mode (teams don't support HITL)
|
|
89
104
|
*/
|
|
90
105
|
continueRun(tools: ToolCall[], options?: {
|
|
91
106
|
headers?: Record<string, string>;
|
|
107
|
+
params?: Record<string, string>;
|
|
92
108
|
}): Promise<void>;
|
|
93
109
|
/**
|
|
94
110
|
* Check endpoint status
|
|
95
111
|
*/
|
|
96
|
-
checkStatus(
|
|
112
|
+
checkStatus(options?: {
|
|
113
|
+
params?: Record<string, string>;
|
|
114
|
+
}): Promise<boolean>;
|
|
97
115
|
/**
|
|
98
116
|
* Fetch agents from endpoint
|
|
99
117
|
*/
|
|
100
|
-
fetchAgents(
|
|
118
|
+
fetchAgents(options?: {
|
|
119
|
+
params?: Record<string, string>;
|
|
120
|
+
}): Promise<AgentDetails[]>;
|
|
101
121
|
/**
|
|
102
122
|
* Fetch teams from endpoint
|
|
103
123
|
*/
|
|
104
|
-
fetchTeams(
|
|
124
|
+
fetchTeams(options?: {
|
|
125
|
+
params?: Record<string, string>;
|
|
126
|
+
}): Promise<TeamDetails[]>;
|
|
105
127
|
/**
|
|
106
128
|
* Initialize client (check status and fetch agents/teams)
|
|
107
129
|
* Automatically selects the first available agent or team if none is configured
|
|
108
130
|
*/
|
|
109
|
-
initialize(
|
|
131
|
+
initialize(options?: {
|
|
132
|
+
params?: Record<string, string>;
|
|
133
|
+
}): Promise<{
|
|
110
134
|
agents: AgentDetails[];
|
|
111
135
|
teams: TeamDetails[];
|
|
112
136
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -250,6 +250,18 @@ var ConfigManager = class {
|
|
|
250
250
|
setHeaders(headers) {
|
|
251
251
|
this.updateField("headers", headers);
|
|
252
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Get global query parameters
|
|
255
|
+
*/
|
|
256
|
+
getParams() {
|
|
257
|
+
return this.config.params;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Set global query parameters
|
|
261
|
+
*/
|
|
262
|
+
setParams(params) {
|
|
263
|
+
this.updateField("params", params);
|
|
264
|
+
}
|
|
253
265
|
/**
|
|
254
266
|
* Get current entity ID (agent or team based on mode)
|
|
255
267
|
*/
|
|
@@ -297,6 +309,26 @@ var ConfigManager = class {
|
|
|
297
309
|
}
|
|
298
310
|
return headers;
|
|
299
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Build query string by merging global params and per-request params.
|
|
314
|
+
* Merge order (lowest to highest precedence):
|
|
315
|
+
* 1. Global params from config
|
|
316
|
+
* 2. Per-request params (overrides global)
|
|
317
|
+
*
|
|
318
|
+
* @param perRequestParams - Optional query parameters for this specific request
|
|
319
|
+
* @returns URLSearchParams object ready to append to URLs
|
|
320
|
+
*/
|
|
321
|
+
buildQueryString(perRequestParams) {
|
|
322
|
+
const params = {};
|
|
323
|
+
const globalParams = this.getParams();
|
|
324
|
+
if (globalParams) {
|
|
325
|
+
Object.assign(params, globalParams);
|
|
326
|
+
}
|
|
327
|
+
if (perRequestParams) {
|
|
328
|
+
Object.assign(params, perRequestParams);
|
|
329
|
+
}
|
|
330
|
+
return new URLSearchParams(params);
|
|
331
|
+
}
|
|
300
332
|
};
|
|
301
333
|
|
|
302
334
|
// src/managers/session-manager.ts
|
|
@@ -304,11 +336,16 @@ var SessionManager = class {
|
|
|
304
336
|
/**
|
|
305
337
|
* Fetch all sessions for an entity
|
|
306
338
|
*/
|
|
307
|
-
async fetchSessions(endpoint, entityType, entityId, dbId, headers) {
|
|
339
|
+
async fetchSessions(endpoint, entityType, entityId, dbId, headers, params) {
|
|
308
340
|
const url = new URL(`${endpoint}/sessions`);
|
|
309
341
|
url.searchParams.set("type", entityType);
|
|
310
342
|
url.searchParams.set("component_id", entityId);
|
|
311
343
|
url.searchParams.set("db_id", dbId);
|
|
344
|
+
if (params) {
|
|
345
|
+
params.forEach((value, key) => {
|
|
346
|
+
url.searchParams.set(key, value);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
312
349
|
const response = await fetch(url.toString(), { headers });
|
|
313
350
|
if (!response.ok) {
|
|
314
351
|
if (response.status === 404) {
|
|
@@ -323,12 +360,20 @@ var SessionManager = class {
|
|
|
323
360
|
* Fetch a specific session's runs
|
|
324
361
|
* Returns an array of RunSchema directly (not wrapped in { data, meta })
|
|
325
362
|
*/
|
|
326
|
-
async fetchSession(endpoint, entityType, sessionId, dbId, headers) {
|
|
363
|
+
async fetchSession(endpoint, entityType, sessionId, dbId, headers, userId, params) {
|
|
327
364
|
const url = new URL(`${endpoint}/sessions/${sessionId}/runs`);
|
|
328
365
|
url.searchParams.set("type", entityType);
|
|
329
366
|
if (dbId) {
|
|
330
367
|
url.searchParams.set("db_id", dbId);
|
|
331
368
|
}
|
|
369
|
+
if (userId) {
|
|
370
|
+
url.searchParams.set("user_id", userId);
|
|
371
|
+
}
|
|
372
|
+
if (params) {
|
|
373
|
+
params.forEach((value, key) => {
|
|
374
|
+
url.searchParams.set(key, value);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
332
377
|
const response = await fetch(url.toString(), { headers });
|
|
333
378
|
if (!response.ok) {
|
|
334
379
|
throw new Error(`Failed to fetch session: ${response.statusText}`);
|
|
@@ -338,11 +383,16 @@ var SessionManager = class {
|
|
|
338
383
|
/**
|
|
339
384
|
* Delete a session
|
|
340
385
|
*/
|
|
341
|
-
async deleteSession(endpoint, sessionId, dbId, headers) {
|
|
386
|
+
async deleteSession(endpoint, sessionId, dbId, headers, params) {
|
|
342
387
|
const url = new URL(`${endpoint}/sessions/${sessionId}`);
|
|
343
388
|
if (dbId) {
|
|
344
389
|
url.searchParams.set("db_id", dbId);
|
|
345
390
|
}
|
|
391
|
+
if (params) {
|
|
392
|
+
params.forEach((value, key) => {
|
|
393
|
+
url.searchParams.set(key, value);
|
|
394
|
+
});
|
|
395
|
+
}
|
|
346
396
|
const response = await fetch(url.toString(), {
|
|
347
397
|
method: "DELETE",
|
|
348
398
|
headers
|
|
@@ -713,6 +763,7 @@ async function streamResponse(options) {
|
|
|
713
763
|
const {
|
|
714
764
|
apiUrl,
|
|
715
765
|
headers = {},
|
|
766
|
+
params,
|
|
716
767
|
requestBody,
|
|
717
768
|
onChunk,
|
|
718
769
|
onError,
|
|
@@ -720,8 +771,9 @@ async function streamResponse(options) {
|
|
|
720
771
|
signal
|
|
721
772
|
} = options;
|
|
722
773
|
let buffer = "";
|
|
774
|
+
const finalUrl = params && params.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
|
|
723
775
|
try {
|
|
724
|
-
const response = await fetch(
|
|
776
|
+
const response = await fetch(finalUrl, {
|
|
725
777
|
method: "POST",
|
|
726
778
|
headers: {
|
|
727
779
|
...!(requestBody instanceof FormData) && {
|
|
@@ -851,9 +903,10 @@ function toSafeISOString(timestamp) {
|
|
|
851
903
|
return new Date(ts).toISOString();
|
|
852
904
|
}
|
|
853
905
|
var AgnoClient = class extends import_eventemitter3.default {
|
|
854
|
-
// toolCallId -> UIComponentSpec
|
|
855
906
|
constructor(config) {
|
|
856
907
|
super();
|
|
908
|
+
// toolCallId -> UIComponentSpec
|
|
909
|
+
this.runCompletedSuccessfully = false;
|
|
857
910
|
this.messageStore = new MessageStore();
|
|
858
911
|
this.configManager = new ConfigManager(config);
|
|
859
912
|
this.sessionManager = new SessionManager();
|
|
@@ -861,6 +914,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
861
914
|
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
862
915
|
this.state = {
|
|
863
916
|
isStreaming: false,
|
|
917
|
+
isRefreshing: false,
|
|
864
918
|
isEndpointActive: false,
|
|
865
919
|
agents: [],
|
|
866
920
|
teams: [],
|
|
@@ -912,6 +966,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
912
966
|
if (this.state.isStreaming) {
|
|
913
967
|
throw new Error("Already streaming a message");
|
|
914
968
|
}
|
|
969
|
+
this.runCompletedSuccessfully = false;
|
|
915
970
|
const runUrl = this.configManager.getRunUrl();
|
|
916
971
|
if (!runUrl) {
|
|
917
972
|
throw new Error("No agent or team selected");
|
|
@@ -954,9 +1009,11 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
954
1009
|
formData.append("user_id", userId);
|
|
955
1010
|
}
|
|
956
1011
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1012
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
957
1013
|
await streamResponse({
|
|
958
1014
|
apiUrl: runUrl,
|
|
959
1015
|
headers,
|
|
1016
|
+
params,
|
|
960
1017
|
requestBody: formData,
|
|
961
1018
|
onChunk: (chunk) => {
|
|
962
1019
|
this.handleChunk(chunk, newSessionId, formData.get("message"));
|
|
@@ -970,11 +1027,15 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
970
1027
|
onError: (error) => {
|
|
971
1028
|
this.handleError(error, newSessionId);
|
|
972
1029
|
},
|
|
973
|
-
onComplete: () => {
|
|
1030
|
+
onComplete: async () => {
|
|
974
1031
|
this.state.isStreaming = false;
|
|
975
1032
|
this.emit("stream:end");
|
|
976
1033
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
977
1034
|
this.emit("state:change", this.getState());
|
|
1035
|
+
if (this.runCompletedSuccessfully) {
|
|
1036
|
+
this.runCompletedSuccessfully = false;
|
|
1037
|
+
await this.refreshSessionMessages();
|
|
1038
|
+
}
|
|
978
1039
|
}
|
|
979
1040
|
});
|
|
980
1041
|
} catch (error) {
|
|
@@ -1038,6 +1099,9 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1038
1099
|
return updated || lastMessage;
|
|
1039
1100
|
});
|
|
1040
1101
|
this.applyPendingUISpecs();
|
|
1102
|
+
if (event === import_agno_types2.RunEvent.RunCompleted || event === import_agno_types2.RunEvent.TeamRunCompleted) {
|
|
1103
|
+
this.runCompletedSuccessfully = true;
|
|
1104
|
+
}
|
|
1041
1105
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1042
1106
|
}
|
|
1043
1107
|
/**
|
|
@@ -1059,22 +1123,92 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1059
1123
|
this.emit("stream:end");
|
|
1060
1124
|
this.emit("state:change", this.getState());
|
|
1061
1125
|
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Refresh messages from the session API after run completion.
|
|
1128
|
+
* Replaces streamed messages with authoritative session data.
|
|
1129
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
1130
|
+
* @private
|
|
1131
|
+
*/
|
|
1132
|
+
async refreshSessionMessages() {
|
|
1133
|
+
const sessionId = this.configManager.getSessionId();
|
|
1134
|
+
if (!sessionId) {
|
|
1135
|
+
Logger.debug("[AgnoClient] Cannot refresh: no session ID");
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
this.state.isRefreshing = true;
|
|
1139
|
+
this.emit("state:change", this.getState());
|
|
1140
|
+
try {
|
|
1141
|
+
const existingUIComponents = /* @__PURE__ */ new Map();
|
|
1142
|
+
for (const message of this.messageStore.getMessages()) {
|
|
1143
|
+
if (message.tool_calls) {
|
|
1144
|
+
for (const toolCall of message.tool_calls) {
|
|
1145
|
+
if (toolCall.ui_component) {
|
|
1146
|
+
existingUIComponents.set(toolCall.tool_call_id, toolCall.ui_component);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
const config = this.configManager.getConfig();
|
|
1152
|
+
const entityType = this.configManager.getMode();
|
|
1153
|
+
const dbId = this.configManager.getDbId() || "";
|
|
1154
|
+
const userId = this.configManager.getUserId();
|
|
1155
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1156
|
+
const params = this.configManager.buildQueryString();
|
|
1157
|
+
const response = await this.sessionManager.fetchSession(
|
|
1158
|
+
config.endpoint,
|
|
1159
|
+
entityType,
|
|
1160
|
+
sessionId,
|
|
1161
|
+
dbId,
|
|
1162
|
+
headers,
|
|
1163
|
+
userId,
|
|
1164
|
+
params
|
|
1165
|
+
);
|
|
1166
|
+
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1167
|
+
if (existingUIComponents.size > 0) {
|
|
1168
|
+
for (const message of messages) {
|
|
1169
|
+
if (message.tool_calls) {
|
|
1170
|
+
for (let i = 0; i < message.tool_calls.length; i++) {
|
|
1171
|
+
const toolCall = message.tool_calls[i];
|
|
1172
|
+
const uiComponent = existingUIComponents.get(toolCall.tool_call_id);
|
|
1173
|
+
if (uiComponent) {
|
|
1174
|
+
message.tool_calls[i].ui_component = uiComponent;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
this.messageStore.setMessages(messages);
|
|
1181
|
+
Logger.debug("[AgnoClient] Session refreshed:", `${messages.length} messages`);
|
|
1182
|
+
this.emit("message:refreshed", messages);
|
|
1183
|
+
this.emit("message:update", messages);
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
Logger.error("[AgnoClient] Failed to refresh session:", error);
|
|
1186
|
+
this.emit("message:error", `Session refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1187
|
+
} finally {
|
|
1188
|
+
this.state.isRefreshing = false;
|
|
1189
|
+
this.emit("state:change", this.getState());
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1062
1192
|
/**
|
|
1063
1193
|
* Load a session
|
|
1064
1194
|
*/
|
|
1065
|
-
async loadSession(sessionId) {
|
|
1195
|
+
async loadSession(sessionId, options) {
|
|
1066
1196
|
Logger.debug("[AgnoClient] loadSession called with sessionId:", sessionId);
|
|
1067
1197
|
const config = this.configManager.getConfig();
|
|
1068
1198
|
const entityType = this.configManager.getMode();
|
|
1069
1199
|
const dbId = this.configManager.getDbId() || "";
|
|
1070
|
-
|
|
1200
|
+
const userId = this.configManager.getUserId();
|
|
1201
|
+
Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId, userId });
|
|
1071
1202
|
const headers = this.configManager.buildRequestHeaders();
|
|
1203
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1072
1204
|
const response = await this.sessionManager.fetchSession(
|
|
1073
1205
|
config.endpoint,
|
|
1074
1206
|
entityType,
|
|
1075
1207
|
sessionId,
|
|
1076
1208
|
dbId,
|
|
1077
|
-
headers
|
|
1209
|
+
headers,
|
|
1210
|
+
userId,
|
|
1211
|
+
params
|
|
1078
1212
|
);
|
|
1079
1213
|
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1080
1214
|
Logger.debug("[AgnoClient] Setting messages to store:", `${messages.length} messages`);
|
|
@@ -1090,7 +1224,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1090
1224
|
/**
|
|
1091
1225
|
* Fetch all sessions
|
|
1092
1226
|
*/
|
|
1093
|
-
async fetchSessions() {
|
|
1227
|
+
async fetchSessions(options) {
|
|
1094
1228
|
const config = this.configManager.getConfig();
|
|
1095
1229
|
const entityType = this.configManager.getMode();
|
|
1096
1230
|
const entityId = this.configManager.getCurrentEntityId();
|
|
@@ -1099,12 +1233,14 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1099
1233
|
throw new Error("Entity ID must be configured");
|
|
1100
1234
|
}
|
|
1101
1235
|
const headers = this.configManager.buildRequestHeaders();
|
|
1236
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1102
1237
|
const sessions = await this.sessionManager.fetchSessions(
|
|
1103
1238
|
config.endpoint,
|
|
1104
1239
|
entityType,
|
|
1105
1240
|
entityId,
|
|
1106
1241
|
dbId,
|
|
1107
|
-
headers
|
|
1242
|
+
headers,
|
|
1243
|
+
params
|
|
1108
1244
|
);
|
|
1109
1245
|
this.state.sessions = sessions;
|
|
1110
1246
|
this.emit("state:change", this.getState());
|
|
@@ -1113,15 +1249,17 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1113
1249
|
/**
|
|
1114
1250
|
* Delete a session
|
|
1115
1251
|
*/
|
|
1116
|
-
async deleteSession(sessionId) {
|
|
1252
|
+
async deleteSession(sessionId, options) {
|
|
1117
1253
|
const config = this.configManager.getConfig();
|
|
1118
1254
|
const dbId = this.configManager.getDbId() || "";
|
|
1119
1255
|
const headers = this.configManager.buildRequestHeaders();
|
|
1256
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1120
1257
|
await this.sessionManager.deleteSession(
|
|
1121
1258
|
config.endpoint,
|
|
1122
1259
|
sessionId,
|
|
1123
1260
|
dbId,
|
|
1124
|
-
headers
|
|
1261
|
+
headers,
|
|
1262
|
+
params
|
|
1125
1263
|
);
|
|
1126
1264
|
this.state.sessions = this.state.sessions.filter(
|
|
1127
1265
|
(s) => s.session_id !== sessionId
|
|
@@ -1235,7 +1373,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1235
1373
|
* Teams do not support the continue endpoint.
|
|
1236
1374
|
*
|
|
1237
1375
|
* @param tools - Array of tool calls with execution results
|
|
1238
|
-
* @param options - Optional request headers
|
|
1376
|
+
* @param options - Optional request headers and query parameters
|
|
1239
1377
|
* @throws Error if no paused run exists
|
|
1240
1378
|
* @throws Error if called with team mode (teams don't support HITL)
|
|
1241
1379
|
*/
|
|
@@ -1273,10 +1411,12 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1273
1411
|
formData.append("user_id", userId);
|
|
1274
1412
|
}
|
|
1275
1413
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1414
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1276
1415
|
try {
|
|
1277
1416
|
await streamResponse({
|
|
1278
1417
|
apiUrl: continueUrl,
|
|
1279
1418
|
headers,
|
|
1419
|
+
params,
|
|
1280
1420
|
requestBody: formData,
|
|
1281
1421
|
onChunk: (chunk) => {
|
|
1282
1422
|
this.handleChunk(chunk, currentSessionId, "");
|
|
@@ -1284,13 +1424,17 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1284
1424
|
onError: (error) => {
|
|
1285
1425
|
this.handleError(error, currentSessionId);
|
|
1286
1426
|
},
|
|
1287
|
-
onComplete: () => {
|
|
1427
|
+
onComplete: async () => {
|
|
1288
1428
|
this.state.isStreaming = false;
|
|
1289
1429
|
this.state.pausedRunId = void 0;
|
|
1290
1430
|
this.state.toolsAwaitingExecution = void 0;
|
|
1291
1431
|
this.emit("stream:end");
|
|
1292
1432
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
1293
1433
|
this.emit("state:change", this.getState());
|
|
1434
|
+
if (this.runCompletedSuccessfully) {
|
|
1435
|
+
this.runCompletedSuccessfully = false;
|
|
1436
|
+
await this.refreshSessionMessages();
|
|
1437
|
+
}
|
|
1294
1438
|
}
|
|
1295
1439
|
});
|
|
1296
1440
|
} catch (error) {
|
|
@@ -1303,10 +1447,17 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1303
1447
|
/**
|
|
1304
1448
|
* Check endpoint status
|
|
1305
1449
|
*/
|
|
1306
|
-
async checkStatus() {
|
|
1450
|
+
async checkStatus(options) {
|
|
1307
1451
|
try {
|
|
1308
1452
|
const headers = this.configManager.buildRequestHeaders();
|
|
1309
|
-
const
|
|
1453
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1454
|
+
const url = new URL(`${this.configManager.getEndpoint()}/health`);
|
|
1455
|
+
if (params.toString()) {
|
|
1456
|
+
params.forEach((value, key) => {
|
|
1457
|
+
url.searchParams.set(key, value);
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
const response = await fetch(url.toString(), { headers });
|
|
1310
1461
|
const isActive = response.ok;
|
|
1311
1462
|
this.state.isEndpointActive = isActive;
|
|
1312
1463
|
this.emit("state:change", this.getState());
|
|
@@ -1320,9 +1471,16 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1320
1471
|
/**
|
|
1321
1472
|
* Fetch agents from endpoint
|
|
1322
1473
|
*/
|
|
1323
|
-
async fetchAgents() {
|
|
1474
|
+
async fetchAgents(options) {
|
|
1324
1475
|
const headers = this.configManager.buildRequestHeaders();
|
|
1325
|
-
const
|
|
1476
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1477
|
+
const url = new URL(`${this.configManager.getEndpoint()}/agents`);
|
|
1478
|
+
if (params.toString()) {
|
|
1479
|
+
params.forEach((value, key) => {
|
|
1480
|
+
url.searchParams.set(key, value);
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
const response = await fetch(url.toString(), { headers });
|
|
1326
1484
|
if (!response.ok) {
|
|
1327
1485
|
throw new Error("Failed to fetch agents");
|
|
1328
1486
|
}
|
|
@@ -1334,9 +1492,16 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1334
1492
|
/**
|
|
1335
1493
|
* Fetch teams from endpoint
|
|
1336
1494
|
*/
|
|
1337
|
-
async fetchTeams() {
|
|
1495
|
+
async fetchTeams(options) {
|
|
1338
1496
|
const headers = this.configManager.buildRequestHeaders();
|
|
1339
|
-
const
|
|
1497
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1498
|
+
const url = new URL(`${this.configManager.getEndpoint()}/teams`);
|
|
1499
|
+
if (params.toString()) {
|
|
1500
|
+
params.forEach((value, key) => {
|
|
1501
|
+
url.searchParams.set(key, value);
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
const response = await fetch(url.toString(), { headers });
|
|
1340
1505
|
if (!response.ok) {
|
|
1341
1506
|
throw new Error("Failed to fetch teams");
|
|
1342
1507
|
}
|
|
@@ -1349,14 +1514,14 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1349
1514
|
* Initialize client (check status and fetch agents/teams)
|
|
1350
1515
|
* Automatically selects the first available agent or team if none is configured
|
|
1351
1516
|
*/
|
|
1352
|
-
async initialize() {
|
|
1353
|
-
const isActive = await this.checkStatus();
|
|
1517
|
+
async initialize(options) {
|
|
1518
|
+
const isActive = await this.checkStatus(options);
|
|
1354
1519
|
if (!isActive) {
|
|
1355
1520
|
return { agents: [], teams: [] };
|
|
1356
1521
|
}
|
|
1357
1522
|
const [agents, teams] = await Promise.all([
|
|
1358
|
-
this.fetchAgents(),
|
|
1359
|
-
this.fetchTeams()
|
|
1523
|
+
this.fetchAgents(options),
|
|
1524
|
+
this.fetchTeams(options)
|
|
1360
1525
|
]);
|
|
1361
1526
|
const currentConfig = this.configManager.getConfig();
|
|
1362
1527
|
const hasAgentConfigured = currentConfig.agentId;
|
package/dist/index.mjs
CHANGED
|
@@ -212,6 +212,18 @@ var ConfigManager = class {
|
|
|
212
212
|
setHeaders(headers) {
|
|
213
213
|
this.updateField("headers", headers);
|
|
214
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Get global query parameters
|
|
217
|
+
*/
|
|
218
|
+
getParams() {
|
|
219
|
+
return this.config.params;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Set global query parameters
|
|
223
|
+
*/
|
|
224
|
+
setParams(params) {
|
|
225
|
+
this.updateField("params", params);
|
|
226
|
+
}
|
|
215
227
|
/**
|
|
216
228
|
* Get current entity ID (agent or team based on mode)
|
|
217
229
|
*/
|
|
@@ -259,6 +271,26 @@ var ConfigManager = class {
|
|
|
259
271
|
}
|
|
260
272
|
return headers;
|
|
261
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* Build query string by merging global params and per-request params.
|
|
276
|
+
* Merge order (lowest to highest precedence):
|
|
277
|
+
* 1. Global params from config
|
|
278
|
+
* 2. Per-request params (overrides global)
|
|
279
|
+
*
|
|
280
|
+
* @param perRequestParams - Optional query parameters for this specific request
|
|
281
|
+
* @returns URLSearchParams object ready to append to URLs
|
|
282
|
+
*/
|
|
283
|
+
buildQueryString(perRequestParams) {
|
|
284
|
+
const params = {};
|
|
285
|
+
const globalParams = this.getParams();
|
|
286
|
+
if (globalParams) {
|
|
287
|
+
Object.assign(params, globalParams);
|
|
288
|
+
}
|
|
289
|
+
if (perRequestParams) {
|
|
290
|
+
Object.assign(params, perRequestParams);
|
|
291
|
+
}
|
|
292
|
+
return new URLSearchParams(params);
|
|
293
|
+
}
|
|
262
294
|
};
|
|
263
295
|
|
|
264
296
|
// src/managers/session-manager.ts
|
|
@@ -266,11 +298,16 @@ var SessionManager = class {
|
|
|
266
298
|
/**
|
|
267
299
|
* Fetch all sessions for an entity
|
|
268
300
|
*/
|
|
269
|
-
async fetchSessions(endpoint, entityType, entityId, dbId, headers) {
|
|
301
|
+
async fetchSessions(endpoint, entityType, entityId, dbId, headers, params) {
|
|
270
302
|
const url = new URL(`${endpoint}/sessions`);
|
|
271
303
|
url.searchParams.set("type", entityType);
|
|
272
304
|
url.searchParams.set("component_id", entityId);
|
|
273
305
|
url.searchParams.set("db_id", dbId);
|
|
306
|
+
if (params) {
|
|
307
|
+
params.forEach((value, key) => {
|
|
308
|
+
url.searchParams.set(key, value);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
274
311
|
const response = await fetch(url.toString(), { headers });
|
|
275
312
|
if (!response.ok) {
|
|
276
313
|
if (response.status === 404) {
|
|
@@ -285,12 +322,20 @@ var SessionManager = class {
|
|
|
285
322
|
* Fetch a specific session's runs
|
|
286
323
|
* Returns an array of RunSchema directly (not wrapped in { data, meta })
|
|
287
324
|
*/
|
|
288
|
-
async fetchSession(endpoint, entityType, sessionId, dbId, headers) {
|
|
325
|
+
async fetchSession(endpoint, entityType, sessionId, dbId, headers, userId, params) {
|
|
289
326
|
const url = new URL(`${endpoint}/sessions/${sessionId}/runs`);
|
|
290
327
|
url.searchParams.set("type", entityType);
|
|
291
328
|
if (dbId) {
|
|
292
329
|
url.searchParams.set("db_id", dbId);
|
|
293
330
|
}
|
|
331
|
+
if (userId) {
|
|
332
|
+
url.searchParams.set("user_id", userId);
|
|
333
|
+
}
|
|
334
|
+
if (params) {
|
|
335
|
+
params.forEach((value, key) => {
|
|
336
|
+
url.searchParams.set(key, value);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
294
339
|
const response = await fetch(url.toString(), { headers });
|
|
295
340
|
if (!response.ok) {
|
|
296
341
|
throw new Error(`Failed to fetch session: ${response.statusText}`);
|
|
@@ -300,11 +345,16 @@ var SessionManager = class {
|
|
|
300
345
|
/**
|
|
301
346
|
* Delete a session
|
|
302
347
|
*/
|
|
303
|
-
async deleteSession(endpoint, sessionId, dbId, headers) {
|
|
348
|
+
async deleteSession(endpoint, sessionId, dbId, headers, params) {
|
|
304
349
|
const url = new URL(`${endpoint}/sessions/${sessionId}`);
|
|
305
350
|
if (dbId) {
|
|
306
351
|
url.searchParams.set("db_id", dbId);
|
|
307
352
|
}
|
|
353
|
+
if (params) {
|
|
354
|
+
params.forEach((value, key) => {
|
|
355
|
+
url.searchParams.set(key, value);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
308
358
|
const response = await fetch(url.toString(), {
|
|
309
359
|
method: "DELETE",
|
|
310
360
|
headers
|
|
@@ -675,6 +725,7 @@ async function streamResponse(options) {
|
|
|
675
725
|
const {
|
|
676
726
|
apiUrl,
|
|
677
727
|
headers = {},
|
|
728
|
+
params,
|
|
678
729
|
requestBody,
|
|
679
730
|
onChunk,
|
|
680
731
|
onError,
|
|
@@ -682,8 +733,9 @@ async function streamResponse(options) {
|
|
|
682
733
|
signal
|
|
683
734
|
} = options;
|
|
684
735
|
let buffer = "";
|
|
736
|
+
const finalUrl = params && params.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
|
|
685
737
|
try {
|
|
686
|
-
const response = await fetch(
|
|
738
|
+
const response = await fetch(finalUrl, {
|
|
687
739
|
method: "POST",
|
|
688
740
|
headers: {
|
|
689
741
|
...!(requestBody instanceof FormData) && {
|
|
@@ -813,9 +865,10 @@ function toSafeISOString(timestamp) {
|
|
|
813
865
|
return new Date(ts).toISOString();
|
|
814
866
|
}
|
|
815
867
|
var AgnoClient = class extends EventEmitter {
|
|
816
|
-
// toolCallId -> UIComponentSpec
|
|
817
868
|
constructor(config) {
|
|
818
869
|
super();
|
|
870
|
+
// toolCallId -> UIComponentSpec
|
|
871
|
+
this.runCompletedSuccessfully = false;
|
|
819
872
|
this.messageStore = new MessageStore();
|
|
820
873
|
this.configManager = new ConfigManager(config);
|
|
821
874
|
this.sessionManager = new SessionManager();
|
|
@@ -823,6 +876,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
823
876
|
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
824
877
|
this.state = {
|
|
825
878
|
isStreaming: false,
|
|
879
|
+
isRefreshing: false,
|
|
826
880
|
isEndpointActive: false,
|
|
827
881
|
agents: [],
|
|
828
882
|
teams: [],
|
|
@@ -874,6 +928,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
874
928
|
if (this.state.isStreaming) {
|
|
875
929
|
throw new Error("Already streaming a message");
|
|
876
930
|
}
|
|
931
|
+
this.runCompletedSuccessfully = false;
|
|
877
932
|
const runUrl = this.configManager.getRunUrl();
|
|
878
933
|
if (!runUrl) {
|
|
879
934
|
throw new Error("No agent or team selected");
|
|
@@ -916,9 +971,11 @@ var AgnoClient = class extends EventEmitter {
|
|
|
916
971
|
formData.append("user_id", userId);
|
|
917
972
|
}
|
|
918
973
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
974
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
919
975
|
await streamResponse({
|
|
920
976
|
apiUrl: runUrl,
|
|
921
977
|
headers,
|
|
978
|
+
params,
|
|
922
979
|
requestBody: formData,
|
|
923
980
|
onChunk: (chunk) => {
|
|
924
981
|
this.handleChunk(chunk, newSessionId, formData.get("message"));
|
|
@@ -932,11 +989,15 @@ var AgnoClient = class extends EventEmitter {
|
|
|
932
989
|
onError: (error) => {
|
|
933
990
|
this.handleError(error, newSessionId);
|
|
934
991
|
},
|
|
935
|
-
onComplete: () => {
|
|
992
|
+
onComplete: async () => {
|
|
936
993
|
this.state.isStreaming = false;
|
|
937
994
|
this.emit("stream:end");
|
|
938
995
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
939
996
|
this.emit("state:change", this.getState());
|
|
997
|
+
if (this.runCompletedSuccessfully) {
|
|
998
|
+
this.runCompletedSuccessfully = false;
|
|
999
|
+
await this.refreshSessionMessages();
|
|
1000
|
+
}
|
|
940
1001
|
}
|
|
941
1002
|
});
|
|
942
1003
|
} catch (error) {
|
|
@@ -1000,6 +1061,9 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1000
1061
|
return updated || lastMessage;
|
|
1001
1062
|
});
|
|
1002
1063
|
this.applyPendingUISpecs();
|
|
1064
|
+
if (event === RunEvent.RunCompleted || event === RunEvent.TeamRunCompleted) {
|
|
1065
|
+
this.runCompletedSuccessfully = true;
|
|
1066
|
+
}
|
|
1003
1067
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1004
1068
|
}
|
|
1005
1069
|
/**
|
|
@@ -1021,22 +1085,92 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1021
1085
|
this.emit("stream:end");
|
|
1022
1086
|
this.emit("state:change", this.getState());
|
|
1023
1087
|
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Refresh messages from the session API after run completion.
|
|
1090
|
+
* Replaces streamed messages with authoritative session data.
|
|
1091
|
+
* Preserves client-side properties like ui_component that aren't stored on the server.
|
|
1092
|
+
* @private
|
|
1093
|
+
*/
|
|
1094
|
+
async refreshSessionMessages() {
|
|
1095
|
+
const sessionId = this.configManager.getSessionId();
|
|
1096
|
+
if (!sessionId) {
|
|
1097
|
+
Logger.debug("[AgnoClient] Cannot refresh: no session ID");
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
this.state.isRefreshing = true;
|
|
1101
|
+
this.emit("state:change", this.getState());
|
|
1102
|
+
try {
|
|
1103
|
+
const existingUIComponents = /* @__PURE__ */ new Map();
|
|
1104
|
+
for (const message of this.messageStore.getMessages()) {
|
|
1105
|
+
if (message.tool_calls) {
|
|
1106
|
+
for (const toolCall of message.tool_calls) {
|
|
1107
|
+
if (toolCall.ui_component) {
|
|
1108
|
+
existingUIComponents.set(toolCall.tool_call_id, toolCall.ui_component);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
const config = this.configManager.getConfig();
|
|
1114
|
+
const entityType = this.configManager.getMode();
|
|
1115
|
+
const dbId = this.configManager.getDbId() || "";
|
|
1116
|
+
const userId = this.configManager.getUserId();
|
|
1117
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1118
|
+
const params = this.configManager.buildQueryString();
|
|
1119
|
+
const response = await this.sessionManager.fetchSession(
|
|
1120
|
+
config.endpoint,
|
|
1121
|
+
entityType,
|
|
1122
|
+
sessionId,
|
|
1123
|
+
dbId,
|
|
1124
|
+
headers,
|
|
1125
|
+
userId,
|
|
1126
|
+
params
|
|
1127
|
+
);
|
|
1128
|
+
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1129
|
+
if (existingUIComponents.size > 0) {
|
|
1130
|
+
for (const message of messages) {
|
|
1131
|
+
if (message.tool_calls) {
|
|
1132
|
+
for (let i = 0; i < message.tool_calls.length; i++) {
|
|
1133
|
+
const toolCall = message.tool_calls[i];
|
|
1134
|
+
const uiComponent = existingUIComponents.get(toolCall.tool_call_id);
|
|
1135
|
+
if (uiComponent) {
|
|
1136
|
+
message.tool_calls[i].ui_component = uiComponent;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
this.messageStore.setMessages(messages);
|
|
1143
|
+
Logger.debug("[AgnoClient] Session refreshed:", `${messages.length} messages`);
|
|
1144
|
+
this.emit("message:refreshed", messages);
|
|
1145
|
+
this.emit("message:update", messages);
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
Logger.error("[AgnoClient] Failed to refresh session:", error);
|
|
1148
|
+
this.emit("message:error", `Session refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1149
|
+
} finally {
|
|
1150
|
+
this.state.isRefreshing = false;
|
|
1151
|
+
this.emit("state:change", this.getState());
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1024
1154
|
/**
|
|
1025
1155
|
* Load a session
|
|
1026
1156
|
*/
|
|
1027
|
-
async loadSession(sessionId) {
|
|
1157
|
+
async loadSession(sessionId, options) {
|
|
1028
1158
|
Logger.debug("[AgnoClient] loadSession called with sessionId:", sessionId);
|
|
1029
1159
|
const config = this.configManager.getConfig();
|
|
1030
1160
|
const entityType = this.configManager.getMode();
|
|
1031
1161
|
const dbId = this.configManager.getDbId() || "";
|
|
1032
|
-
|
|
1162
|
+
const userId = this.configManager.getUserId();
|
|
1163
|
+
Logger.debug("[AgnoClient] Loading session with:", { entityType, dbId, userId });
|
|
1033
1164
|
const headers = this.configManager.buildRequestHeaders();
|
|
1165
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1034
1166
|
const response = await this.sessionManager.fetchSession(
|
|
1035
1167
|
config.endpoint,
|
|
1036
1168
|
entityType,
|
|
1037
1169
|
sessionId,
|
|
1038
1170
|
dbId,
|
|
1039
|
-
headers
|
|
1171
|
+
headers,
|
|
1172
|
+
userId,
|
|
1173
|
+
params
|
|
1040
1174
|
);
|
|
1041
1175
|
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1042
1176
|
Logger.debug("[AgnoClient] Setting messages to store:", `${messages.length} messages`);
|
|
@@ -1052,7 +1186,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1052
1186
|
/**
|
|
1053
1187
|
* Fetch all sessions
|
|
1054
1188
|
*/
|
|
1055
|
-
async fetchSessions() {
|
|
1189
|
+
async fetchSessions(options) {
|
|
1056
1190
|
const config = this.configManager.getConfig();
|
|
1057
1191
|
const entityType = this.configManager.getMode();
|
|
1058
1192
|
const entityId = this.configManager.getCurrentEntityId();
|
|
@@ -1061,12 +1195,14 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1061
1195
|
throw new Error("Entity ID must be configured");
|
|
1062
1196
|
}
|
|
1063
1197
|
const headers = this.configManager.buildRequestHeaders();
|
|
1198
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1064
1199
|
const sessions = await this.sessionManager.fetchSessions(
|
|
1065
1200
|
config.endpoint,
|
|
1066
1201
|
entityType,
|
|
1067
1202
|
entityId,
|
|
1068
1203
|
dbId,
|
|
1069
|
-
headers
|
|
1204
|
+
headers,
|
|
1205
|
+
params
|
|
1070
1206
|
);
|
|
1071
1207
|
this.state.sessions = sessions;
|
|
1072
1208
|
this.emit("state:change", this.getState());
|
|
@@ -1075,15 +1211,17 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1075
1211
|
/**
|
|
1076
1212
|
* Delete a session
|
|
1077
1213
|
*/
|
|
1078
|
-
async deleteSession(sessionId) {
|
|
1214
|
+
async deleteSession(sessionId, options) {
|
|
1079
1215
|
const config = this.configManager.getConfig();
|
|
1080
1216
|
const dbId = this.configManager.getDbId() || "";
|
|
1081
1217
|
const headers = this.configManager.buildRequestHeaders();
|
|
1218
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1082
1219
|
await this.sessionManager.deleteSession(
|
|
1083
1220
|
config.endpoint,
|
|
1084
1221
|
sessionId,
|
|
1085
1222
|
dbId,
|
|
1086
|
-
headers
|
|
1223
|
+
headers,
|
|
1224
|
+
params
|
|
1087
1225
|
);
|
|
1088
1226
|
this.state.sessions = this.state.sessions.filter(
|
|
1089
1227
|
(s) => s.session_id !== sessionId
|
|
@@ -1197,7 +1335,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1197
1335
|
* Teams do not support the continue endpoint.
|
|
1198
1336
|
*
|
|
1199
1337
|
* @param tools - Array of tool calls with execution results
|
|
1200
|
-
* @param options - Optional request headers
|
|
1338
|
+
* @param options - Optional request headers and query parameters
|
|
1201
1339
|
* @throws Error if no paused run exists
|
|
1202
1340
|
* @throws Error if called with team mode (teams don't support HITL)
|
|
1203
1341
|
*/
|
|
@@ -1235,10 +1373,12 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1235
1373
|
formData.append("user_id", userId);
|
|
1236
1374
|
}
|
|
1237
1375
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1376
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1238
1377
|
try {
|
|
1239
1378
|
await streamResponse({
|
|
1240
1379
|
apiUrl: continueUrl,
|
|
1241
1380
|
headers,
|
|
1381
|
+
params,
|
|
1242
1382
|
requestBody: formData,
|
|
1243
1383
|
onChunk: (chunk) => {
|
|
1244
1384
|
this.handleChunk(chunk, currentSessionId, "");
|
|
@@ -1246,13 +1386,17 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1246
1386
|
onError: (error) => {
|
|
1247
1387
|
this.handleError(error, currentSessionId);
|
|
1248
1388
|
},
|
|
1249
|
-
onComplete: () => {
|
|
1389
|
+
onComplete: async () => {
|
|
1250
1390
|
this.state.isStreaming = false;
|
|
1251
1391
|
this.state.pausedRunId = void 0;
|
|
1252
1392
|
this.state.toolsAwaitingExecution = void 0;
|
|
1253
1393
|
this.emit("stream:end");
|
|
1254
1394
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
1255
1395
|
this.emit("state:change", this.getState());
|
|
1396
|
+
if (this.runCompletedSuccessfully) {
|
|
1397
|
+
this.runCompletedSuccessfully = false;
|
|
1398
|
+
await this.refreshSessionMessages();
|
|
1399
|
+
}
|
|
1256
1400
|
}
|
|
1257
1401
|
});
|
|
1258
1402
|
} catch (error) {
|
|
@@ -1265,10 +1409,17 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1265
1409
|
/**
|
|
1266
1410
|
* Check endpoint status
|
|
1267
1411
|
*/
|
|
1268
|
-
async checkStatus() {
|
|
1412
|
+
async checkStatus(options) {
|
|
1269
1413
|
try {
|
|
1270
1414
|
const headers = this.configManager.buildRequestHeaders();
|
|
1271
|
-
const
|
|
1415
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1416
|
+
const url = new URL(`${this.configManager.getEndpoint()}/health`);
|
|
1417
|
+
if (params.toString()) {
|
|
1418
|
+
params.forEach((value, key) => {
|
|
1419
|
+
url.searchParams.set(key, value);
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
const response = await fetch(url.toString(), { headers });
|
|
1272
1423
|
const isActive = response.ok;
|
|
1273
1424
|
this.state.isEndpointActive = isActive;
|
|
1274
1425
|
this.emit("state:change", this.getState());
|
|
@@ -1282,9 +1433,16 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1282
1433
|
/**
|
|
1283
1434
|
* Fetch agents from endpoint
|
|
1284
1435
|
*/
|
|
1285
|
-
async fetchAgents() {
|
|
1436
|
+
async fetchAgents(options) {
|
|
1286
1437
|
const headers = this.configManager.buildRequestHeaders();
|
|
1287
|
-
const
|
|
1438
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1439
|
+
const url = new URL(`${this.configManager.getEndpoint()}/agents`);
|
|
1440
|
+
if (params.toString()) {
|
|
1441
|
+
params.forEach((value, key) => {
|
|
1442
|
+
url.searchParams.set(key, value);
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
const response = await fetch(url.toString(), { headers });
|
|
1288
1446
|
if (!response.ok) {
|
|
1289
1447
|
throw new Error("Failed to fetch agents");
|
|
1290
1448
|
}
|
|
@@ -1296,9 +1454,16 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1296
1454
|
/**
|
|
1297
1455
|
* Fetch teams from endpoint
|
|
1298
1456
|
*/
|
|
1299
|
-
async fetchTeams() {
|
|
1457
|
+
async fetchTeams(options) {
|
|
1300
1458
|
const headers = this.configManager.buildRequestHeaders();
|
|
1301
|
-
const
|
|
1459
|
+
const params = this.configManager.buildQueryString(options?.params);
|
|
1460
|
+
const url = new URL(`${this.configManager.getEndpoint()}/teams`);
|
|
1461
|
+
if (params.toString()) {
|
|
1462
|
+
params.forEach((value, key) => {
|
|
1463
|
+
url.searchParams.set(key, value);
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
const response = await fetch(url.toString(), { headers });
|
|
1302
1467
|
if (!response.ok) {
|
|
1303
1468
|
throw new Error("Failed to fetch teams");
|
|
1304
1469
|
}
|
|
@@ -1311,14 +1476,14 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1311
1476
|
* Initialize client (check status and fetch agents/teams)
|
|
1312
1477
|
* Automatically selects the first available agent or team if none is configured
|
|
1313
1478
|
*/
|
|
1314
|
-
async initialize() {
|
|
1315
|
-
const isActive = await this.checkStatus();
|
|
1479
|
+
async initialize(options) {
|
|
1480
|
+
const isActive = await this.checkStatus(options);
|
|
1316
1481
|
if (!isActive) {
|
|
1317
1482
|
return { agents: [], teams: [] };
|
|
1318
1483
|
}
|
|
1319
1484
|
const [agents, teams] = await Promise.all([
|
|
1320
|
-
this.fetchAgents(),
|
|
1321
|
-
this.fetchTeams()
|
|
1485
|
+
this.fetchAgents(options),
|
|
1486
|
+
this.fetchTeams(options)
|
|
1322
1487
|
]);
|
|
1323
1488
|
const currentConfig = this.configManager.getConfig();
|
|
1324
1489
|
const hasAgentConfigured = currentConfig.agentId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antipopp/agno-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Core client library for Agno agents with streaming support and HITL frontend tool execution",
|
|
5
5
|
"author": "antipopp",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"eventemitter3": "^5.0.1",
|
|
37
|
-
"@antipopp/agno-types": "0.
|
|
37
|
+
"@antipopp/agno-types": "0.9.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"tsup": "^8.0.1",
|