@inferencesh/sdk 0.6.50 → 0.6.52

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 CHANGED
@@ -363,7 +363,7 @@ import {
363
363
  mcpTool,
364
364
  internalTools,
365
365
  string,
366
- IntegrationProviderGoogle,
366
+ CredentialProviderGoogle,
367
367
  } from '@inferencesh/sdk';
368
368
 
369
369
  const clientTool = tool('get_weather')
@@ -375,7 +375,7 @@ const clientTool = tool('get_weather')
375
375
  const gmailSend = httpTool('gmail_send', 'https://gmail.googleapis.com/gmail/v1/users/me/messages/send')
376
376
  .describe('Send an email via Gmail')
377
377
  .method('POST')
378
- .auth({ integration: IntegrationProviderGoogle, integrationId: 'your-integration-id' })
378
+ .auth({ integration: CredentialProviderGoogle, integrationId: 'your-integration-id' })
379
379
  .build();
380
380
 
381
381
  // API key or bearer auth
@@ -606,24 +606,24 @@ if (task.status === TaskStatusCompleted) {
606
606
 
607
607
  ## Integration Constants
608
608
 
609
- `IntegrationDTO` fields (`provider`, `type`, `auth`, `status`) use typed string unions exported as constants:
609
+ `CredentialDTO` fields (`provider`, `type`, `auth`, `status`) use typed string unions exported as constants:
610
610
 
611
611
  ```typescript
612
- import type { IntegrationDTO } from '@inferencesh/sdk';
612
+ import type { CredentialDTO } from '@inferencesh/sdk';
613
613
  import {
614
- IntegrationProviderGoogle,
615
- IntegrationAuthTypeOAuth,
616
- IntegrationStatusConnected,
617
- IntegrationStatusDisconnected,
618
- IntegrationStatusExpired,
619
- IntegrationStatusError,
614
+ CredentialProviderGoogle,
615
+ CredentialTypeOAuth,
616
+ CredentialStatusConnected,
617
+ CredentialStatusDisconnected,
618
+ CredentialStatusExpired,
619
+ CredentialStatusError,
620
620
  isRequirementsNotMetException,
621
621
  } from '@inferencesh/sdk';
622
622
 
623
- function isGoogleConnected(integration: IntegrationDTO): boolean {
623
+ function isGoogleConnected(integration: CredentialDTO): boolean {
624
624
  return (
625
- integration.provider === IntegrationProviderGoogle &&
626
- integration.status === IntegrationStatusConnected
625
+ integration.provider === CredentialProviderGoogle &&
626
+ integration.status === CredentialStatusConnected
627
627
  );
628
628
  }
629
629
 
@@ -633,7 +633,7 @@ try {
633
633
  } catch (error) {
634
634
  if (isRequirementsNotMetException(error)) {
635
635
  for (const req of error.errors) {
636
- if (req.type === 'integration' && req.action?.provider === IntegrationProviderGoogle) {
636
+ if (req.type === 'integration' && req.action?.provider === CredentialProviderGoogle) {
637
637
  // User must connect Google — see https://inference.sh/docs/extend/integrations
638
638
  }
639
639
  }
@@ -643,9 +643,9 @@ try {
643
643
 
644
644
  | Constant group | Values |
645
645
  |----------------|--------|
646
- | `IntegrationProvider*` | `google`, `slack`, `notion`, `github`, `x`, `microsoft`, `salesforce`, `discord`, `gcp`, `mcp`, `reddit` |
647
- | `IntegrationAuthType*` | `service_account`, `oauth`, `api_key`, `wif`, `mcp` |
648
- | `IntegrationStatus*` | `connected`, `disconnected`, `expired`, `error` |
646
+ | `CredentialProvider*` | `google`, `slack`, `notion`, `github`, `x`, `microsoft`, `salesforce`, `discord`, `gcp`, `mcp`, `reddit` |
647
+ | `CredentialType*` | `service_account`, `oauth`, `api_key`, `wif`, `mcp` |
648
+ | `CredentialStatus*` | `connected`, `disconnected`, `expired`, `error` |
649
649
 
650
650
  ## Instance Status Constants
651
651
 
@@ -698,7 +698,7 @@ import type {
698
698
  Task,
699
699
  ApiAppRunRequest,
700
700
  RunOptions,
701
- IntegrationDTO,
701
+ CredentialDTO,
702
702
  AgentTool,
703
703
  } from '@inferencesh/sdk';
704
704
  ```
@@ -4,7 +4,7 @@
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 { AgentRunStateWorking, AgentRunStateSubmitted, AgentRunStateInputRequired, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, ToolTypeClient, } from '../types';
7
+ import { AgentRunStateWorking, AgentRunStateSubmitted, AgentRunStateInputRequired, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, ToolTypeClient, ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled, } from '../types';
8
8
  import { isChatBusy } from '../utils';
9
9
  import { StreamableManager } from '../http/streamable';
10
10
  import { PollManager } from '../http/poll';
@@ -139,17 +139,19 @@ export function createActions(ctx) {
139
139
  checkTurnEnd(chatData);
140
140
  }
141
141
  });
