@inferencesh/sdk 0.6.30 → 0.6.47

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 (53) hide show
  1. package/README.md +35 -0
  2. package/dist/agent/actions.js +72 -13
  3. package/dist/agent/api.d.ts +30 -51
  4. package/dist/agent/api.js +129 -154
  5. package/dist/agent/provider.js +18 -1
  6. package/dist/agent/reducer.js +50 -11
  7. package/dist/agent/types.d.ts +34 -1
  8. package/dist/api/agents.d.ts +23 -14
  9. package/dist/api/agents.js +22 -4
  10. package/dist/api/api-keys.d.ts +4 -3
  11. package/dist/api/apps.d.ts +16 -15
  12. package/dist/api/chats.d.ts +14 -9
  13. package/dist/api/chats.js +6 -0
  14. package/dist/api/engines.d.ts +14 -13
  15. package/dist/api/files.d.ts +4 -3
  16. package/dist/api/files.js +2 -2
  17. package/dist/api/flow-runs.d.ts +8 -7
  18. package/dist/api/flows.d.ts +11 -10
  19. package/dist/api/integrations.d.ts +9 -8
  20. package/dist/api/integrations.js +8 -8
  21. package/dist/api/knowledge.d.ts +25 -24
  22. package/dist/api/mcp-servers.d.ts +10 -9
  23. package/dist/api/projects.d.ts +6 -5
  24. package/dist/api/search.d.ts +3 -2
  25. package/dist/api/secrets.d.ts +6 -5
  26. package/dist/api/sessions.d.ts +5 -4
  27. package/dist/api/sessions.js +2 -3
  28. package/dist/api/tasks.d.ts +14 -11
  29. package/dist/api/tasks.js +10 -4
  30. package/dist/api/teams.d.ts +16 -17
  31. package/dist/delta.d.ts +15 -0
  32. package/dist/delta.js +84 -0
  33. package/dist/hook-builder.d.ts +23 -0
  34. package/dist/hook-builder.js +50 -0
  35. package/dist/http/client.d.ts +9 -1
  36. package/dist/http/client.js +12 -3
  37. package/dist/http/response.d.ts +9 -0
  38. package/dist/http/response.js +1 -0
  39. package/dist/http/stream.d.ts +1 -0
  40. package/dist/http/stream.js +8 -3
  41. package/dist/http/streamable.d.ts +3 -1
  42. package/dist/http/streamable.js +10 -1
  43. package/dist/index.d.ts +11 -5
  44. package/dist/index.js +6 -1
  45. package/dist/proxy/index.d.ts +2 -0
  46. package/dist/proxy/index.js +9 -0
  47. package/dist/tool-builder.d.ts +2 -0
  48. package/dist/tool-builder.js +5 -0
  49. package/dist/types.d.ts +1041 -157
  50. package/dist/types.js +230 -30
  51. package/dist/utils.d.ts +13 -0
  52. package/dist/utils.js +43 -3
  53. package/package.json +8 -5
