@inferencesh/sdk 0.28.0 → 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.29.0] - 2026-10-17
11
+
12
+ ### Removed
13
+ - `CredentialConfigDTO.provider_info` is gone: read `company` (INF-1079). The API stopped sending it in api-v1313.
14
+
15
+ ### Changed
16
+ - `CredentialConfigDTO.auth_scheme_id` is `auth_provider_id`, matching the API (INF-1079).
17
+ - Generated types follow the API: engine release targets (`client.engines.updateBinary` takes a release target, `releases()` lists channel heads), `EngineDTO.capabilities` (`EngineCapability`, `EngineCapabilities`), `ChatMessageDTO.compaction_meta`.
18
+
19
+ ### Fixed
20
+ - Partial chat and run stream updates merge instead of replacing, and streamed text never blinks back to an older copy.
21
+ - A read that got no response is sent again, twice.
22
+
10
23
  ## [0.28.0] - 2026-10-15
11
24
 
12
25
  ### Changed
@@ -12,6 +12,7 @@ import { createLLMDeltaAccumulator } from '../delta.js';
12
12
  import { isAdHocConfig, extractClientToolHandlers } from './types.js';
13
13
  import * as api from './api.js';
14
14
  import { buildMCPInputResult } from './mcp-input.js';
15
+ import { applyChatUpdate } from './reducer.js';
15
16
  import { isInferenceError } from '../http/errors.js';
16
17
  // =============================================================================
17
18
  // Action Creators
@@ -226,11 +227,16 @@ export function createActions(ctx) {
226
227
  },
227
228
  });
228
229
  // Listen for Chat object updates (status changes only — don't replace messages)