142
- // Token-by-token streaming state, reset at every assistant-message boundary.
143
- const deltaAccum = createLLMDeltaAccumulator();
142
+ // Token-by-token streaming state, one accumulator per message being
143
+ // streamed. Deltas name their message (DeltaEvent.resource_id), so state
144
+ // never leaks between messages the way a single shared accumulator allowed.
145
+ const deltaAccums = new Map();
144
146
  // Listen for ChatMessage updates
145
147
  manager.addEventListener('chat_messages', (message, fields) => {
146
- // A new assistant message starts a new accumulation. The accumulator is
147
- // cumulative and shared across the whole connection, so without this the
148
- // next message's deltas merge into the previous message's state — and
149
- // because concat with "" is a no-op, a turn that is only tool calls
150
- // would render the previous message's text as its own.
151
- if (message.role === 'assistant' && !getState().messages.some(m => m.id === message.id)) {
152
- deltaAccum.reset();
148
+ // A message that has reached a terminal state will receive no further
149
+ // deltas, so its accumulator is done. This bounds the map by the number
150
+ // of messages streaming at once rather than by chat length.
151
+ if (message.status === ChatMessageStatusReady
152
+ || message.status === ChatMessageStatusFailed
153
+ || message.status === ChatMessageStatusCancelled) {
154
+ deltaAccums.delete(message.id);
153
155
  }
154
156
  updateMessage(message, fields);
155
157
  });
@@ -163,10 +165,23 @@ export function createActions(ctx) {
163
165
  checkTurnEnd({ ...currentChat, active_run: run });
164
166
  });
