@inferencesh/sdk 0.6.50 → 0.6.51

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.
@@ -1,7 +1,38 @@
1
1
  import { StreamableManager } from '../http/streamable';
2
2
  import { PollManager } from '../http/poll';
3
- import { ToolTypeClient, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, } from '../types';
3
+ import { ChatMessageStatusCancelled, ChatMessageStatusFailed, ChatMessageStatusReady, ToolTypeClient, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, } from '../types';
4
4
  import { isChatBusy } from '../utils';
5
+ const terminalMessageStatuses = new Set([ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled]);
6
+ /**
7
+ * Decides when one sendMessage() turn is over.
8
+ *
9
+ * For an existing chat the stream/poll is opened before the POST so nothing is
10
+ * missed, but its first snapshot is the previous turn's idle state. Resolving on
11
+ * that made sendMessage return before the new run had started. An idle snapshot
12
+ * only counts once the chat was seen busy, or once this turn's assistant message
13
+ * reached a terminal status (runs that finish between two observations).
14
+ */
15
+ class TurnGate {
16
+ constructor(existingChat) {
17
+ this.existingChat = existingChat;
18
+ this.assistantMessageId = null;
19
+ this.sawBusy = false;
20
+ this.assistantDone = false;
21
+ }
22
+ observeChat(chat) {
23
+ if (isChatBusy(chat))
24
+ this.sawBusy = true;
25
+ }
26
+ observeMessage(message) {
27
+ if (message.id === this.assistantMessageId && terminalMessageStatuses.has(message.status)) {
28
+ this.assistantDone = true;
29
+ }
30
+ }
31
+ /** Whether an idle observation may end the turn. */
32
+ get settled() {
33
+ return !this.existingChat || this.sawBusy || this.assistantDone;
34
+ }
35
+ }
5
36
  /**
6
37
  * Agent for chat interactions
7
38
  *
@@ -68,17 +99,28 @@ export class Agent {
68
99
  };
69
100
  const useStream = options.stream ?? this.http.getStreamDefault();
70
101
  const shouldWait = useStream === false || hasCallbacks;
102
+ const gate = new TurnGate(!!this.chatId);
71
103
  const waitFn = useStream === false
72
- ? (opts) => this.pollUntilIdle(opts)
73
- : (opts) => this.streamUntilIdle(opts);
104
+ ? (opts) => this.pollUntilIdle(opts, gate)
105
+ : (opts) => this.streamUntilIdle(opts, gate);
74
106
  // For existing chats: Start waiting BEFORE POST so we don't miss updates
75
107
  let waitPromise = null;
76
108
  if (this.chatId && shouldWait) {
77
109
  waitPromise = waitFn(options);
78
110
  }
79
111
  // Make the POST request
80
- const resp = await this.http.request('post', '/agents/run', { data: body });
81
- const response = resp.data;
112
+ let response;
113
+ try {
114
+ const resp = await this.http.request('post', '/agents/run', { data: body });
115
+ response = resp.data;
116
+ }
117
+ catch (err) {
118
+ // Nothing to wait for; don't leave the pre-opened stream/poller running.
119
+ if (waitPromise)
120
+ this.disconnect();
121
+ throw err;
122
+ }
123
+ gate.assistantMessageId = response.assistant_message?.id ?? null;
82
124
  // For new chats: Set chatId and start waiting immediately after POST
83
125
  const isNewChat = !this.chatId && response.assistant_message.chat_id;
84
126
  if (isNewChat) {
@@ -145,10 +187,10 @@ export class Agent {
145
187
  startStreaming(options = {}) {
146
188
  if (!this.chatId)
147
189
  return;
148
- this.streamUntilIdle(options);
190
+ this.streamUntilIdle(options, new TurnGate(false));
149
191
  }
150
192
  /** Stream events until chat becomes idle */