229
- manager.addEventListener('chats', (chatData) => {
230
- dispatch({ type: 'UPDATE_CHAT', payload: chatData });
231
- if (chatData) {
232
- callbacks.onStatusChange?.(isChatBusy(chatData) ? 'streaming' : 'idle');
233
- checkTurnEnd(chatData);
230
+ manager.addEventListener('chats', (chatData, fields) => {
231
+ if (!chatData)
232
+ return;
233
+ dispatch({ type: 'UPDATE_CHAT', payload: chatData, fields });
234
+ // A partial update (a plan step writing agent_data) says nothing about
235
+ // the turn on its own: judge the chat it merges into.
236
+ const chat = applyChatUpdate(getState().chat, chatData, fields);
237
+ if (chat) {
238
+ callbacks.onStatusChange?.(isChatBusy(chat) ? 'streaming' : 'idle');
239
+ checkTurnEnd(chat);
234
240
  }
235
241
  });
236
242
  // Listen for ChatMessage updates
@@ -244,8 +250,11 @@ export function createActions(ctx) {
244
250
  updateMessage(message, fields);
245
251
  });
246
252
  // Listen for AgentRun updates (state transitions, output)
247
- manager.addEventListener('agent_runs', (run) => {
248
- dispatch({ type: 'UPDATE_ACTIVE_RUN', payload: run });
253
+ manager.addEventListener('agent_runs', (run, fields) => {
254
+ dispatch({ type: 'UPDATE_ACTIVE_RUN', payload: run, fields });
255
+ // A partial update (the run's output) carries no state.
256
+ if (fields)
257
+ return;
249
258
  callbacks.onStatusChange?.(isRunWorking(run.state) || isRunInterrupted(run.state) ? 'streaming' : 'idle');
250
259
  const currentChat = getState().chat;
251
260
  if (currentChat)
@@ -566,6 +575,7 @@ export function createActions(ctx) {
566
575
  throw error;
567
576
  }
568
577
  },
578
+ listRunInterrupts: (runId) => api.listRunInterrupts(client, runId),
569
579
  loadOlderMessages: async () => {
570
580
  const chatId = getChatId();
571
581
  const cursor = getState().messageCursor;
@@ -3,6 +3,12 @@
3
3
  *
4
4
  * Pure reducer for managing agent chat state.
5
5
  */
6
+ import type { ChatDTO } from '../types.js';
6
7
  import type { AgentChatState, ChatAction } from './types.js';
8
+ /**
9
+ * The chat after a chats event: replaced by a full one, merged with a partial
10
+ * one. A partial update to another chat (or before any chat) is dropped.
11
+ */
12
+ export declare function applyChatUpdate(existing: ChatDTO | null, update: ChatDTO, fields?: string[]): ChatDTO | null;
7
13
  export declare const initialState: AgentChatState;
8
14
  export declare function chatReducer(state: AgentChatState, action: ChatAction): AgentChatState;
@@ -4,7 +4,7 @@
4
4
  * Pure reducer for managing agent chat state.
5
5
  */
6
6
  import { ChatStatusBusy, ChatStatusAwaitingInput, ChatStatusIdle } from '../types.js';
7
- import { isRunInterrupted, isRunWorking } from '../utils.js';
7
+ import { isMessageTerminal, isRunInterrupted, isRunWorking } from '../utils.js';
8
8
  function deriveChatStatus(run) {
9
9
  if (!run)
10
10
  return ChatStatusIdle;
@@ -14,6 +14,38 @@ function deriveChatStatus(run) {
14
14
  return ChatStatusAwaitingInput;
15
15
  return ChatStatusIdle;
16
16
  }
17
+ /**
18
+ * A partial stream update (`fields` set) carries only the fields it names, so
19
+ * it merges into the object it updates instead of replacing it: a chat update
20
+ * naming only agent_data (a plan step) keeps the chat's status and active run.
21
+ * A named field missing from the payload was cleared (omitempty).
22
+ */
23
+ function mergeFields(existing, update, fields) {
24
+ const merged = { ...existing };
25
+ for (const field of fields)
26
+ merged[field] = update[field];
27
+ return merged;
28
+ }
29
+ /**
30
+ * The chat after a chats event: replaced by a full one, merged with a partial
31
+ * one. A partial update to another chat (or before any chat) is dropped.
32
+ */
33
+ export function applyChatUpdate(existing, update, fields) {
34
+ if (!fields)
35
+ return update;
36
+ if (!existing || existing.id !== update.id)
37
+ return existing;
38
+ const merged = mergeFields(existing, update, fields);
39
+ // The projector's update names active_run_id, which ChatDTO does not
40
+ // declare. The run object belongs to that id: a new or cleared active run
41
+ // drops it until the run's own event arrives.
42
+ if (fields.includes('active_run_id')) {
43
+ const runId = update.active_run_id;
44
+ if (merged.active_run && merged.active_run.id !== runId)
45
+ merged.active_run = undefined;
46
+ }
47
+ return merged;
48
+ }
17
49
  /**
18
50
  * Every message enters state through here. The API serializes a message with
19
51
  * no content as `content: null` (a nil Go slice), and a partial stream update
@@ -27,6 +59,28 @@ function normalizeMessage(message, existing) {
27
59
  return message;
28
60
  return { ...message, content: existing?.content ?? [] };
29
61
  }
62
+ /**
63
+ * Streamed text only grows until the message is done. Deltas build the text
64
+ * locally, while a message update carries the server's saved copy, which can
65
+ * lag behind them (often still empty). Taking that copy as-is blanks the text
66
+ * until the next delta, so while the message is still generating, a text
67
+ * that is an earlier version of what is shown keeps what is shown. Once the
68
+ * message is terminal the server's copy is final and wins.
69
+ */
70
+ function keepStreamedText(updated, existing) {
71
+ if (isMessageTerminal(updated.status))
72
+ return updated;
73
+ const shown = existing.content.find((c) => c.type === 'text')?.text;
74
+ if (!shown)
75
+ return updated;
76
+ const incoming = updated.content.find((c) => c.type === 'text');
77
+ if (incoming?.text && !shown.startsWith(incoming.text))
78
+ return updated;
79
+ const content = incoming
80
+ ? updated.content.map((c) => (c === incoming ? { ...c, text: shown } : c))
81
+ : [{ type: 'text', text: shown }, ...updated.content];
82
+ return { ...updated, content };
83
+ }
30
84
  const normalizeMessages = (messages) => messages.map((m) => normalizeMessage(m));
31
85
  // =============================================================================
32
86
  // Initial State
@@ -59,10 +113,10 @@ export function chatReducer(state, action) {
59
113
  }
60
114
  case 'UPDATE_CHAT': {
61
115
  // Update chat metadata without replacing messages
62
- const chat = action.payload;
63
- if (!chat)
116
+ if (!action.payload)
64
117
  return state;
65
- return { ...state, chat };
118
+ const chat = applyChatUpdate(state.chat, action.payload, action.fields);
119
+ return chat === state.chat ? state : { ...state, chat };
66
120
  }
67
121
  // The settings and set-agent endpoints answer with only what they wrote.
68
122
  // Merge it into the chat it belongs to; a chat switched away from in the
@@ -104,7 +158,15 @@ export function chatReducer(state, action) {
104
158
  case 'UPDATE_ACTIVE_RUN': {
105
159
  if (!state.chat)
106
160
  return state;
107
- return { ...state, chat: { ...state.chat, active_run: action.payload, status: deriveChatStatus(action.payload) } };
161
+ let run = action.payload;
162
+ if (action.fields) {
163
+ // A partial update (the run's output) needs the run it belongs to.
164
+ const existing = state.chat.active_run;
165
+ if (!existing || existing.id !== run.id)
166
+ return state;
167
+ run = mergeFields(existing, run, action.fields);
168
+ }
169
+ return { ...state, chat: { ...state.chat, active_run: run, status: deriveChatStatus(run) } };
108
170
  }
109
171
  case 'SET_MESSAGES':
110
172
  return { ...state, messages: normalizeMessages(action.payload) };
@@ -120,9 +182,7 @@ export function chatReducer(state, action) {
120
182
  const existingIndex = state.messages.findIndex((m) => m.id === message.id);
121
183
  if (existingIndex !== -1) {
122
184
  const existing = state.messages[existingIndex];
123
- const updated = action.partial
124
- ? normalizeMessage({ ...existing, ...message }, existing)
125
- : normalizeMessage(message);
185
+ const updated = keepStreamedText(action.partial ? normalizeMessage({ ...existing, ...message }, existing) : normalizeMessage(message), existing);
126
186
  if (existing === updated)
127
187
  return state;
128
188
  const newMessages = [...state.messages];
@@ -148,6 +208,10 @@ export function chatReducer(state, action) {
148
208
  if (!target)
149
209
  return state;
150
210
  const textBlock = target.content.find(c => c.type === 'text');
211
+ // Deltas from a stream joined mid-message start partway; the message
212
+ // update already showed more, so keep it until they catch up.
213
+ if (textBlock?.text && textBlock.text.startsWith(output.response ?? ''))
214
+ return state;
151
215
  const newContent = textBlock
152
216
  ? target.content.map(c => c.type === 'text' ? { ...c, text: output.response } : c)
153
217
  : [{ type: 'text', text: output.response }, ...target.content];
@@ -4,7 +4,7 @@
4
4
  * Public types for the Agent chat module.
5
5
  */
6
6
  import type { Dispatch } from 'react';
7
- import type { AgentRunDTO, AgentVersionDTO, AlwaysAllowOptionsDTO, AlwaysAllowResultDTO, ToolExplanationDTO, ChatAgentDTO, ChatDTO, ChatMessageDTO, ChatSettingsDTO, ChatSettingsRequest, AgentTool, AgentConfigInput as GeneratedAgentConfig, CoreAppConfigInput as CoreAppConfig, FileRef, ElicitResult } from '../types.js';
7
+ import type { AgentRunDTO, AgentVersionDTO, AlwaysAllowOptionsDTO, AlwaysAllowResultDTO, ToolExplanationDTO, ChatAgentDTO, ChatDTO, ChatMessageDTO, ChatSettingsDTO, ChatSettingsRequest, AgentTool, AgentConfigInput as GeneratedAgentConfig, CoreAppConfigInput as CoreAppConfig, FileRef, ElicitResult, InterruptDTO } from '../types.js';
8
8
  import type { HttpClient } from '../http/client.js';
9
9
  import type { ClientToolResult } from '../tool-builder.js';
10
10
  import type { StreamableManager } from '../http/streamable.js';
@@ -190,6 +190,8 @@ export interface AgentChatActions {
190
190
  * `requires_sign_in` (ErrorCodeRequiresSignIn).
191
191
  */
192
192
  resolveInterrupt: (interruptId: string, decision: 'allow' | 'deny') => Promise<void>;
193
+ /** A run's pending interrupts (`heldTurn` finds a held turn among them). */
194
+ listRunInterrupts: (runId: string) => Promise<InterruptDTO[]>;
193
195
  /** Load older messages (scroll-up pagination). Returns true if more exist. */
194
196
  loadOlderMessages: () => Promise<boolean>;
195
197
  /** Whether there are older messages to load */
@@ -261,6 +263,7 @@ export type ChatAction = {
261
263
  } | {
262
264
  type: 'UPDATE_CHAT';
263
265
  payload: ChatDTO | null;
266
+ fields?: string[];
264
267
  } | {
265
268
  type: 'MERGE_CHAT_SETTINGS';
266
269
  payload: ChatSettingsDTO;
@@ -270,6 +273,7 @@ export type ChatAction = {
270
273
  } | {
271
274
  type: 'UPDATE_ACTIVE_RUN';
272
275
  payload: AgentRunDTO;
276
+ fields?: string[];
273
277
  } | {
274
278
  type: 'SET_MESSAGES';
275
279
  payload: ChatMessageDTO[];
@@ -1,7 +1,7 @@
1
1
  import { HttpClient } from '../http/client.js';
2
2
  import type { Response } from '../http/response.js';
3
3
  import type { EngineUpdateBody } from './write-bodies.js';
4
- import { EngineDTO as Engine, CursorListRequest, CursorListResponse } from '../types.js';
4
+ import { EngineDTO as Engine, EngineReleasesResponse, CursorListRequest, CursorListResponse } from '../types.js';
5
5
  /**
6
6
  * Engines API
7
7
  */
@@ -65,8 +65,16 @@ export declare class EnginesAPI {
65
65
  */
66
66
  drain(engineId: string): Promise<Response<void>>;
67
67
  /**
68
- * Update an engine binary (drain + restart with new version)
68
+ * Update an engine binary: it drains, installs the release and restarts.
69
+ * `version` is "stable" (the default: newest stable, lifting any pin),
70
+ * "canary" (the current canary build, pinned), or a version such as
71
+ * v1.9.3 (pinned). A pinned engine stays on its version until sent
72
+ * "stable" again.
69
73
  */
70
- updateBinary(engineId: string): Promise<Response<void>>;
74
+ updateBinary(engineId: string, version?: string): Promise<Response<void>>;
75
+ /**
76
+ * The head of each engine release channel (stable, canary) on dist.inference.sh.
77
+ */
78
+ releases(): Promise<Response<EngineReleasesResponse>>;
71
79
  }
72
80
  export declare function createEnginesAPI(http: HttpClient): EnginesAPI;
@@ -85,10 +85,21 @@ export class EnginesAPI {
85
85
  return this.http.request('post', `/engines/${engineId}/drain`);
86
86
  }
87
87
  /**
88
- * Update an engine binary (drain + restart with new version)
88
+ * Update an engine binary: it drains, installs the release and restarts.
89
+ * `version` is "stable" (the default: newest stable, lifting any pin),
90
+ * "canary" (the current canary build, pinned), or a version such as
91
+ * v1.9.3 (pinned). A pinned engine stays on its version until sent
92
+ * "stable" again.
89
93
  */
90
- async updateBinary(engineId) {
91
- return this.http.request('post', `/engines/${engineId}/update`);
94
+ async updateBinary(engineId, version) {
95
+ const body = version ? { version } : {};
96
+ return this.http.request('post', `/engines/${engineId}/update`, { data: body });
97
+ }
98
+ /**
99
+ * The head of each engine release channel (stable, canary) on dist.inference.sh.
100
+ */
101
+ async releases() {
102
+ return this.http.request('get', '/engines/releases');
92
103
  }
93
104
  }
94
105
  export function createEnginesAPI(http) {
package/dist/api/tasks.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { streamUntilTerminal } from '../http/stream-until-terminal.js';
2
2
  import { PollManager } from '../http/poll.js';
3
- import { TaskStatusCompleted, TaskStatusFailed, TaskStatusCancelled, } from '../types.js';
3
+ import { TaskStatusCompleted, TaskStatusFailed, TaskStatusCancelled, TaskStatusRejected, } from '../types.js';
4
4
  import { parseStatus } from '../utils.js';
5
5
  //TODO: This is ugly...
6
6
  function stripTask(task) {
@@ -28,6 +28,9 @@ function settleTerminal(data, stripped, settle) {
28
28
  case TaskStatusCancelled:
29
29
  settle.reject(new Error('task cancelled'));
30
30
  break;
31
+ case TaskStatusRejected:
32
+ settle.reject(new Error(data.error || 'task rejected'));
33
+ break;
31
34
  }
32
35
  }
33
36
  /**
@@ -1,6 +1,40 @@
1
1
  import { InferenceError, RequirementsNotMetException } from './errors.js';
2
2
  import { EventSource } from 'eventsource';
3
3
  import { SDK_VERSION } from '../version.js';
4
+ /** How long to wait before each new try of a read that got no response. */
5
+ const NETWORK_RETRY_DELAYS_MS = [300, 1000];
6
+ /**
7
+ * fetch, sending a GET or HEAD that got no response again after each of
8
+ * NETWORK_RETRY_DELAYS_MS: a dropped connection or a network change fails a
9
+ * read that would succeed a moment later, and a read changes nothing on the
10
+ * server, so sending it again is safe. fetch rejects with a TypeError only
11
+ * when no response came; a response of any status, an abort, or a request
12
+ * of another method is the caller's at once.
13
+ */
14
+ function fetchRetryingReads(input, init, attempt = 0) {
15
+ const method = (init.method ?? 'GET').toUpperCase();
16
+ const read = method === 'GET' || method === 'HEAD';
17
+ const sent = fetch(input, init);
18
+ if (!read)
19
+ return sent;
20
+ return sent.catch(async (error) => {
21
+ const delay = NETWORK_RETRY_DELAYS_MS[attempt];
22
+ if (delay === undefined || !(error instanceof TypeError) || init.signal?.aborted)
23
+ throw error;
24
+ await wait(delay, init.signal);
25
+ return fetchRetryingReads(input, init, attempt + 1);
26
+ });
27
+ }
28
+ /** Resolves after ms, or rejects with the abort when signal aborts first. */
29
+ function wait(ms, signal) {
30
+ return new Promise((resolve, reject) => {
31
+ const timer = setTimeout(resolve, ms);
32
+ signal?.addEventListener('abort', () => {
33
+ clearTimeout(timer);
34
+ reject(signal.reason);
35
+ }, { once: true });
36
+ });
37
+ }
4
38
  /**
5
39
  * Low-level HTTP client for inference.sh API
6
40
  *
@@ -127,7 +161,7 @@ export class HttpClient {
127
161
  * (`refused: 'return'`), handed back with its body unread.
128
162
  */
129
163
  async fetchHandled(url, targetUrl, init, refused) {
130
- const send = (token) => fetch(url, {
164
+ const send = (token) => fetchRetryingReads(url, {
131
165
  ...init,
132
166
  headers: { ...init.headers, ...this.requestHeaders(targetUrl, token) },
133
167
  credentials: this.credentials,
@@ -213,7 +247,7 @@ export class HttpClient {
213
247
  if (options.data) {
214
248
  fetchOptions.body = JSON.stringify(options.data);
215
249
  }
216
- const response = await fetch(fetchUrl, fetchOptions);
250
+ const response = await fetchRetryingReads(fetchUrl, fetchOptions);
217
251
  const responseText = await response.text();
218
252
  let data = null;
219
253
  try {
package/dist/index.d.ts CHANGED
@@ -36,8 +36,8 @@ export type { ClientTool, ClientToolHandler, ClientToolResult } from './tool-bui
36
36
  export { lifecycleHook, learningHooks } from './hook-builder.js';
37
37
  export type { LifecycleHookBuilder } from './hook-builder.js';
38
38
  export { DeltaAccumulator, createLLMDeltaAccumulator, type DeltaEvent, type FieldTags, type FieldTagsRegistry } from './delta.js';
39
- export { parseStatus, isTerminalStatus, isChatBusy, isAwaitingHuman, isRunTerminal, isRunInterrupted, isRunSettled, isRunWorking, isMessageTerminal, pendingApprovals, } from './utils.js';
40
- export type { PendingApproval } from './utils.js';
39
+ export { parseStatus, isTerminalStatus, isChatBusy, isAwaitingHuman, isRunTerminal, isRunInterrupted, isRunSettled, isRunWorking, isMessageTerminal, pendingApprovals, heldTurn, } from './utils.js';
40
+ export type { PendingApproval, HeldTurn } from './utils.js';
41
41
  export * from './types.js';
42
42
  export type { TaskDTO as Task } from './types.js';
43
43
  import { HttpClient, type HttpClientConfig } from './http/client.js';
package/dist/index.js CHANGED
@@ -38,7 +38,7 @@ export { lifecycleHook, learningHooks } from './hook-builder.js';
38
38
  // Delta accumulator for streaming responses
39
39
  export { DeltaAccumulator, createLLMDeltaAccumulator } from './delta.js';
40
40
  // Status utilities (handle both int and string status values)
41
- export { parseStatus, isTerminalStatus, isChatBusy, isAwaitingHuman, isRunTerminal, isRunInterrupted, isRunSettled, isRunWorking, isMessageTerminal, pendingApprovals, } from './utils.js';
41
+ export { parseStatus, isTerminalStatus, isChatBusy, isAwaitingHuman, isRunTerminal, isRunInterrupted, isRunSettled, isRunWorking, isMessageTerminal, pendingApprovals, heldTurn, } from './utils.js';
42
42
  // Types - includes TaskStatus constants and all DTOs
43
43
  export * from './types.js';
44
44
  // =============================================================================
package/dist/types.d.ts CHANGED
@@ -1489,6 +1489,34 @@ export interface CredentialRequirement {
1489
1489
  * Auth is the credential's auth provider, for a slug no row defines yet.
1490
1490
  */
1491
1491
  auth?: AuthMethod;
1492
+ /**
1493
+ * The rest describe the platform api_key scheme a platform app's deploy
1494
+ * catalogues for the slug: set on the scheme it creates, and filled into
1495
+ * an existing one only where that is still empty (an admin's edit
1496
+ * stands). Any other deploy ignores them.
1497
+ * DisplayName is the scheme's name ("Claude Code"); at most
1498
+ * MaxCredentialDisplayName characters.
1499
+ */
1500
+ display_name?: string;
1501
+ /**
1502
+ * ConnectionScope is who a connection belongs to: team (empty) or user.
1503
+ */
1504
+ connection_scope?: CredentialScope;
1505
+ /**
1506
+ * Instructions tell a person how to get the key (markdown, at most
1507
+ * MaxAuthProviderInstructions characters).
1508
+ */
1509
+ instructions?: string;
1510
+ /**
1511
+ * DocsURL is the scheme's documentation link.
1512
+ */
1513
+ docs_url?: string;
1514
+ /**
1515
+ * ExpiresAfterDays is how long a saved key lasts: it counts as expired
1516
+ * this many days after it is saved. 0 is never; at most
1517
+ * MaxExpiresAfterDays.
1518
+ */
1519
+ expires_after_days?: number;
1492
1520
  }
1493
1521
  /**
1494
1522
  * CompanySeed is a provider (the company behind a credential) as an app
@@ -1629,7 +1657,7 @@ export interface AppVersionDTO extends BaseModelDTO {
1629
1657
  export interface DeployWarning {
1630
1658
  /**
1631
1659
  * Code identifies the check: readonly_broad_credential,
1632
- * unused_credential, missing_annotations.
1660
+ * unused_credential, missing_annotations, unapproved_platform_scope.
1633
1661
  */
1634
1662
  code: string;
1635
1663
  /**
@@ -1791,6 +1819,32 @@ export interface ArtifactVersionDTO extends BaseModelDTO {
1791
1819
  [key: string]: any;
1792
1820
  };
1793
1821
  created_by_user_id?: string;
1822
+ /**
1823
+ * Files are the pages and data served beside the index page.
1824
+ */
1825
+ files?: ArtifactVersionFileDTO[];
1826
+ }
1827
+ /**
1828
+ * ArtifactVersionFileDTO is one file published beside a version's index.
1829
+ */
1830
+ export interface ArtifactVersionFileDTO {
1831
+ path: string;
1832
+ size_bytes: number;
1833
+ content_type: string;
1834
+ }
1835
+ /**
1836
+ * ArtifactFileInput is one extra file in a publish, served at Path relative
1837
+ * to the index page: another page (.html, .md), or css, js, json, svg, txt,
1838
+ * xml, csv.
1839
+ */
1840
+ export interface ArtifactFileInput {
1841
+ path: string;
1842
+ content: string;
1843
+ /**
1844
+ * ContentEncoding is "base64" when Content is base64-encoded, as for the
1845
+ * main content.
1846
+ */
1847
+ content_encoding?: string;
1794
1848
  }
1795
1849
  /**
1796
1850
  * ArtifactCreateRequest is the body for POST /artifacts. Creates the entry
@@ -1816,6 +1870,11 @@ export interface ArtifactCreateRequest {
1816
1870
  * from browsers and CLIs: edge firewalls reject raw <script> in JSON bodies.
1817
1871
  */
1818
1872
  content_encoding?: string;
1873
+ /**
1874
+ * Files are published beside the index page. A publish is the whole
1875
+ * site: files of the previous version are not carried over.
1876
+ */
1877
+ files?: ArtifactFileInput[];
1819
1878
  label?: string;
1820
1879
  notes?: string;
1821
1880
  origin?: string;
@@ -1862,6 +1921,11 @@ export interface ArtifactPublishRequest {
1862
1921
  * ContentEncoding is "base64" when Content is base64-encoded UTF-8.
1863
1922
  */
1864
1923
  content_encoding?: string;
1924
+ /**
1925
+ * Files are published beside the index page. A publish is the whole
1926
+ * site: files of the previous version are not carried over.
1927
+ */
1928
+ files?: ArtifactFileInput[];
1865
1929
  label?: string;
1866
1930
  notes?: string;
1867
1931
  origin?: string;
@@ -1932,9 +1996,25 @@ export interface ArtifactDataRequest {
1932
1996
  [key: string]: any;
1933
1997
  };
1934
1998
  /**
1935
- * Limit caps a list; the server clamps it.
1999
+ * Limit caps a list; the server clamps it to 200.
1936
2000
  */
1937
2001
  limit?: number;
2002
+ /**
2003
+ * Cursor continues a list from the next_cursor of the page before.
2004
+ */
2005
+ cursor?: string;
2006
+ /**
2007
+ * Order is the list order: -updated_at (the default), updated_at,
2008
+ * -created_at or created_at.
2009
+ */
2010
+ order?: string;
2011
+ /**
2012
+ * Where keeps only documents whose top-level fields equal these values
2013
+ * (string, number, boolean, or null for a missing field).
2014
+ */
2015
+ where?: {
2016
+ [key: string]: any;
2017
+ };
1938
2018
  }
1939
2019
  /**
1940
2020
  * ArtifactDataListResponse is a page of documents from one collection.
@@ -1943,6 +2023,10 @@ export interface ArtifactDataListResponse {
1943
2023
  collection: string;
1944
2024
  documents: ArtifactDataDTO[];
1945
2025
  count: number;
2026
+ /**
2027
+ * NextCursor fetches the page after this one; empty on the last page.
2028
+ */
2029
+ next_cursor?: string;
1946
2030
  }
1947
2031
  /**
1948
2032
  * ArtifactViewerDTO is what the user capability tells a page about whoever
@@ -2277,6 +2361,10 @@ export interface ChatMessageDTO extends BaseModelDTO, PermissionModelDTO {
2277
2361
  tools?: Tool[];
2278
2362
  tool_call_id?: string;
2279
2363
  tool_invocations?: ToolInvocationDTO[];
2364
+ /**
2365
+ * CompactionMeta is what a compaction (role compaction) retired.
2366
+ */
2367
+ compaction_meta?: CompactionMeta;
2280
2368
  }
2281
2369
  /**
2282
2370
  * PolicyRuleDTO is one rule, typed form Kind[selector](specifier).
@@ -2529,6 +2617,12 @@ export interface CredentialDTO extends BaseModelDTO, PermissionModelDTO {
2529
2617
  account_identifier?: string;
2530
2618
  account_name?: string;
2531
2619
  scopes: StringSlice;
2620
+ /**
2621
+ * AllowedScopes, on an OAuth app row (grant credentials), is every
2622
+ * scope a login through it may request; absent when any scope may be
2623
+ * (a team's own client by default). Never set on a login.
2624
+ */
2625
+ allowed_scopes?: StringSlice;
2532
2626
  expires_at?: string;
2533
2627
  vault_id?: string;
2534
2628
  metadata?: {
@@ -2572,17 +2666,12 @@ export interface CredentialConfigDTO {
2572
2666
  slug: string;
2573
2667
  /**
2574
2668
  * Provider is the credential slug (what Credential.Provider stores):
2575
- * one way to authenticate. The company it belongs to is ProviderInfo.
2669
+ * one way to authenticate. The company it belongs to is Company.
2576
2670
  */
2577
2671
  provider: string;
2578
2672
  /**
2579
- * ProviderInfo is the company this slug belongs to, for grouping: the
2580
- * providers row its auth provider names, else the slug's own identity.
2581
- */
2582
- provider_info?: CompanySummary;
2583
- /**
2584
- * Company is ProviderInfo under its settled name (INF-1079); provider_info
2585
- * stays one release.
2673
+ * Company is the company this slug belongs to, for grouping: the
2674
+ * companies row its auth provider names, else the slug's own identity.
2586
2675
  */
2587
2676
  company?: CompanySummary;
2588
2677
  type: string;
@@ -2591,9 +2680,20 @@ export interface CredentialConfigDTO {
2591
2680
  description: string;
2592
2681
  icon_url?: string;
2593
2682
  how_it_works?: string[];
2683
+ /**
2684
+ * Instructions tell a person how to get what this credential asks for
2685
+ * (markdown, links allowed): the auth scheme's.
2686
+ */
2687
+ instructions?: string;
2594
2688
  docs_url?: string;
2595
2689
  secret_fields?: SecretFieldConfig[];
2596
2690
  allows_byok: boolean;
2691
+ /**
2692
+ * ExpiresAfterDays is how long a saved key lasts, in days: a key counts
2693
+ * as expired that long after it is saved (its credential's expires_at).
2694
+ * 0 is never.
2695
+ */
2696
+ expires_after_days?: number;
2597
2697
  available: boolean;
2598
2698
  has_managed: boolean;
2599
2699
  /**
@@ -2613,7 +2713,7 @@ export interface CredentialConfigDTO {
2613
2713
  * AuthProviderID is set when the provider is one the team defined
2614
2714
  * itself (models.AuthProvider), so the UI can offer edit and remove.
2615
2715
  */
2616
- auth_scheme_id?: string;
2716
+ auth_provider_id?: string;
2617
2717
  /**
2618
2718
  * Credential is the login used where no account is named: the caller's
2619
2719
  * own, else the workspace's default account.
@@ -2641,6 +2741,10 @@ export interface SecretFieldConfig {
2641
2741
  placeholder: string;
2642
2742
  sensitive: boolean;
2643
2743
  optional: boolean;
2744
+ /**
2745
+ * Pattern is the scheme field's pattern (shared.SecretField.Pattern).
2746
+ */
2747
+ pattern?: string;
2644
2748
  }
2645
2749
  /**
2646
2750
  * SearchRequest represents a search request.
@@ -2750,9 +2854,38 @@ export interface EngineDTO extends BaseModelDTO, PermissionModelDTO {
2750
2854
  api_url: string;
2751
2855
  status: EngineStatus;
2752
2856
  engine_version: string;
2857
+ /**
2858
+ * EnginePin is the version the engine is held on; empty follows stable.
2859
+ */
2860
+ engine_pin?: string;
2861
+ /**
2862
+ * Capabilities are what the engine last reported it can do.
2863
+ */
2864
+ capabilities?: EngineCapabilities;
2753
2865
  system_info?: SystemInfo;
2754
2866
  workers: (WorkerDTO | undefined)[];
2755
2867
  }
2868
+ /**
2869
+ * EngineUpdateRequest names the release an engine should install: "stable",
2870
+ * "canary", or a version such as v1.9.3. Empty is stable.
2871
+ */
2872
+ export interface EngineUpdateRequest {
2873
+ version?: string;
2874
+ }
2875
+ /**
2876
+ * EngineRelease is one published engine build.
2877
+ */
2878
+ export interface EngineRelease {
2879
+ version: string;
2880
+ release_date?: string;
2881
+ }
2882
+ /**
2883
+ * EngineReleasesResponse is the head of each engine release channel.
2884
+ */
2885
+ export interface EngineReleasesResponse {
2886
+ stable?: EngineRelease;
2887
+ canary?: EngineRelease;
2888
+ }
2756
2889
  /**
2757
2890
  * EngineSummary is a lightweight engine response embedded in tasks.
2758
2891
  */
@@ -2831,6 +2964,19 @@ export interface WorkerRAM {
2831
2964
  worker_id: string;
2832
2965
  total: number;
2833
2966
  }
2967
+ /**
2968
+ * EngineCapability is something an engine can do beyond the base contract
2969
+ * every engine meets. An engine reports the ones it has (EngineTelemetry);
2970
+ * a task lists the ones it needs (Task.Requires); the scheduler only sends
2971
+ * a task to an engine that has every one it needs.
2972
+ */
2973
+ export type EngineCapability = "egress_gateway";
2974
+ export declare const EngineCapabilityEgressGateway: EngineCapability;
2975
+ /**
2976
+ * EngineCapabilities is a set of capabilities, kept as a list. Nil and
2977
+ * empty are the same: nothing beyond the base contract.
2978
+ */
2979
+ export type EngineCapabilities = EngineCapability[];
2834
2980
  /**
2835
2981
  * EntitlementDTO for API responses
2836
2982
  */
@@ -2914,7 +3060,7 @@ export interface DecideEntitlementRequestRequest {
2914
3060
  * and APIError.Code on the legacy envelope. Clients branch on these, so a
2915
3061
  * code is a named const here, where it generates into models and the SDKs.
2916
3062
  */
2917
- export type ErrorCode = "invalid_request" | "validation_error" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "name_conflict" | "already_exists" | "not_configured" | "method_not_allowed" | "rate_limited" | "internal_error" | "team_role_required" | "blocked_by_usage_policy" | "last_owner" | "account_deactivated" | "account_banned" | "person_required" | "otp_required" | "requires_sign_in" | "insufficient_scope" | "invalid_scope" | "impersonation_reason_required" | "mcp_auth_expired" | "admin_session_required" | "admin_scopes_not_approved" | "cli_session_required" | "admin_required" | "same_admin_required" | "browser_session_required" | "invalid_ttl" | "admin_authenticator_required" | "limit_exceeded" | "feature_not_available" | "entitlement_unavailable" | "payment_required" | "payment_method_required" | "form_closed" | "already_submitted" | "already_claimed" | "already_entitled" | "request_open" | "invalid_code" | "already_processed" | "expired" | "code_confirmation_required" | "app_retired" | "app_maintenance" | "invalid_transition" | "SESSION_NOT_FOUND" | "SESSION_EXPIRED" | "SESSION_ENDED" | "WORKER_LEASED" | "APP_MISMATCH" | "VERSION_MISMATCH" | "agents_disabled" | "remote_offline" | "remote_timeout" | "harness_not_drivable" | "harness_too_old";
3063
+ export type ErrorCode = "invalid_request" | "validation_error" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "name_conflict" | "already_exists" | "not_configured" | "method_not_allowed" | "rate_limited" | "internal_error" | "requirements_not_met" | "team_role_required" | "blocked_by_usage_policy" | "last_owner" | "account_deactivated" | "account_banned" | "person_required" | "otp_required" | "requires_sign_in" | "insufficient_scope" | "invalid_scope" | "impersonation_reason_required" | "mcp_auth_expired" | "admin_session_required" | "admin_scopes_not_approved" | "cli_session_required" | "admin_required" | "same_admin_required" | "browser_session_required" | "invalid_ttl" | "admin_authenticator_required" | "limit_exceeded" | "feature_not_available" | "entitlement_unavailable" | "payment_required" | "payment_method_required" | "form_closed" | "already_submitted" | "already_claimed" | "already_entitled" | "request_open" | "invalid_code" | "already_processed" | "expired" | "code_confirmation_required" | "app_retired" | "app_maintenance" | "invalid_transition" | "SESSION_NOT_FOUND" | "SESSION_EXPIRED" | "SESSION_ENDED" | "WORKER_LEASED" | "APP_MISMATCH" | "VERSION_MISMATCH" | "agents_disabled" | "remote_offline" | "remote_timeout" | "harness_not_drivable" | "harness_too_old";
2918
3064
  export declare const ErrorCodeInvalidRequest: ErrorCode;
2919
3065
  export declare const ErrorCodeValidationError: ErrorCode;
2920
3066
  export declare const ErrorCodeUnauthorized: ErrorCode;
@@ -2927,6 +3073,12 @@ export declare const ErrorCodeNotConfigured: ErrorCode;
2927
3073
  export declare const ErrorCodeMethodNotAllowed: ErrorCode;
2928
3074
  export declare const ErrorCodeRateLimited: ErrorCode;
2929
3075
  export declare const ErrorCodeInternalError: ErrorCode;
3076
+ /**
3077
+ * ErrorCodeRequirementsNotMet (412): the run needs a secret or a
3078
+ * credential the caller has not set up. Meta "errors" lists each
3079
+ * RequirementError, its action saying how to set it up.
3080
+ */
3081
+ export declare const ErrorCodeRequirementsNotMet: ErrorCode;
2930
3082
  /**
2931
3083
  * ErrorCodeTeamRoleRequired: the caller's team role or org-admin status
2932
3084
  * does not allow the action. Meta is TeamRoleRequiredMeta when a
@@ -4620,6 +4772,11 @@ export interface SetupAction {
4620
4772
  * list comes from; sent back when the keys are saved.
4621
4773
  */
4622
4774
  provider_website?: string;
4775
+ /**
4776
+ * Instructions tell a person how to get what the provider's scheme
4777
+ * asks for (markdown, links allowed).
4778
+ */
4779
+ instructions?: string;
4623
4780
  }
4624
4781
  /**
4625
4782
  * CheckRequirementsRequest is the request body for checking requirements
@@ -5656,6 +5813,12 @@ export interface SecretField {
5656
5813
  placeholder?: string;
5657
5814
  sensitive?: boolean;
5658
5815
  optional?: boolean;
5816
+ /**
5817
+ * Pattern, when set, is a regular expression (RE2) a saved value must
5818
+ * match, so a pasted login link or the wrong key is refused on save
5819
+ * instead of failing the first run ("^sk-ant-oat01-").
5820
+ */
5821
+ pattern?: string;
5659
5822
  }
5660
5823
  /**
5661
5824
  * AuthMethodClientAuth is how client_id/client_secret reach the token
@@ -6547,6 +6710,12 @@ export declare const GraphEdgeTypeReferences: GraphEdgeType;
6547
6710
  export declare const GraphEdgeTypeSupersedes: GraphEdgeType;
6548
6711
  export declare const GraphEdgeTypeInput: GraphEdgeType;
6549
6712
  export declare const GraphEdgeTypeOutput: GraphEdgeType;
6713
+ /**
6714
+ * InterruptResourceTurn is an interrupt that holds a run's next turn before
6715
+ * its model call, with nothing in flight; its ResourceID is the run's. An
6716
+ * allow starts the turn, a deny ends the run.
6717
+ */
6718
+ export declare const InterruptResourceTurn: InterruptResourceType;
6550
6719
  /**
6551
6720
  * MergeStrategy defines how a delta field should be merged by consumers.
6552
6721
  */
@@ -7353,6 +7522,12 @@ export declare const TaskStatusUploading: TaskStatus;
7353
7522
  export declare const TaskStatusCompleted: TaskStatus;
7354
7523
  export declare const TaskStatusFailed: TaskStatus;
7355
7524
  export declare const TaskStatusCancelled: TaskStatus;
7525
+ /**
7526
+ * TaskStatusRejected is a run admission refused (no balance, no payment
7527
+ * method). The task is written already ended, keeping what was asked
7528
+ * for; it never ran and no status leads to it.
7529
+ */
7530
+ export declare const TaskStatusRejected: TaskStatus;
7356
7531
  /**
7357
7532
  * Infra defines where a task should run.
7358
7533
  */
@@ -7698,7 +7873,7 @@ export declare const InterruptResolutionDeny: InterruptResolution;
7698
7873
  /**
7699
7874
  * InterruptResourceType identifies the kind of resource an interrupt gates.
7700
7875
  */
7701
- export type InterruptResourceType = "tool_invocation" | "hook_event";
7876
+ export type InterruptResourceType = "turn" | "tool_invocation" | "hook_event";
7702
7877
  export declare const InterruptResourceToolInvocation: InterruptResourceType;
7703
7878
  export declare const InterruptResourceHookEvent: InterruptResourceType;
7704
7879
  /**
@@ -7835,6 +8010,16 @@ export interface ContextInjection {
7835
8010
  */
7836
8011
  items?: string[];
7837
8012
  }
8013
+ /**
8014
+ * CompactionMeta is stored on ChatMessage for context compaction markers.
8015
+ */
8016
+ export interface CompactionMeta {
8017
+ compacted_up_to_order: number;
8018
+ compacted_count: number;
8019
+ estimated_tokens: number;
8020
+ method?: string;
8021
+ analysis?: string;
8022
+ }
7838
8023
  /**
7839
8024
  * ToolCallEventData is the typed payload for agent.tool_call events.
7840
8025
  */
package/dist/types.js CHANGED
@@ -376,6 +376,7 @@ export const ToolRiskMedium = "medium";
376
376
  * ToolRiskHigh: dangerous or irreversible changes.
377
377
  */
378
378
  export const ToolRiskHigh = "high";
379
+ export const EngineCapabilityEgressGateway = "egress_gateway";
379
380
  export const ErrorCodeInvalidRequest = "invalid_request";
380
381
  export const ErrorCodeValidationError = "validation_error";
381
382
  export const ErrorCodeUnauthorized = "unauthorized";
@@ -388,6 +389,12 @@ export const ErrorCodeNotConfigured = "not_configured";
388
389
  export const ErrorCodeMethodNotAllowed = "method_not_allowed";
389
390
  export const ErrorCodeRateLimited = "rate_limited";
390
391
  export const ErrorCodeInternalError = "internal_error";
392
+ /**
393
+ * ErrorCodeRequirementsNotMet (412): the run needs a secret or a
394
+ * credential the caller has not set up. Meta "errors" lists each
395
+ * RequirementError, its action saying how to set it up.
396
+ */
397
+ export const ErrorCodeRequirementsNotMet = "requirements_not_met";
391
398
  /**
392
399
  * ErrorCodeTeamRoleRequired: the caller's team role or org-admin status
393
400
  * does not allow the action. Meta is TeamRoleRequiredMeta when a
@@ -979,6 +986,12 @@ export const GraphEdgeTypeReferences = "references";
979
986
  export const GraphEdgeTypeSupersedes = "supersedes";
980
987
  export const GraphEdgeTypeInput = "input";
981
988
  export const GraphEdgeTypeOutput = "output";
989
+ /**
990
+ * InterruptResourceTurn is an interrupt that holds a run's next turn before
991
+ * its model call, with nothing in flight; its ResourceID is the run's. An
992
+ * allow starts the turn, a deny ends the run.
993
+ */
994
+ export const InterruptResourceTurn = "turn";
982
995
  export const MergeStrategyConcat = "concat";
983
996
  export const MergeStrategyReplace = "replace";
984
997
  export const MergeStrategyIndexed = "indexed";
@@ -1454,6 +1467,12 @@ export const TaskStatusUploading = 9;
1454
1467
  export const TaskStatusCompleted = 10;
1455
1468
  export const TaskStatusFailed = 11;
1456
1469
  export const TaskStatusCancelled = 12;
1470
+ /**
1471
+ * TaskStatusRejected is a run admission refused (no balance, no payment
1472
+ * method). The task is written already ended, keeping what was asked
1473
+ * for; it never ran and no status leads to it.
1474
+ */
1475
+ export const TaskStatusRejected = 13;
1457
1476
  export const InfraPrivate = "private";
1458
1477
  export const InfraCloud = "cloud";
1459
1478
  export const InfraPrivateFirst = "private_first";
package/dist/utils.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  * Status utilities for handling both int and string-based status values.
3
3
  * Provides future compatibility when API migrates from int to string status.
4
4
  */
5
+ import type { InterruptDTO } from './types.js';
5
6
  import { TaskStatus } from './types.js';
6
7
  import type { AgentRunState, ChatDTO, ChatMessageStatus } from './types.js';
7
8
  /**
@@ -10,7 +11,7 @@ import type { AgentRunState, ChatDTO, ChatMessageStatus } from './types.js';
10
11
  */
11
12
  export declare function parseStatus(status: number | string | undefined | null): TaskStatus;
12
13
  /**
13
- * Check if a task status is terminal (completed, failed, or cancelled).
14
+ * Check if a task status is terminal (completed, failed, cancelled, or rejected).
14
15
  * Handles both int and string status values.
15
16
  */
16
17
  export declare function isTerminalStatus(status: number | string | undefined | null): boolean;
@@ -39,3 +40,12 @@ export type PendingApproval = {
39
40
  * which the API projects onto the chat, so no message scan is needed.
40
41
  */
41
42
  export declare function pendingApprovals(chat: ChatDTO | null | undefined): PendingApproval[];
43
+ /** A run's next turn held for the person (InterruptResourceTurn): after a long stretch without them, it waits for "keep going" (allow) or "stop" (deny). */
44
+ export type HeldTurn = {
45
+ interruptId: string;
46
+ runId: string;
47
+ /** Steps the run took without the person, when the api says. */
48
+ steps: number | null;
49
+ };
50
+ /** The held turn among a run's pending interrupts, if one is held. */
51
+ export declare function heldTurn(interrupts: InterruptDTO[] | null | undefined): HeldTurn | null;
package/dist/utils.js CHANGED
@@ -2,8 +2,8 @@
2
2
  * Status utilities for handling both int and string-based status values.
3
3
  * Provides future compatibility when API migrates from int to string status.
4
4
  */
5
- import { InterruptReasonToolApproval, InterruptStatusPending } from './types.js';
6
- import { TaskStatusUnknown, TaskStatusReceived, TaskStatusQueued, TaskStatusDispatched, TaskStatusPreparing, TaskStatusServing, TaskStatusSettingUp, TaskStatusRunning, TaskStatusCancelling, TaskStatusUploading, TaskStatusCompleted, TaskStatusFailed, TaskStatusCancelled, AgentRunStateWorking, AgentRunStateSubmitted, AgentRunStateInputRequired, AgentRunStateAuthRequired, AgentRunStateCompleted, AgentRunStateFailed, AgentRunStateCanceled, AgentRunStateRejected, ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled, ChatStatusBusy, ChatStatusAwaitingInput, } from './types.js';
5
+ import { InterruptReasonToolApproval, InterruptResourceTurn, InterruptStatusPending } from './types.js';
6
+ import { TaskStatusUnknown, TaskStatusReceived, TaskStatusQueued, TaskStatusDispatched, TaskStatusPreparing, TaskStatusServing, TaskStatusSettingUp, TaskStatusRunning, TaskStatusCancelling, TaskStatusUploading, TaskStatusCompleted, TaskStatusFailed, TaskStatusCancelled, TaskStatusRejected, AgentRunStateWorking, AgentRunStateSubmitted, AgentRunStateInputRequired, AgentRunStateAuthRequired, AgentRunStateCompleted, AgentRunStateFailed, AgentRunStateCanceled, AgentRunStateRejected, ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled, ChatStatusBusy, ChatStatusAwaitingInput, } from './types.js';
7
7
  /** Map string status names to TaskStatus values (for future string-based API) */
8
8
  const STATUS_STRING_MAP = {
9
9
  unknown: TaskStatusUnknown,
@@ -19,6 +19,7 @@ const STATUS_STRING_MAP = {
19
19
  completed: TaskStatusCompleted,
20
20
  failed: TaskStatusFailed,
21
21
  cancelled: TaskStatusCancelled,
22
+ rejected: TaskStatusRejected,
22
23
  };
23
24
  /**
24
25
  * Parse task status from int or string to TaskStatus number.
@@ -37,12 +38,12 @@ export function parseStatus(status) {
37
38
  return TaskStatusUnknown;
38
39
  }
39
40
  /**
40
- * Check if a task status is terminal (completed, failed, or cancelled).
41
+ * Check if a task status is terminal (completed, failed, cancelled, or rejected).
41
42
  * Handles both int and string status values.
42
43
  */
43
44
  export function isTerminalStatus(status) {
44
45
  const parsed = parseStatus(status);
45
- return parsed === TaskStatusCompleted || parsed === TaskStatusFailed || parsed === TaskStatusCancelled;
46
+ return parsed === TaskStatusCompleted || parsed === TaskStatusFailed || parsed === TaskStatusCancelled || parsed === TaskStatusRejected;
46
47
  }
47
48
  // Run and message state predicates. Ports of the Go methods AgentRunState.IsTerminal/
48
49
  // IsInterrupted/IsSettled and ChatMessageStatus.IsTerminal; every consumer uses these.
@@ -79,7 +80,8 @@ export function isAwaitingHuman(chat) {
79
80
  return isRunInterrupted(run.state);
80
81
  return chat?.status === ChatStatusAwaitingInput;
81
82
  }
82
- function parseApprovalMeta(interrupt) {
83
+ /** An interrupt's meta, which arrives as an object or a JSON string. */
84
+ function parseMeta(interrupt) {
83
85
  const meta = interrupt.meta;
84
86
  if (!meta)
85
87
  return {};
@@ -104,7 +106,7 @@ export function pendingApprovals(chat) {
104
106
  if (interrupt.reason !== InterruptReasonToolApproval || interrupt.status !== InterruptStatusPending) {
105
107
  continue;
106
108
  }
107
- const meta = parseApprovalMeta(interrupt);
109
+ const meta = parseMeta(interrupt);
108
110
  out.push({
109
111
  interruptId: interrupt.id,
110
112
  toolInvocationId: interrupt.resource_id ?? meta.tool_invocation_id ?? '',
@@ -115,3 +117,11 @@ export function pendingApprovals(chat) {
115
117
  }
116
118
  return out;
117
119
  }
120
+ /** The held turn among a run's pending interrupts, if one is held. */
121
+ export function heldTurn(interrupts) {
122
+ const interrupt = interrupts?.find(i => i.resource_type === InterruptResourceTurn && i.status === InterruptStatusPending);
123
+ if (!interrupt)
124
+ return null;
125
+ const { steps } = parseMeta(interrupt);
126
+ return { interruptId: interrupt.id, runId: interrupt.run_id, steps: typeof steps === 'number' ? steps : null };
127
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inferencesh/sdk",
3
- "version": "0.28.0",
3
+ "version": "0.29.1",
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",