165
167
  manager.addEventListener('delta', (evt) => {
166
- if (evt && evt.delta) {
167
- deltaAccum.apply(evt.delta);
168
- dispatch({ type: 'DELTA_TOKEN', payload: deltaAccum.toOutput() });
168
+ if (!evt || !evt.delta)
169
+ return;
170
+ // On a chat stream every task is created with an execution edge, so a
171
+ // delta with no resource id means something is wrong upstream — a missing
172
+ // or ambiguous edge, or a failed lookup. Guessing a target there would
173
+ // reintroduce exactly the misattribution this field exists to end, so
174
+ // drop it: the text still lands when the message itself arrives.
175
+ const messageId = evt.resource_id;
176
+ if (!messageId)
177
+ return;
178
+ let accum = deltaAccums.get(messageId);
179
+ if (!accum) {
180
+ accum = createLLMDeltaAccumulator();
181
+ deltaAccums.set(messageId, accum);
169
182
  }
183
+ accum.apply(evt.delta);
184
+ dispatch({ type: 'DELTA_TOKEN', payload: { messageId, output: accum.toOutput() } });
170
185
  });
171
186
  setStreamManager(manager);
172
187
  manager.start();
@@ -85,16 +85,19 @@ export function chatReducer(state, action) {
85
85
  messages: [...state.messages, action.payload].sort((a, b) => a.order - b.order),
86
86
  };
87
87
  case 'DELTA_TOKEN': {
88
- const output = action.payload;
88
+ const { messageId, output } = action.payload;
89
89
  const msgs = state.messages;
90
- const lastAssistant = [...msgs].reverse().find(m => m.role === 'assistant');
91
- if (!lastAssistant)
90
+ // Apply to the message the delta names — never to a guessed one. A
91
+ // message we have not received yet (or an unnamed delta) is dropped
92
+ // rather than misattributed; the text still arrives with the message.
93
+ const target = msgs.find(m => m.id === messageId);
94
+ if (!target)
92
95
  return state;
93
- const textBlock = lastAssistant.content?.find(c => c.type === 'text');
96
+ const textBlock = target.content?.find(c => c.type === 'text');
94
97
  const newContent = textBlock
95
- ? lastAssistant.content.map(c => c.type === 'text' ? { ...c, text: output.response } : c)
96
- : [{ type: 'text', text: output.response }, ...lastAssistant.content];
97
- const newMessages = msgs.map(m => m.id === lastAssistant.id ? { ...lastAssistant, content: newContent } : m);
98
+ ? target.content.map(c => c.type === 'text' ? { ...c, text: output.response } : c)
99
+ : [{ type: 'text', text: output.response }, ...target.content];
100
+ const newMessages = msgs.map(m => m.id === target.id ? { ...target, content: newContent } : m);
98
101
  return { ...state, messages: newMessages };
99
102
  }
100
103
  case 'SET_CONNECTION_STATUS':
@@ -220,7 +220,10 @@ export type ChatAction = {
220
220
  payload: ChatMessageDTO;
221
221
  } | {
222
222
  type: 'DELTA_TOKEN';
223
- payload: Record<string, any>;
223
+ payload: {
224
+ messageId: string;
225
+ output: Record<string, any>;
226
+ };
224
227
  } | {
225
228
  type: 'SET_CONNECTION_STATUS';
226
229
  payload: ChatStatus;
@@ -1,7 +1,7 @@
1
1
  import { HttpClient } from '../http/client';
2
2
  import type { Response } from '../http/response';
3
3
  import { FilesAPI } from './files';
4
- import { ChatDTO, ChatMessageDTO, AgentConfigInput as AgentConfig, AgentDTO, AgentVersionDTO, CreateAgentRequest, FileDTO as File, InterruptDTO, CursorListRequest, CursorListResponse } from '../types';
4
+ import { ChatDTO, ChatMessageDTO, LLMDelta, LLMOutput, AgentConfigInput as AgentConfig, AgentDTO, AgentVersionDTO, CreateAgentRequest, FileDTO as File, InterruptDTO, CursorListRequest, CursorListResponse } from '../types';
5
5
  /** Internal tool definition returned by getInternalTools */
6
6
  export interface InternalToolDefinition {
7
7
  id: string;
@@ -20,6 +20,20 @@ export interface AgentOptions {
20
20
  /** Per-chat context variables — resolved in call tool URL templates ({{context.X}}) */
21
21
  context?: Record<string, string>;
22
22
  }
23
+ /**
24
+ * One streamed token batch for a message, with everything received for that
25
+ * message so far. `output.response` is the assistant text as it grows.
26
+ */
27
+ export interface AgentDelta {
28
+ /** The chat message the tokens belong to (normally this turn's assistant message) */
29
+ messageId: string;
30
+ /** This batch alone */
31
+ delta: LLMDelta;
32
+ /** All batches for the message merged, in the shape of the message's final output */
33
+ output: LLMOutput;
34
+ /** Producer sequence number, monotonically increasing per message */
35
+ seq: number;
36
+ }
23
37
  export interface SendMessageOptions {
24
38
  /** File attachments - Blob (will be uploaded) or FileDTO (already uploaded, has uri) */
25
39
  files?: (Blob | File)[];
@@ -27,6 +41,12 @@ export interface SendMessageOptions {
27
41
  onMessage?: (message: ChatMessageDTO) => void;
28
42
  /** Callback for chat updates */
29
43
  onChat?: (chat: ChatDTO) => void;
44
+ /**
45
+ * Callback for token-by-token output while the assistant message is being
46
+ * generated. Streaming mode only: with `stream: false` there are no deltas
47
+ * and the message arrives whole through onMessage.
48
+ */
49
+ onDelta?: (delta: AgentDelta) => void;
30
50
  /** Callback when a client tool needs execution */
31
51
  onToolCall?: (invocation: {
32
52
  id: string;
@@ -1,7 +1,39 @@
1
1
  import { StreamableManager } from '../http/streamable';
2
2
  import { PollManager } from '../http/poll';
3
- import { ToolTypeClient, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, } from '../types';
3
+ import { createLLMDeltaAccumulator } from '../delta';
4
+ import { ChatMessageStatusCancelled, ChatMessageStatusFailed, ChatMessageStatusReady, ToolTypeClient, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, } from '../types';
4
5
  import { isChatBusy } from '../utils';
6
+ const terminalMessageStatuses = new Set([ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled]);
7
+ /**
8
+ * Decides when one sendMessage() turn is over.
9
+ *
10
+ * For an existing chat the stream/poll is opened before the POST so nothing is
11
+ * missed, but its first snapshot is the previous turn's idle state. Resolving on
12
+ * that made sendMessage return before the new run had started. An idle snapshot
13
+ * only counts once the chat was seen busy, or once this turn's assistant message
14
+ * reached a terminal status (runs that finish between two observations).
15
+ */
16
+ class TurnGate {
17
+ constructor(existingChat) {
18
+ this.existingChat = existingChat;
19
+ this.assistantMessageId = null;
20
+ this.sawBusy = false;
21
+ this.assistantDone = false;
22
+ }
23
+ observeChat(chat) {
24
+ if (isChatBusy(chat))
25
+ this.sawBusy = true;
26
+ }
27
+ observeMessage(message) {
28
+ if (message.id === this.assistantMessageId && terminalMessageStatuses.has(message.status)) {
29
+ this.assistantDone = true;
30
+ }
31
+ }
32
+ /** Whether an idle observation may end the turn. */
33
+ get settled() {
34
+ return !this.existingChat || this.sawBusy || this.assistantDone;
35
+ }
36
+ }
5
37
  /**
6
38
  * Agent for chat interactions
7
39
  *
@@ -28,7 +60,7 @@ export class Agent {
28
60
  async sendMessage(text, options = {}) {
29
61
  this.dispatchedToolCalls.clear();
30
62
  const isTemplate = typeof this.config === 'string';
31
- const hasCallbacks = !!(options.onMessage || options.onChat || options.onToolCall);
63
+ const hasCallbacks = !!(options.onMessage || options.onChat || options.onToolCall || options.onDelta);
32
64
  // Process files - either already uploaded (FileDTO with uri) or needs upload (Blob)
33
65
  let imageUris;
34
66
  let fileUris;
@@ -68,17 +100,28 @@ export class Agent {
68
100
  };
69
101
  const useStream = options.stream ?? this.http.getStreamDefault();
70
102
  const shouldWait = useStream === false || hasCallbacks;
103
+ const gate = new TurnGate(!!this.chatId);
71
104
  const waitFn = useStream === false
72
- ? (opts) => this.pollUntilIdle(opts)
73
- : (opts) => this.streamUntilIdle(opts);
105
+ ? (opts) => this.pollUntilIdle(opts, gate)
106
+ : (opts) => this.streamUntilIdle(opts, gate);
74
107
  // For existing chats: Start waiting BEFORE POST so we don't miss updates
75
108
  let waitPromise = null;
76
109
  if (this.chatId && shouldWait) {
77
110
  waitPromise = waitFn(options);
78
111
  }
79
112
  // Make the POST request
80
- const resp = await this.http.request('post', '/agents/run', { data: body });
81
- const response = resp.data;
113
+ let response;
114
+ try {
115
+ const resp = await this.http.request('post', '/agents/run', { data: body });
116
+ response = resp.data;
117
+ }
118
+ catch (err) {
119
+ // Nothing to wait for; don't leave the pre-opened stream/poller running.
120
+ if (waitPromise)
121
+ this.disconnect();
122
+ throw err;
123
+ }
124
+ gate.assistantMessageId = response.assistant_message?.id ?? null;
82
125
  // For new chats: Set chatId and start waiting immediately after POST
83
126
  const isNewChat = !this.chatId && response.assistant_message.chat_id;
84
127
  if (isNewChat) {
@@ -145,10 +188,10 @@ export class Agent {
145
188
  startStreaming(options = {}) {
146
189
  if (!this.chatId)
147
190
  return;
148
- this.streamUntilIdle(options);
191
+ this.streamUntilIdle(options, new TurnGate(false));
149
192
  }
150
193
  /** Stream events until chat becomes idle */
151
- streamUntilIdle(options) {
194
+ streamUntilIdle(options, gate) {
152
195
  if (!this.chatId)
153
196
  return Promise.resolve();
154
197
  const { url, headers, credentials } = this.http.getStreamableConfig(`/chats/${this.chatId}/stream`);
@@ -159,21 +202,60 @@ export class Agent {
159
202
  headers,
160
203
  credentials,
161
204
  });
205
+ // Last chat/run observation was idle but the gate wasn't settled yet;
206
+ // a terminal message for this turn can settle it.
207
+ let idlePending = false;
208
+ const onIdle = () => {
209
+ if (gate.settled)
210
+ resolve();
211
+ else
212
+ idlePending = true;
213
+ };
162
214
  this.stream.addEventListener('chats', (chat) => {
163
215
  options.onChat?.(chat);
164
- if (!isChatBusy(chat)) {
165
- resolve();
166
- }
216
+ gate.observeChat(chat);
217
+ if (!isChatBusy(chat))
218
+ onIdle();
219
+ else
220
+ idlePending = false;
167
221
  });
168
222
  this.stream.addEventListener('agent_runs', (run) => {
169
223
  const asChat = { active_run: run };
170
224
  options.onChat?.(asChat);
171
- if (!isChatBusy(asChat)) {
172
- resolve();
225
+ gate.observeChat(asChat);
226
+ if (!isChatBusy(asChat))
227
+ onIdle();
228
+ else
229
+ idlePending = false;
230
+ });
231
+ // One accumulator per message being streamed, keyed by the message id
232
+ // the delta names, so a tool-call-only turn never shows the previous
233
+ // message's text. Same attribution rule as the React hooks.
234
+ const deltaAccums = new Map();
235
+ this.stream.addEventListener('delta', (evt) => {
236
+ if (!options.onDelta || !evt?.delta || !evt.resource_id)
237
+ return;
238
+ let accum = deltaAccums.get(evt.resource_id);
239
+ if (!accum) {
240
+ accum = createLLMDeltaAccumulator();
241
+ deltaAccums.set(evt.resource_id, accum);
173
242
  }
243
+ accum.apply(evt.delta);
244
+ options.onDelta({
245
+ messageId: evt.resource_id,
246
+ delta: evt.delta,
247
+ output: accum.toOutput(),
248
+ seq: evt.seq,
249
+ });
174
250
  });
175
251
  this.stream.addEventListener('chat_messages', (message) => {
252
+ // A terminal message receives no further deltas.
253
+ if (terminalMessageStatuses.has(message.status))
254
+ deltaAccums.delete(message.id);
255
+ gate.observeMessage(message);
176
256
  options.onMessage?.(message);
257
+ if (idlePending && gate.settled)
258
+ resolve();
177
259
  if (message.tool_invocations && options.onToolCall) {
178
260
  for (const inv of message.tool_invocations) {
179
261
  if (this.dispatchedToolCalls.has(inv.id))
@@ -193,7 +275,7 @@ export class Agent {
193
275
  });
194
276
  }
195
277
  /** Poll until chat becomes idle, dispatching callbacks on changes */
196
- pollUntilIdle(options) {
278
+ pollUntilIdle(options, gate) {
197
279
  if (!this.chatId)
198
280
  return Promise.resolve();
199
281
  const intervalMs = options.pollIntervalMs ?? this.http.getPollIntervalMs();
@@ -206,7 +288,9 @@ export class Agent {
206
288
  // Lightweight status check first
207
289
  const statusResp = await this.http.request('get', `/chats/${this.chatId}/status`);
208
290
  const status = statusResp.data;
209
- if (status.status === prevStatus) {
291
+ // Unchanged status is skipped — unless the turn is still ungated: a run
292
+ // that started and finished between two polls only shows in the messages.
293
+ if (status.status === prevStatus && gate.settled) {
210
294
  // No change — return a stub to skip processing
211
295
  return { status: status.status };
212
296
  }
@@ -220,6 +304,9 @@ export class Agent {
220
304
  return;
221
305
  prevStatus = chat.status;
222
306
  options.onChat?.(chat);
307
+ gate.observeChat(chat);
308
+ for (const message of chat.chat_messages ?? [])
309
+ gate.observeMessage(message);
223
310
  // Dispatch new/updated messages
224
311
  if (chat.chat_messages && options.onMessage) {
225
312
  for (const message of chat.chat_messages) {
@@ -248,7 +335,7 @@ export class Agent {
248
335
  }
249
336
  }
250
337
  }
251
- if (!isChatBusy(chat)) {
338
+ if (!isChatBusy(chat) && gate.settled) {
252
339
  this.poller?.stop();
253
340
  this.poller = null;
254
341
  resolve();
@@ -1,6 +1,6 @@
1
1
  import { HttpClient } from '../http/client';
2
2
  import type { Response } from '../http/response';
3
- import { IntegrationDTO, IntegrationConfigDTO, IntegrationConnectRequest, IntegrationConnectResponse, CursorListRequest, CursorListResponse } from '../types';
3
+ import { CredentialDTO, CredentialConfigDTO, CredentialConnectRequest, CredentialConnectResponse, CursorListRequest, CursorListResponse } from '../types';
4
4
  /**
5
5
  * Integrations API
6
6
  */
@@ -10,15 +10,15 @@ export declare class IntegrationsAPI {
10
10
  /**
11
11
  * List integrations with cursor-based pagination
12
12
  */
13
- list(params?: Partial<CursorListRequest>): Promise<Response<CursorListResponse<IntegrationDTO>>>;
13
+ list(params?: Partial<CursorListRequest>): Promise<Response<CursorListResponse<CredentialDTO>>>;
14
14
  /**
15
15
  * Get available integrations
16
16
  */
17
- listAvailable(): Promise<Response<IntegrationConfigDTO[]>>;
17
+ listAvailable(): Promise<Response<CredentialConfigDTO[]>>;
18
18
  /**
19
19
  * Get integration configs
20
20
  */
21
- getConfigs(): Promise<Response<IntegrationConfigDTO[]>>;
21
+ getConfigs(): Promise<Response<CredentialConfigDTO[]>>;
22
22
  /**
23
23
  * Get capabilities
24
24
  */
@@ -30,11 +30,11 @@ export declare class IntegrationsAPI {
30
30
  /**
31
31
  * Connect an integration
32
32
  */
33
- connect(data: IntegrationConnectRequest): Promise<Response<IntegrationConnectResponse>>;
33
+ connect(data: CredentialConnectRequest): Promise<Response<CredentialConnectResponse>>;
34
34
  /**
35
35
  * Get an integration by provider key
36
36
  */
37
- get(provider: string): Promise<Response<IntegrationDTO>>;
37
+ get(provider: string): Promise<Response<CredentialDTO>>;
38
38
  /**
39
39
  * Disconnect an integration
40
40
  */
@@ -17,7 +17,11 @@ export class HttpClient {
17
17
  this.proxyUrl = config.proxyUrl;
18
18
  this.getToken = config.getToken;
19
19
  this.customHeaders = { 'X-Client-Source': 'inference-sdk-js/0.5.13', ...config.headers };
20
- this.credentials = config.credentials || 'include';
20
+ // Bearer auth needs no cookies, and 'include' makes browsers reject the
21
+ // response unless the API answers with Allow-Credentials — which it does not
22
+ // for third-party origins (WebKit reports that as "Load failed"). Cookies
23
+ // matter only for the proxy / getToken flows, which keep 'include'.
24
+ this.credentials = config.credentials || (config.apiKey ? 'omit' : 'include');
21
25
  this.onError = config.onError;
22
26
  this.onMessage = config.onMessage;
23
27
  this.streamDefault = config.stream ?? true;
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { PollManager, type PollManagerOptions } from './http/poll';
7
7
  export { InferenceError, RequirementsNotMetException, SessionError, SessionNotFoundError, SessionExpiredError, SessionEndedError, WorkerLostError, isRequirementsNotMetException, isInferenceError, isSessionError, } from './http/errors';
8
8
  export { TasksAPI, type RunOptions } from './api/tasks';
9
9
  export { FilesAPI, type UploadFileOptions } from './api/files';
10
- export { AgentsAPI, Agent, type AgentOptions, type SendMessageOptions, type AgentRunOptions } from './api/agents';
10
+ export { AgentsAPI, Agent, type AgentOptions, type SendMessageOptions, type AgentRunOptions, type AgentDelta } from './api/agents';
11
11
  export { SessionsAPI } from './api/sessions';
12
12
  export { AppsAPI } from './api/apps';
13
13
  export { ChatsAPI } from './api/chats';
@@ -32,6 +32,7 @@ export { parseStatus, isTerminalStatus, isChatBusy, pendingApprovals } from './u
32
32
  export type { PendingApproval } from './utils';
33
33
  export * from './types';
34
34
  export type { TaskDTO as Task } from './types';
35
+ export type { CredentialDTO as IntegrationDTO, CredentialConfigDTO as IntegrationConfigDTO, CredentialConnectRequest as IntegrationConnectRequest, CredentialConnectResponse as IntegrationConnectResponse, CredentialCompleteOAuthRequest as IntegrationCompleteOAuthRequest, CredentialRequirement as IntegrationRequirement, CredentialStatus as IntegrationStatus, CredentialScope as IntegrationScope, CredentialGrant as IntegrationGrant, CredentialType as IntegrationAuthType, CredentialProvider as IntegrationProvider, } from './types';
35
36
  import { HttpClient, type HttpClientConfig } from './http/client';
36
37
  import { TasksAPI, RunOptions } from './api/tasks';
37
38
  import { FilesAPI, UploadFileOptions } from './api/files';
@@ -71,6 +72,11 @@ export interface InferenceConfig {
71
72
  * Polling interval in milliseconds when stream is false (default: 2000).
72
73
  */
73
74
  pollIntervalMs?: number;
75
+ /**
76
+ * fetch() credentials mode. Defaults to 'omit' with an apiKey and 'include'
77
+ * for proxyUrl / getToken flows that rely on cookies.
78
+ */
79
+ credentials?: RequestCredentials;
74
80
  }
75
81
  /**
76
82
  * Inference.sh SDK Client