package/README.md CHANGED
@@ -409,6 +409,41 @@ const agent = client.agents.create({
409
409
 
410
410
  `callTool` is an alias for `httpTool`. Run `npx tsx examples/tool-builder.ts` for more schema examples (no API key required).
411
411
 
412
+ ### Lifecycle hooks
413
+
414
+ Use `lifecycleHook()` to attach hooks to agent events. Hooks can call a webhook or delegate to another agent as a task:
415
+
416
+ ```typescript
417
+ import { inference, lifecycleHook, HookEventTurnStart, HookEventToolCall } from '@inferencesh/sdk';
418
+
419
+ const client = inference({ apiKey: 'your-api-key' });
420
+
421
+ const agent = client.agents.create({
422
+ core_app: { ref: 'openrouter/claude-sonnet-4@abc' },
423
+ hooks: [
424
+ lifecycleHook(HookEventTurnStart)
425
+ .webhook('https://example.com/on-turn')
426
+ .timeout(10)
427
+ .build(),
428
+ lifecycleHook(HookEventToolCall)
429
+ .task('my-org/approval-agent')
430
+ .async(true)
431
+ .build(),
432
+ ],
433
+ });
434
+ ```
435
+
436
+ ### Queued messages
437
+
438
+ `sendMessage` automatically queues when the agent is busy processing a previous message. Queued messages appear with a `queued` status until the agent picks them up.
439
+
440
+ To cancel a queued message before it is processed, use `cancelMessage` on the React provider or `chats.cancelMessage` on the API client:
441
+
442
+ ```typescript
443
+ // Via the API client
444
+ await client.chats.cancelMessage(messageId);
445
+ ```
446
+
412
447
  ### File attachments
413
448
 
414
449
  Pass files in `sendMessage` options. `Blob` values are uploaded first; objects with a `uri` (already uploaded via `client.files.upload`) are attached as-is:
@@ -4,10 +4,11 @@
4
4
  * Action creators that handle side effects (API calls, streaming).
5
5
  * These are created once per provider instance with access to dispatch.
6
6
  */
7
- import { ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, ToolTypeClient, } from '../types';
7
+ import { AgentRunStateWorking, AgentRunStateSubmitted, AgentRunStateInputRequired, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, ToolTypeClient, } from '../types';
8
8
  import { isChatBusy } from '../utils';
9
9
  import { StreamableManager } from '../http/streamable';
10
10
  import { PollManager } from '../http/poll';
11
+ import { createLLMDeltaAccumulator } from '../delta';
11
12
  import { isAdHocConfig, extractClientToolHandlers } from './types';
12
13
  import * as api from './api';
13
14
  // =============================================================================
@@ -15,7 +16,7 @@ import * as api from './api';
15
16
  // =============================================================================
16
17
  export function createActions(ctx) {
17
18
  const dispatchedToolInvocations = new Set();
18
- const { client, dispatch, getConfig, getChatId, getClientToolHandlers, getStreamManager, setStreamManager, getStreamEnabled, getPollIntervalMs, callbacks } = ctx;
19
+ const { client, dispatch, getState, getConfig, getChatId, getClientToolHandlers, getStreamManager, setStreamManager, getStreamEnabled, getPollIntervalMs, callbacks } = ctx;
19
20
  let prevChatWasBusy = false;
20
21
  const checkTurnEnd = (chat) => {
21
22
  const busy = isChatBusy(chat);
@@ -34,13 +35,13 @@ export function createActions(ctx) {
34
35
  checkTurnEnd(chat);
35
36
  }
36
37
  };
37
- const updateMessage = (message) => {
38
+ const updateMessage = (message, fields) => {
38
39
  const chatId = getChatId();
39
40
  // TODO: remove startsWith once the provider normalizes chatId to full ID after first fetchChat
40
41
  // Support short ID matching (URL short IDs are prefixes of full IDs)
41
42
  if (chatId && message.chat_id && message.chat_id !== chatId && !message.chat_id.startsWith(chatId))
42
43
  return;
43
- dispatch({ type: 'UPDATE_MESSAGE', payload: message });
44
+ dispatch({ type: 'UPDATE_MESSAGE', payload: message, partial: fields ? true : undefined });
44
45
  // Dispatch client tool handlers when ready (in_progress or awaiting_input for backwards compat)
45
46
  const clientToolHandlers = getClientToolHandlers();
46
47
  if (message.tool_invocations && chatId && clientToolHandlers.size > 0) {
@@ -88,7 +89,7 @@ export function createActions(ctx) {
88
89
  dispatch({ type: 'SET_CONNECTION_STATUS', payload: 'connecting' });
89
90
  callbacks.onStatusChange?.('connecting');
90
91
  try {
91
- // Fetch initial chat
92
+ // Fetch initial chat (fetchChat loads messages separately since Chat.Get no longer preloads them)
92
93
  const chat = await api.fetchChat(client, id);
93
94
  if (chat) {
94
95
  setChat(chat);
@@ -139,15 +140,25 @@ export function createActions(ctx) {
139
140
  }
140
141
  });
141
142
  // Listen for ChatMessage updates
142
- manager.addEventListener('chat_messages', (message) => {
143
- updateMessage(message);
143
+ manager.addEventListener('chat_messages', (message, fields) => {
144
+ updateMessage(message, fields);
144
145
  });
145
146
  // Listen for AgentRun updates (state transitions, output)
146
147
  manager.addEventListener('agent_runs', (run) => {
147
148
  dispatch({ type: 'UPDATE_ACTIVE_RUN', payload: run });
148
- const asChat = { active_run: run };
149
- callbacks.onStatusChange?.(isChatBusy(asChat) ? 'streaming' : 'idle');
150
- checkTurnEnd(asChat);
149
+ const isRunActive = run.state === AgentRunStateWorking || run.state === AgentRunStateSubmitted || run.state === AgentRunStateInputRequired;
150
+ callbacks.onStatusChange?.(isRunActive ? 'streaming' : 'idle');
151
+ const currentChat = getState().chat;
152
+ if (currentChat)
153
+ checkTurnEnd({ ...currentChat, active_run: run });
154
+ });
155
+ // Listen for LLM delta events (token-by-token streaming)
156
+ const deltaAccum = createLLMDeltaAccumulator();
157
+ manager.addEventListener('delta', (evt) => {
158
+ if (evt && evt.delta) {
159
+ deltaAccum.apply(evt.delta);
160
+ dispatch({ type: 'DELTA_TOKEN', payload: deltaAccum.toOutput() });
161
+ }
151
162
  });
152
163
  setStreamManager(manager);
153
164
  manager.start();
@@ -156,13 +167,16 @@ export function createActions(ctx) {
156
167
  const pollChat = (id) => {
157
168
  let prevStatus = null;
158
169
  const manager = new PollManager({
159
- pollFunction: () => client.http.request('get', `/chats/${id}/status`),
170
+ pollFunction: async () => {
171
+ const resp = await client.http.request('get', `/chats/${id}/status`);
172
+ return resp.data;
173
+ },
160
174
  intervalMs: getPollIntervalMs(),
161
175
  onData: async (statusData) => {
162
176
  if (statusData.status === prevStatus)
163
177
  return;
164
178
  prevStatus = statusData.status;
165
- // Status changed — fetch full chat
179
+ // Status changed — fetch chat (fetchChat loads messages)
166
180
  try {
167
181
  const chat = await api.fetchChat(client, id);
168
182
  if (chat) {
@@ -229,7 +243,10 @@ export function createActions(ctx) {
229
243
  try {
230
244
  const result = await api.sendMessage(client, agentConfig, chatId, trimmedText, files);
231
245
  if (result) {
232
- const { chatId: newChatId } = result;
246
+ const { chatId: newChatId, userMessage } = result;
247
+ // Add user message from POST response immediately
248
+ if (userMessage)
249
+ dispatch({ type: 'UPDATE_MESSAGE', payload: userMessage });
233
250
  // Start streaming if not already connected
234
251
  const streamManager = getStreamManager();
235
252
  if (newChatId && !streamManager) {
@@ -330,6 +347,48 @@ export function createActions(ctx) {
330
347
  throw error;
331
348
  }
332
349
  },
350
+ cancelMessage: async (messageId) => {
351
+ try {
352
+ await api.cancelMessage(client, messageId);
353
+ }
354
+ catch (error) {
355
+ console.error('[AgentSDK] Failed to cancel message:', error);
356
+ const err = error instanceof Error ? error : new Error('Failed to cancel message');
357
+ dispatch({ type: 'SET_ERROR', payload: err.message });
358
+ callbacks.onError?.(err);
359
+ throw error;
360
+ }
361
+ },
362
+ resolveInterrupt: async (interruptId, decision) => {
363
+ try {
364
+ await api.resolveInterrupt(client, interruptId, decision);
365
+ }
366
+ catch (error) {
367
+ console.error('[AgentSDK] Failed to resolve interrupt:', error);
368
+ const err = error instanceof Error ? error : new Error('Failed to resolve interrupt');
369
+ dispatch({ type: 'SET_CONNECTION_STATUS', payload: 'error' });
370
+ dispatch({ type: 'SET_ERROR', payload: err.message });
371
+ callbacks.onError?.(err);
372
+ throw error;
373
+ }
374
+ },
375
+ loadOlderMessages: async () => {
376
+ const chatId = getChatId();
377
+ const cursor = getState().messageCursor;
378
+ if (!chatId || !cursor)
379
+ return false;
380
+ const page = await api.fetchMessagesPage(client, chatId, { cursor });
381
+ if (page.items.length > 0) {
382
+ dispatch({
383
+ type: 'PREPEND_MESSAGES',
384
+ payload: { messages: page.items, cursor: page.next_cursor, hasMore: page.has_next },
385
+ });
386
+ }
387
+ return page.has_next;
388
+ },
389
+ get hasOlderMessages() {
390
+ return getState().hasOlderMessages ?? false;
391
+ },
333
392
  };
334
393
  const internalActions = {
335
394
  streamChat,
@@ -1,50 +1,42 @@
1
1
  /**
2
2
  * Agent Chat API
3
3
  *
4
- * API functions for agent chat operations.
5
- * Uses the client passed in from the provider.
6
- */
7
- import type { ChatDTO, ChatMessageDTO } from '../types';
8
- import type { AdHocAgentConfig, TemplateAgentConfig, AgentOptions, AgentClient, FileRef } from './types';
9
- /**
10
- * File input that can be either a File to upload or an already-uploaded file
11
- */
12
- export type FileInput = globalThis.File | FileRef;
13
- /**
14
- * Send a message using ad-hoc agent config
15
- */
16
- export declare function sendAdHocMessage(client: AgentClient, config: AdHocAgentConfig, chatId: string | null, text: string, attachments?: FileRef[]): Promise<{
17
- chatId: string;
18
- userMessage: ChatMessageDTO;
19
- assistantMessage: ChatMessageDTO;
20
- } | null>;
21
- /**
22
- * Send a message using template agent config
4
+ * Two paths by user intent:
5
+ * - New conversation: POST /chats (create chat with agent) → POST /chats/{id}/messages
6
+ * - Existing chat: POST /chats/{id}/messages
7
+ *
8
+ * /agents/run stays for A2A/programmatic use.
23
9
  */
24
- export declare function sendTemplateMessage(client: AgentClient, config: TemplateAgentConfig, chatId: string | null, text: string, attachments?: FileRef[]): Promise<{
10
+ import type { ChatDTO, ChatMessageDTO, InterruptDTO } from '../types';
11
+ import type { AgentOptions, AgentClient, AgentInfo, FileRef } from './types';
12
+ export interface SendResult {
25
13
  chatId: string;
26
14
  userMessage: ChatMessageDTO;
27
- assistantMessage: ChatMessageDTO;
28
- } | null>;
15
+ }
29
16
  /**
30
- * Send a message (unified interface)
17
+ * File input that can be either a File to upload or an already-uploaded file
31
18
  */
32
- export declare function sendMessage(client: AgentClient, config: AgentOptions, chatId: string | null, text: string, files?: FileInput[]): Promise<{
33
- chatId: string;
34
- userMessage: ChatMessageDTO;
35
- assistantMessage: ChatMessageDTO;
36
- } | null>;
19
+ export type FileInput = globalThis.File | FileRef;
37
20
  /**
38
- * Fetch a chat by ID
39
- */
21
+ * Send a message — creates chat if needed, then sends message
22
+ */
23
+ export declare function sendMessage(client: AgentClient, config: AgentOptions, chatId: string | null, text: string, files?: FileInput[]): Promise<SendResult | null>;
24
+ export declare function fetchAgentInfo(client: AgentClient, agentRef: string): Promise<AgentInfo | null>;
25
+ export interface FetchMessagesOptions {
26
+ limit?: number;
27
+ cursor?: string;
28
+ }
29
+ export interface FetchMessagesResult {
30
+ items: ChatMessageDTO[];
31
+ next_cursor: string;
32
+ has_next: boolean;
33
+ }
34
+ export declare function fetchMessages(client: AgentClient, chatId: string, options?: FetchMessagesOptions): Promise<ChatMessageDTO[]>;
35
+ export declare function fetchMessagesPage(client: AgentClient, chatId: string, options?: FetchMessagesOptions): Promise<FetchMessagesResult>;
40
36
  export declare function fetchChat(client: AgentClient, chatId: string): Promise<ChatDTO | null>;
41
- /**
42
- * Stop a chat
43
- */
44
37
  export declare function stopChat(client: AgentClient, chatId: string): Promise<void>;
45
- /**
46
- * Submit a tool result (for client tools/widgets/awaiting input)
47
- */
38
+ export declare function cancelMessage(client: AgentClient, messageId: string): Promise<void>;
39
+ export declare function setAgent(client: AgentClient, chatId: string, agentRef: string): Promise<ChatDTO>;
48
40
  export declare function submitToolResult(client: AgentClient, toolInvocationId: string, resultOrAction: string | {
49
41
  action: {
50
42
  type: string;
@@ -52,25 +44,12 @@ export declare function submitToolResult(client: AgentClient, toolInvocationId:
52
44
  };
53
45
  form_data?: Record<string, unknown>;
54
46
  }): Promise<void>;
55
- /**
56
- * Approve a tool (for HIL approval)
57
- */
58
47
  export declare function approveTool(client: AgentClient, toolInvocationId: string): Promise<void>;
59
- /**
60
- * Reject a tool (for HIL approval)
61
- */
62
48
  export declare function rejectTool(client: AgentClient, toolInvocationId: string, reason?: string): Promise<void>;
63
- /**
64
- * Always allow a tool for this chat
65
- */
66
49
  export declare function alwaysAllowTool(client: AgentClient, chatId: string, toolInvocationId: string, toolName: string): Promise<void>;
67
- /**
68
- * Upload a file and return the uploaded file reference
69
- */
50
+ export declare function resolveInterrupt(client: AgentClient, interruptId: string, decision: 'allow' | 'deny'): Promise<InterruptDTO>;
51
+ export declare function listRunInterrupts(client: AgentClient, runId: string): Promise<InterruptDTO[]>;
70
52
  export declare function uploadFile(client: AgentClient, file: globalThis.File): Promise<FileRef>;
71
- /**
72
- * Get streamable config for chat streaming (NDJSON)
73
- */
74
53
  export declare function getChatStreamConfig(client: AgentClient, chatId: string): {
75
54
  url: string;
76
55
  headers: Record<string, string>;
package/dist/agent/api.js CHANGED
@@ -1,136 +1,126 @@
1
1
  /**
2
2
  * Agent Chat API
3
3
  *
4
- * API functions for agent chat operations.
5
- * Uses the client passed in from the provider.
6
- */
7
- import { isAdHocConfig, extractToolSchemas } from './types';
8
- /**
9
- * Check if input is an already-uploaded file
4
+ * Two paths by user intent:
5
+ * - New conversation: POST /chats (create chat with agent) → POST /chats/{id}/messages
6
+ * - Existing chat: POST /chats/{id}/messages
7
+ *
8
+ * /agents/run stays for A2A/programmatic use.
10
9
  */
10
+ import { isAdHocConfig } from './types';
11
11
  function isFileRef(input) {
12
12
  return 'uri' in input && typeof input.uri === 'string';
13
13
  }
14
14
  /**
15
- * Send a message using ad-hoc agent config
15
+ * Process file inputs — upload raw files, pass through already-uploaded FileRefs
16
16
  */
17
- export async function sendAdHocMessage(client, config, chatId, text, attachments) {
18
- // Extract just the schemas from tools (handlers are stripped out)
19
- const toolSchemas = config.tools ? extractToolSchemas(config.tools) : undefined;
20
- const request = {
21
- chat_id: chatId ?? undefined,
22
- agent_config: {
23
- ...config,
24
- system_prompt: config.system_prompt ?? '',
25
- tools: toolSchemas
26
- },
27
- agent_name: config.name,
28
- input: {
29
- text,
30
- attachments,
31
- context_size: 0,
32
- system_prompt: '',
33
- context: [],
34
- role: 'user',
35
- },
36
- };
37
- const response = await client.http.request('post', '/agents/run', { data: request });
38
- if (response) {
39
- const { user_message, assistant_message } = response;
40
- if (user_message && assistant_message) {
41
- return {
42
- chatId: assistant_message.chat_id,
43
- userMessage: user_message,
44
- assistantMessage: assistant_message,
45
- };
17
+ async function processFiles(client, files) {
18
+ if (!files || files.length === 0)
19
+ return undefined;
20
+ const results = await Promise.all(files.map(async (file) => {
21
+ if (isFileRef(file))
22
+ return file;
23
+ try {
24
+ return await client.files.upload(file);
46
25
  }
47
- }
48
- return null;
26
+ catch (error) {
27
+ console.error('[AgentSDK] Failed to upload file:', error);
28
+ return null;
29
+ }
30
+ }));
31
+ const refs = results.filter((r) => r !== null);
32
+ return refs.length > 0 ? refs : undefined;
49
33
  }
50
34
  /**
51
- * Send a message using template agent config
35
+ * Create a new chat with an agent — POST /chats
52
36
  */
53
- export async function sendTemplateMessage(client, config, chatId, text, attachments) {
54
- const request = {
55
- chat_id: chatId ?? undefined,
56
- // Only include agent if it's not empty (for existing chats, backend uses chat's agent)
57
- agent: config.agent || undefined,
58
- // Agent-level context (version_id, app_id, ...). Omit when empty so we don't
59
- // send a bare {} for agents that declare no context.
60
- context: config.context && Object.keys(config.context).length > 0 ? config.context : undefined,
61
- input: {
62
- text,
63
- attachments,
64
- context_size: 0,
65
- system_prompt: '',
66
- context: [],
67
- role: 'user',
68
- },
37
+ async function createChat(client, config) {
38
+ const agentRef = isAdHocConfig(config) ? config.core_app.ref : config.agent;
39
+ const context = !isAdHocConfig(config) ? config.context : undefined;
40
+ const resp = await client.http.request('post', '/chats', {
41
+ data: { agent: agentRef, context },
42
+ });
43
+ return resp.data;
44
+ }
45
+ /**
46
+ * Send a message in a chat — POST /chats/{id}/messages
47
+ */
48
+ async function sendChatMessage(client, chatId, text) {
49
+ const resp = await client.http.request('post', `/chats/${chatId}/messages`, {
50
+ data: { message: text },
51
+ });
52
+ return {
53
+ chatId,
54
+ userMessage: resp.data,
69
55
  };
70
- const response = await client.http.request('post', '/agents/run', { data: request });
71
- if (response) {
72
- const { user_message, assistant_message } = response;
73
- if (user_message && assistant_message) {
74
- return {
75
- chatId: assistant_message.chat_id,
76
- userMessage: user_message,
77
- assistantMessage: assistant_message,
78
- };
79
- }
80
- }
81
- return null;
82
56
  }
83
57
  /**
84
- * Send a message (unified interface)
58
+ * Send a message — creates chat if needed, then sends message
85
59
  */
86
60
  export async function sendMessage(client, config, chatId, text, files) {
87
- // Process files - upload if needed, collect as FileRef attachments
88
- let attachments;
89
- if (files && files.length > 0) {
90
- attachments = [];
91
- for (const file of files) {
92
- // Check if already uploaded (FileRef)
93
- if (isFileRef(file)) {
94
- attachments.push(file);
95
- continue;
96
- }
97
- // Upload the file
98
- try {
99
- const result = await client.files.upload(file);
100
- if (result) {
101
- attachments.push(result);
102
- }
103
- }
104
- catch (error) {
105
- console.error('[AgentSDK] Failed to upload file:', error);
106
- }
107
- }
108
- if (attachments.length === 0) {
109
- attachments = undefined;
110
- }
61
+ await processFiles(client, files);
62
+ // Existing chat — just send the message
63
+ if (chatId) {
64
+ return sendChatMessage(client, chatId, text);
65
+ }
66
+ // New chat — create it, then send the first message
67
+ const chat = await createChat(client, config);
68
+ return sendChatMessage(client, chat.id, text);
69
+ }
70
+ // =========================================================================
71
+ // Agent info
72
+ // =========================================================================
73
+ export async function fetchAgentInfo(client, agentRef) {
74
+ try {
75
+ const resp = await client.http.request('get', `/agents/${agentRef}`);
76
+ const version = resp.data?.version;
77
+ return {
78
+ description: version?.description,
79
+ example_prompts: version?.example_prompts,
80
+ };
111
81
  }
112
- if (isAdHocConfig(config)) {
113
- return sendAdHocMessage(client, config, chatId, text, attachments);
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ export async function fetchMessages(client, chatId, options) {
87
+ const result = await fetchMessagesPage(client, chatId, options);
88
+ return result.items;
89
+ }
90
+ export async function fetchMessagesPage(client, chatId, options) {
91
+ try {
92
+ const params = {};
93
+ if (options?.limit !== undefined)
94
+ params.limit = options.limit;
95
+ if (options?.cursor)
96
+ params.cursor = options.cursor;
97
+ const resp = await client.http.request('get', `/chats/${chatId}/messages`, { params });
98
+ return resp.data || { items: [], next_cursor: '', has_next: false };
114
99
  }
115
- else {
116
- return sendTemplateMessage(client, config, chatId, text, attachments);
100
+ catch (error) {
101
+ console.error('[AgentSDK] Failed to fetch messages:', error);
102
+ return { items: [], next_cursor: '', has_next: false };
117
103
  }
118
104
  }
119
- /**
120
- * Fetch a chat by ID
121
- */
122
105
  export async function fetchChat(client, chatId) {
123
106
  try {
124
- return await client.http.request('get', `/chats/${chatId}`);
107
+ const resp = await client.http.request('get', `/chats/${chatId}`);
108
+ const chat = resp.data;
109
+ // Chat.Get no longer preloads messages — fetch them separately and attach
110
+ if (chat && (!chat.chat_messages || chat.chat_messages.length === 0)) {
111
+ const page = await fetchMessagesPage(client, chatId);
112
+ chat.chat_messages = page.items;
113
+ // Store pagination info on the chat for the reducer to pick up
114
+ chat._messageCursor = page.next_cursor;
115
+ chat._hasOlderMessages = page.has_next;
116
+ }
117
+ return chat;
125
118
  }
126
119
  catch (error) {
127
120
  console.error('[AgentSDK] Failed to fetch chat:', error);
128
121
  }
129
122
  return null;
130
123
  }
131
- /**
132
- * Stop a chat
133
- */
134
124
  export async function stopChat(client, chatId) {
135
125
  try {
136
126
  await client.http.request('post', `/chats/${chatId}/stop`);
@@ -139,67 +129,52 @@ export async function stopChat(client, chatId) {
139
129
  console.error('[AgentSDK] Failed to stop chat:', error);
140
130
  }
141
131
  }
142
- /**
143
- * Submit a tool result (for client tools/widgets/awaiting input)
144
- */
132
+ export async function cancelMessage(client, messageId) {
133
+ await client.http.request('post', `/chats/messages/${messageId}/cancel`);
134
+ }
135
+ export async function setAgent(client, chatId, agentRef) {
136
+ const resp = await client.http.request('post', `/chats/${chatId}/agent`, {
137
+ data: { agent: agentRef },
138
+ });
139
+ return resp.data;
140
+ }
141
+ // =========================================================================
142
+ // Tool operations
143
+ // =========================================================================
145
144
  export async function submitToolResult(client, toolInvocationId, resultOrAction) {
146
- try {
147
- const data = typeof resultOrAction === 'string' ? { result: resultOrAction } : resultOrAction;
148
- await client.http.request('post', `/tools/${toolInvocationId}`, { data });
149
- }
150
- catch (error) {
151
- console.error('[AgentSDK] Failed to submit tool result:', error);
152
- throw error;
153
- }
145
+ const data = typeof resultOrAction === 'string' ? { result: resultOrAction } : resultOrAction;
146
+ await client.http.request('post', `/tools/${toolInvocationId}`, { data });
154
147
  }
155
- /**
156
- * Approve a tool (for HIL approval)
157
- */
158
148
  export async function approveTool(client, toolInvocationId) {
159
- try {
160
- await client.http.request('post', `/tools/${toolInvocationId}/invoke`);
161
- }
162
- catch (error) {
163
- console.error('[AgentSDK] Failed to approve tool:', error);
164
- throw error;
165
- }
149
+ await client.http.request('post', `/tools/${toolInvocationId}/invoke`);
166
150
  }
167
- /**
168
- * Reject a tool (for HIL approval)
169
- */
170
151
  export async function rejectTool(client, toolInvocationId, reason) {
171
- try {
172
- await client.http.request('post', `/tools/${toolInvocationId}/reject`, { data: { reason } });
173
- }
174
- catch (error) {
175
- console.error('[AgentSDK] Failed to reject tool:', error);
176
- throw error;
177
- }
152
+ await client.http.request('post', `/tools/${toolInvocationId}/reject`, { data: { reason } });
178
153
  }
179
- /**
180
- * Always allow a tool for this chat
181
- */
182
154
  export async function alwaysAllowTool(client, chatId, toolInvocationId, toolName) {
183
- try {
184
- await client.http.request('post', `/chats/${chatId}/tools/${toolInvocationId}/always-allow`, {
185
- data: { tool_name: toolName }
186
- });
187
- }
188
- catch (error) {
189
- console.error('[AgentSDK] Failed to always-allow tool:', error);
190
- throw error;
191
- }
155
+ await client.http.request('post', `/chats/${chatId}/tools/${toolInvocationId}/always-allow`, {
156
+ data: { tool_name: toolName }
157
+ });
192
158
  }
193
- /**
194
- * Upload a file and return the uploaded file reference
195
- */
159
+ // =========================================================================
160
+ // Interrupt operations
161
+ // =========================================================================
162
+ export async function resolveInterrupt(client, interruptId, decision) {
163
+ const resp = await client.http.request('post', `/interrupts/${interruptId}/resolve`, {
164
+ data: { decision }
165
+ });
166
+ return resp.data;
167
+ }
168
+ export async function listRunInterrupts(client, runId) {
169
+ const resp = await client.http.request('get', `/agent-runs/${runId}/interrupts`);
170
+ return resp.data;
171
+ }
172
+ // =========================================================================
173
+ // File & stream operations
174
+ // =========================================================================
196
175
  export async function uploadFile(client, file) {
197
- const result = await client.files.upload(file);
198
- return result;
176
+ return client.files.upload(file);
199
177
  }
200
- /**
201
- * Get streamable config for chat streaming (NDJSON)
202
- */
203
178
  export function getChatStreamConfig(client, chatId) {
204
179
  return client.http.getStreamableConfig(`/chats/${chatId}/stream`);
205
180
  }