151
- streamUntilIdle(options) {
193
+ streamUntilIdle(options, gate) {
152
194
  if (!this.chatId)
153
195
  return Promise.resolve();
154
196
  const { url, headers, credentials } = this.http.getStreamableConfig(`/chats/${this.chatId}/stream`);
@@ -159,21 +201,37 @@ export class Agent {
159
201
  headers,
160
202
  credentials,
161
203
  });
204
+ // Last chat/run observation was idle but the gate wasn't settled yet;
205
+ // a terminal message for this turn can settle it.
206
+ let idlePending = false;
207
+ const onIdle = () => {
208
+ if (gate.settled)
209
+ resolve();
210
+ else
211
+ idlePending = true;
212
+ };
162
213
  this.stream.addEventListener('chats', (chat) => {
163
214
  options.onChat?.(chat);
164
- if (!isChatBusy(chat)) {
165
- resolve();
166
- }
215
+ gate.observeChat(chat);
216
+ if (!isChatBusy(chat))
217
+ onIdle();
218
+ else
219
+ idlePending = false;
167
220
  });
168
221
  this.stream.addEventListener('agent_runs', (run) => {
169
222
  const asChat = { active_run: run };
170
223
  options.onChat?.(asChat);
171
- if (!isChatBusy(asChat)) {
172
- resolve();
173
- }
224
+ gate.observeChat(asChat);
225
+ if (!isChatBusy(asChat))
226
+ onIdle();
227
+ else
228
+ idlePending = false;
174
229
  });
175
230
  this.stream.addEventListener('chat_messages', (message) => {
231
+ gate.observeMessage(message);
176
232
  options.onMessage?.(message);
233
+ if (idlePending && gate.settled)
234
+ resolve();
177
235
  if (message.tool_invocations && options.onToolCall) {
178
236
  for (const inv of message.tool_invocations) {
179
237
  if (this.dispatchedToolCalls.has(inv.id))
@@ -193,7 +251,7 @@ export class Agent {
193
251
  });
194
252
  }
195
253
  /** Poll until chat becomes idle, dispatching callbacks on changes */
196
- pollUntilIdle(options) {
254
+ pollUntilIdle(options, gate) {
197
255
  if (!this.chatId)
198
256
  return Promise.resolve();
199
257
  const intervalMs = options.pollIntervalMs ?? this.http.getPollIntervalMs();
@@ -206,7 +264,9 @@ export class Agent {
206
264
  // Lightweight status check first
207
265
  const statusResp = await this.http.request('get', `/chats/${this.chatId}/status`);
208
266
  const status = statusResp.data;
209
- if (status.status === prevStatus) {
267
+ // Unchanged status is skipped — unless the turn is still ungated: a run
268
+ // that started and finished between two polls only shows in the messages.
269
+ if (status.status === prevStatus && gate.settled) {
210
270
  // No change — return a stub to skip processing
211
271
  return { status: status.status };
212
272
  }
@@ -220,6 +280,9 @@ export class Agent {
220
280
  return;
221
281
  prevStatus = chat.status;
222
282
  options.onChat?.(chat);
283
+ gate.observeChat(chat);
284
+ for (const message of chat.chat_messages ?? [])
285
+ gate.observeMessage(message);
223
286
  // Dispatch new/updated messages
224
287
  if (chat.chat_messages && options.onMessage) {
225
288
  for (const message of chat.chat_messages) {
@@ -248,7 +311,7 @@ export class Agent {
248
311
  }
249
312
  }
250
313
  }
251
- if (!isChatBusy(chat)) {
314
+ if (!isChatBusy(chat) && gate.settled) {
252
315
  this.poller?.stop();
253
316
  this.poller = null;
254
317
  resolve();
@@ -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
@@ -71,6 +71,11 @@ export interface InferenceConfig {
71
71
  * Polling interval in milliseconds when stream is false (default: 2000).
72
72
  */
73
73
  pollIntervalMs?: number;
74
+ /**
75
+ * fetch() credentials mode. Defaults to 'omit' with an apiKey and 'include'
76
+ * for proxyUrl / getToken flows that rely on cookies.
77
+ */
78
+ credentials?: RequestCredentials;
74
79
  }
75
80
  /**
76
81
  * Inference.sh SDK Client
package/dist/types.d.ts CHANGED
@@ -2709,6 +2709,11 @@ export interface MenuItem {
2709
2709
  id: string;
2710
2710
  label: string;
2711
2711
  slug?: string;
2712
+ /**
2713
+ * Path is the linked page's path, filled in when a menu is read so a client
2714
+ * can build the link without fetching each page. Never stored.
2715
+ */
2716
+ path?: string;
2712
2717
  page_id?: string;
2713
2718
  url?: string;
2714
2719
  icon?: string;
@@ -2729,6 +2734,7 @@ export interface PageDTO extends BaseModelDTO, PermissionModelDTO {
2729
2734
  type: PageType;
2730
2735
  metadata: PageMetadata;
2731
2736
  slug: string;
2737
+ path: string;
2732
2738
  /**
2733
2739
  * PublishAt mirrors Metadata.PublishAt, which remains the field clients write.
2734
2740
  * Surfaced here so a reader does not have to reach into the metadata blob.
@@ -4381,6 +4387,11 @@ export type RefRouteType = string;
4381
4387
  export declare const RefRouteTypeApp: RefRouteType;
4382
4388
  export declare const RefRouteTypeAgent: RefRouteType;
4383
4389
  export declare const RefRouteTypeSkill: RefRouteType;
4390
+ /**
4391
+ * RefRouteTypeURL routes a site path to another (/docs/api-files →
4392
+ * /docs/api/sdk/files). Alias and target are literal paths, not refs.
4393
+ */
4394
+ export declare const RefRouteTypeURL: RefRouteType;
4384
4395
  export type RefRouteMode = string;
4385
4396
  export declare const RefRouteModeRewrite: RefRouteMode;
4386
4397
  export declare const RefRouteModeRedirect: RefRouteMode;
package/dist/types.js CHANGED
@@ -678,6 +678,11 @@ export const TeamInviteStatusRevoked = "revoked";
678
678
  export const RefRouteTypeApp = "app";
679
679
  export const RefRouteTypeAgent = "agent";
680
680
  export const RefRouteTypeSkill = "skill";
681
+ /**
682
+ * RefRouteTypeURL routes a site path to another (/docs/api-files →
683
+ * /docs/api/sdk/files). Alias and target are literal paths, not refs.
684
+ */
685
+ export const RefRouteTypeURL = "url";
681
686
  export const RefRouteModeRewrite = "rewrite";
682
687
  export const RefRouteModeRedirect = "redirect";
683
688
  export const KnowledgeTypeConcept = "concept";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inferencesh/sdk",
3
- "version": "0.6.50",
3
+ "version": "0.6.51",
4
4
  "description": "Official JavaScript/TypeScript SDK for inference.sh - Run AI models with a simple API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",