@inferencesh/sdk 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.34.0] - 2026-10-26
11
+
12
+ ### Breaking
13
+ - `CursorListRequest.page` and `CursorListResponse.total_items` are gone: lists are cursor-only. Page with `cursor` and `has_more`.
14
+
15
+ ### Added
16
+ - `ToolInvocationDTO.action`: the phrase the model wrote for the call ("Fetch unread emails from alice@x.com"). Empty when it left it out.
17
+ - `AgentRunDTO.finished_at`: when the run reached a terminal state.
18
+ - `ChatRunEvent.duration_ms`: how long the run took, from its start to its end.
19
+
20
+ ### Changed
21
+ - Auth scheme scopes (`scopes`, `required_scopes`) are the provider's own scope names; `scope_aliases` are optional shorthand for them.
22
+
23
+ ## [0.33.0] - 2026-10-24
24
+
25
+ ### Breaking
26
+ - `AuthResponse.otp_method` is gone: read `otp_methods`, the ordered `SecondFactor[]` (`totp`, `passkey`, `recovery`, `email`) a sign-in may be finished with.
27
+
28
+ ### Added
29
+ - The agent reducer applies streamed reasoning as it arrives; before, only text streamed.
30
+ - `AgentInfo.model_capabilities`: what the agent's model takes besides text (`image`, `file`, ...), from its core app version.
31
+ - `isRunWaiting(run)`. A chat whose run waits on the agent's own wait call (`ChatStatusWaiting`) counts as an open turn, not as one needing a person.
32
+ - Generated types: `ChatStatusWaiting`, `ToolInvocationStatusWaiting`, `ChatEventTypeRunFailed`, `ChatEventTypeRunEnded`, `ChatRunEvent`, `RunEndReason`, `SecondFactor`, `InfraRemote`, `ScopeContentWrite`, `ErrorCodeLastAuthenticator`, `InstancePriceHistoryPointDTO`, app capability and remote llm direct mode types.
33
+
34
+ ### Changed
35
+ - Proxy endpoints: cancelling a queued message needs `conversations:write` only.
36
+
37
+ ## [0.32.0] - 2026-10-20
38
+
10
39
  ### Changed
11
40
  - `approveTool` and `rejectTool` resolve the call's interrupt (`POST /interrupts/{id}/resolve`), the same answer as every other pause (a wait, a hook gate, a held turn); they no longer post to `/tools/{id}/invoke|reject`. A call that is not awaiting approval rejects with "Tool call … is not awaiting approval".
12
41
  - `resolveInterrupt` (agent actions and `AgentsAPI`) takes an optional `reason`, sent with a deny as `data.reason`.
@@ -392,13 +392,14 @@ export function createActions(ctx) {
392
392
  const result = await api.sendMessage(client, agentConfig, chatId, trimmedText, files);
393
393
  if (result) {
394
394
  const { chatId: newChatId, userMessage } = result;
395
- // Add user message from POST response immediately
396
- if (userMessage)
395
+ // An open SSE stream owns the message: it may already have moved it
396
+ // on (a message that ends a wait is taken up before this response
397
+ // returns). Polling refetches only when the chat's status changes,
398
+ // so it shows the response, as does a chat with no stream yet.
399
+ const manager = getStreamManager();
400
+ if (userMessage && !(manager instanceof StreamableManager))
397
401
  dispatch({ type: 'UPDATE_MESSAGE', payload: userMessage });
398
- // Start streaming if not already connected
399
- const streamManager = getStreamManager();
400
- if (newChatId && !streamManager) {
401
- // Either new chat or stream was stopped - restart streaming
402
+ if (newChatId && !manager) {
402
403
  if (!chatId) {
403
404
  dispatch({ type: 'SET_CHAT_ID', payload: newChatId });
404
405
  callbacks.onChatCreated?.(newChatId);
package/dist/agent/api.js CHANGED
@@ -76,9 +76,11 @@ export async function fetchAgentInfo(client, agentRef) {
76
76
  try {
77
77
  const resp = await client.http.request('get', `/agents/${agentRef}`);
78
78
  const version = resp.data?.version;
79
+ const capabilities = version?.core_app?.app?.version?.metadata?.capabilities;
79
80
  return {
80
81
  description: version?.description,
81
82
  example_prompts: version?.example_prompts,
83
+ model_capabilities: Array.isArray(capabilities) ? capabilities : undefined,
82
84
  };
83
85
  }
84
86
  catch {
@@ -3,13 +3,15 @@
3
3
  *
4
4
  * Pure reducer for managing agent chat state.
5
5
  */
6
- import { ChatStatusBusy, ChatStatusAwaitingInput, ChatStatusIdle } from '../types.js';
7
- import { isMessageTerminal, isRunInterrupted, isRunWorking } from '../utils.js';
6
+ import { ChatMessageContentTypeReasoning, ChatMessageContentTypeText, ChatStatusBusy, ChatStatusAwaitingInput, ChatStatusIdle, ChatStatusWaiting, } from '../types.js';
7
+ import { isMessageTerminal, isRunInterrupted, isRunWaiting, isRunWorking } from '../utils.js';
8
8
  function deriveChatStatus(run) {
9
9
  if (!run)
10
10
  return ChatStatusIdle;
11
11
  if (isRunWorking(run.state))
12
12
  return ChatStatusBusy;
13
+ if (isRunWaiting(run))
14
+ return ChatStatusWaiting;
13
15
  if (isRunInterrupted(run.state))
14
16
  return ChatStatusAwaitingInput;
15
17
  return ChatStatusIdle;
@@ -60,26 +62,55 @@ function normalizeMessage(message, existing) {
60
62
  return { ...message, content: existing?.content ?? [] };
61
63
  }
62
64
  /**
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.
65
+ * The content blocks deltas stream, and the delta field each is built from.
66
+ * An optional block gets no block until something streams into it.
69
67
  */
70
- function keepStreamedText(updated, existing) {
68
+ const streamedBlocks = [
69
+ { type: ChatMessageContentTypeText, field: 'response', optional: false },
70
+ { type: ChatMessageContentTypeReasoning, field: 'reasoning', optional: true },
71
+ ];
72
+ /** content with the block of type set to text, added in front when missing. */
73
+ function withBlockText(content, type, text) {
74
+ return content.some((c) => c.type === type)
75
+ ? content.map((c) => (c.type === type ? { ...c, text } : c))
76
+ : [{ type, text }, ...content];
77
+ }
78
+ const blockText = (message, type) => message.content.find((c) => c.type === type)?.text;
79
+ /** copy is an earlier version of shown: shown already has all of it and more. */
80
+ const isBehind = (copy, shown) => !!shown && shown.startsWith(copy ?? '');
81
+ /**
82
+ * Streamed text and reasoning only grow until the message is done. Deltas
83
+ * build them locally, while a message update carries the server's saved
84
+ * copy, which can lag behind them (often still empty). While the message is
85
+ * generating, a server copy behind what is shown keeps what is shown. Once
86
+ * the message is terminal the server's copy is final and wins.
87
+ */
88
+ function keepStreamedBlocks(updated, existing) {
71
89
  if (isMessageTerminal(updated.status))
72
90
  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 };
91
+ let content = updated.content;
92
+ for (const { type } of streamedBlocks) {
93
+ const shown = blockText(existing, type);
94
+ if (isBehind(blockText(updated, type), shown))
95
+ content = withBlockText(content, type, shown);
96
+ }
97
+ return content === updated.content ? updated : { ...updated, content };
98
+ }
99
+ /**
100
+ * The message with what the deltas have built so far. Deltas from a stream
101
+ * joined mid-message start partway, behind what the message already shows,
102
+ * so the message keeps its copy until they catch up.
103
+ */
104
+ function applyStreamedOutput(message, output) {
105
+ let content = message.content;
106
+ for (const { type, field, optional } of streamedBlocks) {
107
+ const streamed = output[field];
108
+ if (optional && !streamed)
109
+ continue;
110
+ if (!isBehind(streamed, blockText(message, type)))
111
+ content = withBlockText(content, type, streamed);
112
+ }
113
+ return content === message.content ? message : { ...message, content };
83
114
  }
84
115
  const normalizeMessages = (messages) => messages.map((m) => normalizeMessage(m));
85
116
  // =============================================================================
@@ -182,7 +213,7 @@ export function chatReducer(state, action) {
182
213
  const existingIndex = state.messages.findIndex((m) => m.id === message.id);
183
214
  if (existingIndex !== -1) {
184
215
  const existing = state.messages[existingIndex];
185
- const updated = keepStreamedText(action.partial ? normalizeMessage({ ...existing, ...message }, existing) : normalizeMessage(message), existing);
216
+ const updated = keepStreamedBlocks(action.partial ? normalizeMessage({ ...existing, ...message }, existing) : normalizeMessage(message), existing);
186
217
  if (existing === updated)
187
218
  return state;
188
219
  const newMessages = [...state.messages];
@@ -207,16 +238,10 @@ export function chatReducer(state, action) {
207
238
  const target = msgs.find(m => m.id === messageId);
208
239
  if (!target)
209
240
  return state;
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 ?? ''))
241
+ const next = applyStreamedOutput(target, output);
242
+ if (next === target)
214
243
  return state;
215
- const newContent = textBlock
216
- ? target.content.map(c => c.type === 'text' ? { ...c, text: output.response } : c)
217
- : [{ type: 'text', text: output.response }, ...target.content];
218
- const newMessages = msgs.map(m => m.id === target.id ? { ...target, content: newContent } : m);
219
- return { ...state, messages: newMessages };
244
+ return { ...state, messages: msgs.map(m => (m.id === target.id ? next : m)) };
220
245
  }
221
246
  case 'SET_CONNECTION_STATUS':
222
247
  return { ...state, connectionStatus: action.payload };
@@ -89,7 +89,13 @@ export declare function isTemplateConfig(config: AgentOptions): config is Templa
89
89
  /**
90
90
  * Agent metadata fetched from the backend for template configs
91
91
  */
92
- export type AgentInfo = Partial<Pick<AgentVersionDTO, 'description' | 'example_prompts'>>;
92
+ export type AgentInfo = Partial<Pick<AgentVersionDTO, 'description' | 'example_prompts'>> & {
93
+ /**
94
+ * What the agent's model takes besides text ("image", "file", ...), from
95
+ * its app version. Undefined when unknown; then assume everything.
96
+ */
97
+ model_capabilities?: string[];
98
+ };
93
99
  /**
94
100
  * Status of the chat
95
101
  */
package/dist/index.d.ts CHANGED
@@ -36,7 +36,7 @@ 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, heldTurn, pendingWait, } from './utils.js';
39
+ export { parseStatus, isTerminalStatus, isChatBusy, isAwaitingHuman, isRunTerminal, isRunInterrupted, isRunWaiting, isRunSettled, isRunWorking, isMessageTerminal, pendingApprovals, heldTurn, pendingWait, } from './utils.js';
40
40
  export type { PendingApproval, HeldTurn, PendingWait } from './utils.js';
41
41
  export * from './types.js';
42
42
  export type { TaskDTO as Task } from './types.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, heldTurn, pendingWait, } from './utils.js';
41
+ export { parseStatus, isTerminalStatus, isChatBusy, isAwaitingHuman, isRunTerminal, isRunInterrupted, isRunWaiting, isRunSettled, isRunWorking, isMessageTerminal, pendingApprovals, heldTurn, pendingWait, } from './utils.js';
42
42
  // Types - includes TaskStatus constants and all DTOs
43
43
  export * from './types.js';
44
44
  // =============================================================================
@@ -140,7 +140,6 @@
140
140
  "path": "/chats/messages/{messageId}/cancel",
141
141
  "purpose": "cancel a message",
142
142
  "scopes": [
143
- "conversations:read",
144
143
  "conversations:write"
145
144
  ]
146
145
  },
package/dist/types.d.ts CHANGED
@@ -394,6 +394,10 @@ export interface AgentRunDTO extends BaseModelDTO, PermissionModelDTO {
394
394
  state: AgentRunState;
395
395
  error?: string;
396
396
  output?: any;
397
+ /**
398
+ * FinishedAt is when the run reached a terminal state; nil while it runs.
399
+ */
400
+ finished_at?: string;
397
401
  interrupt_reason?: InterruptReason;
398
402
  interrupt_tool_id?: string;
399
403
  interrupt_meta?: any;
@@ -608,7 +612,11 @@ export interface AuthResponse {
608
612
  session_id: string;
609
613
  is_new?: boolean;
610
614
  otp_required?: boolean;
611
- otp_method?: string;
615
+ /**
616
+ * OTPMethods are the second factors the sign-in may be finished with,
617
+ * the default first (POST /auth/otp/verify with method).
618
+ */
619
+ otp_methods?: SecondFactor[];
612
620
  challenge_token?: string;
613
621
  redirect_to?: string;
614
622
  provider?: string;
@@ -911,7 +919,7 @@ export interface EstimateCostResponse {
911
919
  /**
912
920
  * Scope represents an API key permission scope string.
913
921
  */
914
- export type Scope = "*" | "agents" | "apps" | "conversations" | "files" | "datastores" | "templates" | "flows" | "projects" | "teams" | "billing" | "artifacts" | "agents:read" | "agents:write" | "agents:execute" | "apps:read" | "apps:write" | "apps:execute" | "conversations:read" | "conversations:write" | "files:read" | "files:write" | "datastores:read" | "datastores:write" | "flows:read" | "flows:write" | "flows:execute" | "projects:read" | "projects:write" | "teams:read" | "teams:write" | "billing:read" | "billing:write" | "secrets:read" | "secrets:write" | "secrets:reveal" | "credentials:read" | "credentials:write" | "engines:read" | "engines:write" | "remotes:read" | "remotes:write" | "apikeys:read" | "apikeys:write" | "knowledge:read" | "knowledge:write" | "artifacts:read" | "artifacts:write" | "user:read" | "user:write" | "settings:read" | "settings:write" | "approvals:write" | "admin:read" | "admin:write" | "store:pricing" | "store:submit";
922
+ export type Scope = "*" | "agents" | "apps" | "conversations" | "files" | "datastores" | "templates" | "flows" | "projects" | "teams" | "billing" | "artifacts" | "agents:read" | "agents:write" | "agents:execute" | "apps:read" | "apps:write" | "apps:execute" | "conversations:read" | "conversations:write" | "files:read" | "files:write" | "datastores:read" | "datastores:write" | "flows:read" | "flows:write" | "flows:execute" | "projects:read" | "projects:write" | "teams:read" | "teams:write" | "billing:read" | "billing:write" | "secrets:read" | "secrets:write" | "secrets:reveal" | "credentials:read" | "credentials:write" | "engines:read" | "engines:write" | "remotes:read" | "remotes:write" | "apikeys:read" | "apikeys:write" | "knowledge:read" | "knowledge:write" | "artifacts:read" | "artifacts:write" | "user:read" | "user:write" | "settings:read" | "settings:write" | "approvals:write" | "admin:read" | "admin:write" | "store:pricing" | "store:submit" | "content:write";
915
923
  /**
916
924
  * API Key Scopes - hierarchical permission system.
917
925
  * Resource-level scopes (e.g., "agents") imply all action-level scopes (e.g., "agents:read").
@@ -1218,10 +1226,18 @@ export declare const ScopeStorePricing: Scope;
1218
1226
  * publisher's behalf. Held like ScopeStorePricing.
1219
1227
  */
1220
1228
  export declare const ScopeStoreSubmit: Scope;
1229
+ /**
1230
+ * ScopeContentWrite writes the site's content (/content): blog and docs
1231
+ * pages, menus and the platform media library. Held like
1232
+ * ScopeStorePricing: only in the platform's workspace, by its members,
1233
+ * their keys and runs, and its own keys. Reads of published content take
1234
+ * no scope.
1235
+ */
1236
+ export declare const ScopeContentWrite: Scope;
1221
1237
  /**
1222
1238
  * ScopeGroup identifies a category of scopes for UI grouping
1223
1239
  */
1224
- export type ScopeGroup = "agents" | "apps" | "conversations" | "files" | "datastores" | "flows" | "projects" | "teams" | "billing" | "secrets" | "credentials" | "engines" | "remotes" | "apikeys" | "knowledge" | "artifacts" | "user" | "settings" | "approvals" | "admin" | "store";
1240
+ export type ScopeGroup = "agents" | "apps" | "conversations" | "files" | "datastores" | "flows" | "projects" | "teams" | "billing" | "secrets" | "credentials" | "engines" | "remotes" | "apikeys" | "knowledge" | "artifacts" | "user" | "settings" | "approvals" | "admin" | "store" | "content";
1225
1241
  export declare const ScopeGroupAgents: ScopeGroup;
1226
1242
  export declare const ScopeGroupApps: ScopeGroup;
1227
1243
  export declare const ScopeGroupConversations: ScopeGroup;
@@ -1243,6 +1259,7 @@ export declare const ScopeGroupSettings: ScopeGroup;
1243
1259
  export declare const ScopeGroupApprovals: ScopeGroup;
1244
1260
  export declare const ScopeGroupAdmin: ScopeGroup;
1245
1261
  export declare const ScopeGroupStore: ScopeGroup;
1262
+ export declare const ScopeGroupContent: ScopeGroup;
1246
1263
  /**
1247
1264
  * ScopeDefinition describes a single scope for UI rendering
1248
1265
  */
@@ -1398,9 +1415,6 @@ export interface AppPricing {
1398
1415
  description: string;
1399
1416
  description_rendered?: string;
1400
1417
  }
1401
- /**
1402
- * AppFunction represents a callable entry point within an app version.
1403
- */
1404
1418
  export interface AppFunction {
1405
1419
  name: string;
1406
1420
  description?: string;
@@ -2776,7 +2790,6 @@ export interface SortOrder {
2776
2790
  */
2777
2791
  export interface CursorListRequest {
2778
2792
  cursor: string;
2779
- page?: number;
2780
2793
  limit: number;
2781
2794
  direction: string;
2782
2795
  search?: SearchRequest;
@@ -2802,7 +2815,6 @@ export interface CursorListResponse<T extends any> {
2802
2815
  has_next: boolean;
2803
2816
  has_previous: boolean;
2804
2817
  items_per_page: number;
2805
- total_items: number;
2806
2818
  }
2807
2819
  /**
2808
2820
  * CountResponse is the response for count endpoints.
@@ -3062,7 +3074,7 @@ export interface DecideEntitlementRequestRequest {
3062
3074
  * and APIError.Code on the legacy envelope. Clients branch on these, so a
3063
3075
  * code is a named const here, where it generates into models and the SDKs.
3064
3076
  */
3065
- 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";
3077
+ 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" | "last_authenticator" | "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";
3066
3078
  export declare const ErrorCodeInvalidRequest: ErrorCode;
3067
3079
  export declare const ErrorCodeValidationError: ErrorCode;
3068
3080
  export declare const ErrorCodeUnauthorized: ErrorCode;
@@ -3171,6 +3183,13 @@ export declare const ErrorCodeInvalidTTL: ErrorCode;
3171
3183
  * has not proved it gets otp_required instead: re-authenticate with it.
3172
3184
  */
3173
3185
  export declare const ErrorCodeAdminAuthenticatorRequired: ErrorCode;
3186
+ /**
3187
+ * ErrorCodeLastAuthenticator (409): the change would leave two-step
3188
+ * verification on with no method to prove it (removing the last
3189
+ * authenticator app or passkey), or turn it on with none enrolled.
3190
+ * Turn two-step verification off first, or enroll a method.
3191
+ */
3192
+ export declare const ErrorCodeLastAuthenticator: ErrorCode;
3174
3193
  /**
3175
3194
  * Entitlements. LimitExceeded (402) and FeatureNotAvailable (403) carry
3176
3195
  * EntitlementErrorMeta. EntitlementUnavailable (500) means the plan could
@@ -3846,6 +3865,29 @@ export interface InstanceTypeBootTime {
3846
3865
  updated_at: string;
3847
3866
  sample_size: number;
3848
3867
  }
3868
+ /**
3869
+ * InstancePriceHistoryPointDTO is one day's cheapest hourly prices, in cents,
3870
+ * for a GPU type. List prices rarely move; the in-stock price does, as stock
3871
+ * comes and goes. A price with no listing (or no stock) that day is omitted.
3872
+ */
3873
+ export interface InstancePriceHistoryPointDTO {
3874
+ day: string;
3875
+ /**
3876
+ * OnDemand and Spot are the cheapest listed prices, in stock or not.
3877
+ */
3878
+ on_demand?: number;
3879
+ spot?: number;
3880
+ /**
3881
+ * OnDemandInStock and SpotInStock are the cheapest prices that had stock.
3882
+ */
3883
+ on_demand_in_stock?: number;
3884
+ spot_in_stock?: number;
3885
+ providers: number;
3886
+ /**
3887
+ * Regions is the number of provider regions with on-demand stock.
3888
+ */
3889
+ regions: number;
3890
+ }
3849
3891
  export interface InterruptDTO extends BaseModelDTO, PermissionModelDTO {
3850
3892
  run_id: string;
3851
3893
  chat_id: string;
@@ -5379,6 +5421,11 @@ export interface ToolInvocationDTO extends BaseModelDTO, PermissionModelDTO {
5379
5421
  tool_invocation_id: string;
5380
5422
  type: ToolType;
5381
5423
  display_name?: string;
5424
+ /**
5425
+ * Action is what the model said the call does, as an imperative phrase
5426
+ * ("Fetch unread emails from alice@x.com"). Empty when it left it out.
5427
+ */
5428
+ action?: string;
5382
5429
  execution_id?: string;
5383
5430
  function: ToolInvocationFunction;
5384
5431
  status: ToolInvocationStatus;
@@ -5454,7 +5501,17 @@ export interface UserDTO extends BaseModelDTO {
5454
5501
  avatar_url: string;
5455
5502
  banned_at?: string;
5456
5503
  ban_note?: string;
5504
+ /**
5505
+ * TOTPEnabled mirrors TwoFactorEnabled for clients built before it
5506
+ * (the Swift SDK decodes it as required).
5507
+ * Deprecated: read TwoFactorEnabled. Kept until no Swift app build older
5508
+ * than sdk-swift 0.23.0 is in use, since those fail to decode /me without it.
5509
+ */
5457
5510
  totp_enabled: boolean;
5511
+ /**
5512
+ * TwoFactorEnabled is the account's two-step verification switch.
5513
+ */
5514
+ two_factor_enabled: boolean;
5458
5515
  metadata?: UserMetadataDTO;
5459
5516
  }
5460
5517
  /**
@@ -5944,8 +6001,8 @@ export interface AuthMethodLookup {
5944
6001
  }
5945
6002
  /**
5946
6003
  * AuthMethodCapability is something an app can ask for from this provider,
5947
- * satisfied by a connection holding its scopes. Scopes are in the scheme's
5948
- * own (friendly) names, the ones a credential stores.
6004
+ * satisfied by a connection holding its scopes. Scopes are the provider's
6005
+ * own names (Wire form), the ones a credential stores.
5949
6006
  */
5950
6007
  export interface AuthMethodCapability {
5951
6008
  key: string;
@@ -6002,10 +6059,11 @@ export interface AuthMethod {
6002
6059
  authorization_endpoint?: string;
6003
6060
  scopes?: string[];
6004
6061
  /**
6005
- * ScopeAliases map the scheme's own scope names to what the provider
6006
- * wants on the wire ("gmail.send" → "https://www.googleapis.com/auth/
6007
- * gmail.send"). Credentials store the alias; the wire form is used only
6008
- * in requests. A scope with no alias is sent as is.
6062
+ * ScopeAliases are shorthand a caller may write for a provider scope
6063
+ * ("gmail.send" → "https://www.googleapis.com/auth/gmail.send"). They
6064
+ * are accepted on input only: credentials, capabilities and allowed
6065
+ * lists hold the provider's own name (Wire), and every comparison is
6066
+ * in that form. A scope with no alias is the provider's name as is.
6009
6067
  */
6010
6068
  scope_aliases?: {
6011
6069
  [key: string]: string;
@@ -6053,7 +6111,7 @@ export interface AuthMethod {
6053
6111
  * re-authorizing for more scopes, whatever the caller asked for: the
6054
6112
  * scopes the identity lookup and token refresh need (Google's openid,
6055
6113
  * email and profile; X's users.read and offline.access). In the
6056
- * scheme's own names, like Scopes. Empty = only what was asked for.
6114
+ * provider's own names, like Scopes. Empty = only what was asked for.
6057
6115
  */
6058
6116
  required_scopes?: string[];
6059
6117
  /**
@@ -6248,10 +6306,15 @@ export declare const EntitlementRequestOpen: EntitlementRequestState;
6248
6306
  export declare const EntitlementRequestAccepted: EntitlementRequestState;
6249
6307
  export declare const EntitlementRequestDeclined: EntitlementRequestState;
6250
6308
  export declare const EntitlementRequestWithdrawn: EntitlementRequestState;
6251
- export type ChatStatus = "busy" | "idle" | "awaiting_input" | "completed";
6309
+ export type ChatStatus = "busy" | "idle" | "awaiting_input" | "waiting" | "completed";
6252
6310
  export declare const ChatStatusBusy: ChatStatus;
6253
6311
  export declare const ChatStatusIdle: ChatStatus;
6254
6312
  export declare const ChatStatusAwaitingInput: ChatStatus;
6313
+ /**
6314
+ * ChatStatusWaiting: the run is paused on the agent's own wait call. A
6315
+ * message ends the wait early; nobody has to act on it.
6316
+ */
6317
+ export declare const ChatStatusWaiting: ChatStatus;
6255
6318
  export declare const ChatStatusCompleted: ChatStatus;
6256
6319
  export type PlanStepStatus = "pending" | "in_progress" | "completed" | "cancelled";
6257
6320
  export declare const PlanStepStatusPending: PlanStepStatus;
@@ -6333,8 +6396,46 @@ export interface ChatMessageContent {
6333
6396
  tool_calls?: ToolCall[];
6334
6397
  event?: ChatEvent;
6335
6398
  }
6336
- export type ChatEventType = "hook";
6399
+ export type ChatEventType = "hook" | "run_failed" | "run_ended";
6337
6400
  export declare const ChatEventTypeHook: ChatEventType;
6401
+ /**
6402
+ * ChatEventTypeRunFailed marks the point a run ended in failure; the
6403
+ * content's text is the run's error.
6404
+ */
6405
+ export declare const ChatEventTypeRunFailed: ChatEventType;
6406
+ /**
6407
+ * ChatEventTypeRunEnded marks the point a run completed or was stopped;
6408
+ * the event's run says how, and the content's text, when set, why.
6409
+ */
6410
+ export declare const ChatEventTypeRunEnded: ChatEventType;
6411
+ /**
6412
+ * RunEndReason is why a run that completed ended the way it did, when its
6413
+ * last turn did not end with a reply.
6414
+ */
6415
+ export type RunEndReason = "output_limit" | "no_reply";
6416
+ /**
6417
+ * RunEndReasonOutputLimit: the model's last turn hit its output limit
6418
+ * (max_tokens) before it replied or called a tool.
6419
+ */
6420
+ export declare const RunEndReasonOutputLimit: RunEndReason;
6421
+ /**
6422
+ * RunEndReasonNoReply: the model ended its last turn with no reply and
6423
+ * no tool call.
6424
+ */
6425
+ export declare const RunEndReasonNoReply: RunEndReason;
6426
+ /**
6427
+ * ChatRunEvent is how a run ended, on a run_ended event.
6428
+ */
6429
+ export interface ChatRunEvent {
6430
+ run_id: string;
6431
+ state: AgentRunState;
6432
+ reason?: RunEndReason;
6433
+ /**
6434
+ * DurationMs is how long the run took, from its start to its end. The
6435
+ * event message's created_at is when it ended.
6436
+ */
6437
+ duration_ms?: number;
6438
+ }
6338
6439
  /**
6339
6440
  * ChatEvent is the payload of an event-role message: system info shown in the
6340
6441
  * chat but never sent to the model.
@@ -6342,6 +6443,7 @@ export declare const ChatEventTypeHook: ChatEventType;
6342
6443
  export interface ChatEvent {
6343
6444
  type: ChatEventType;
6344
6445
  hook?: ChatHookEvent;
6446
+ run?: ChatRunEvent;
6345
6447
  }
6346
6448
  /**
6347
6449
  * ChatHookEvent records one lifecycle hook handler run.
@@ -6732,8 +6834,8 @@ export declare const GraphEdgeTypeOutput: GraphEdgeType;
6732
6834
  export declare const InterruptResourceTurn: InterruptResourceType;
6733
6835
  /**
6734
6836
  * InterruptReasonWait is a tool call the agent made to wait: the run is
6735
- * paused until the interrupt's deadline, when its own expiry trigger settles
6736
- * it (allow), or until a person ends the wait sooner. Its resource is the
6837
+ * paused until the interrupt's deadline, when the expiry sweep settles it
6838
+ * (allow), or until a person ends the wait sooner. Its resource is the
6737
6839
  * wait call (InterruptResourceToolInvocation).
6738
6840
  */
6739
6841
  export declare const InterruptReasonWait: InterruptReason;
@@ -7058,6 +7160,33 @@ export type MCPServerAuthType = "oauth" | "api_key" | "none";
7058
7160
  export declare const MCPServerAuthOAuth: MCPServerAuthType;
7059
7161
  export declare const MCPServerAuthAPIKey: MCPServerAuthType;
7060
7162
  export declare const MCPServerAuthNone: MCPServerAuthType;
7163
+ /**
7164
+ * SecondFactor is one way a person proves their second factor. It names
7165
+ * what a session proved (AuthSession.SecondFactor), what a login challenge
7166
+ * offers, the method a verify request picks, and the kind of an enrolled
7167
+ * method (SecondFactorMethod.Kind: the enrollable ones).
7168
+ */
7169
+ export type SecondFactor = "totp" | "passkey" | "recovery" | "email";
7170
+ /**
7171
+ * SecondFactorTOTP: a code from an enrolled authenticator app.
7172
+ */
7173
+ export declare const SecondFactorTOTP: SecondFactor;
7174
+ /**
7175
+ * SecondFactorPasskey: a WebAuthn assertion from an enrolled passkey.
7176
+ */
7177
+ export declare const SecondFactorPasskey: SecondFactor;
7178
+ /**
7179
+ * SecondFactorRecovery: one of the account's single-use recovery codes.
7180
+ * Not enrolled on its own: issued once an authenticator exists.
7181
+ */
7182
+ export declare const SecondFactorRecovery: SecondFactor;
7183
+ /**
7184
+ * SecondFactorEmail: a code emailed to the account. The weakest: the
7185
+ * same mailbox a magic link lands in, so it is offered only to an
7186
+ * account with two-step verification off (a platform admin's first
7187
+ * sign-in, re-auth before they enroll).
7188
+ */
7189
+ export declare const SecondFactorEmail: SecondFactor;
7061
7190
  /**
7062
7191
  * TeamInviteStatus represents the status of a team invitation
7063
7192
  */
@@ -7552,10 +7681,17 @@ export declare const TaskStatusRejected: TaskStatus;
7552
7681
  /**
7553
7682
  * Infra defines where a task should run.
7554
7683
  */
7555
- export type Infra = "private" | "cloud" | "private_first";
7684
+ export type Infra = "private" | "cloud" | "private_first" | "remote";
7556
7685
  export declare const InfraPrivate: Infra;
7557
7686
  export declare const InfraCloud: Infra;
7558
7687
  export declare const InfraPrivateFirst: Infra;
7688
+ /**
7689
+ * InfraRemote is a model call a harness on the caller's own remote
7690
+ * answers (an agent whose model app is a harness model app). The
7691
+ * scheduler never takes it: the remote model service sends it to the
7692
+ * remote's daemon, whose frames end it.
7693
+ */
7694
+ export declare const InfraRemote: Infra;
7559
7695
  /**
7560
7696
  * TaskLogType defines the type of task log.
7561
7697
  */
@@ -8070,11 +8206,12 @@ export declare const AgentEventSubagentCompleted: AgentEventType;
8070
8206
  /**
8071
8207
  * ToolInvocationStatus represents the execution status of a tool invocation
8072
8208
  */
8073
- export type ToolInvocationStatus = "pending" | "in_progress" | "awaiting_input" | "awaiting_approval" | "completed" | "failed" | "cancelled";
8209
+ export type ToolInvocationStatus = "pending" | "in_progress" | "awaiting_input" | "awaiting_approval" | "waiting" | "completed" | "failed" | "cancelled";
8074
8210
  export declare const ToolInvocationStatusPending: ToolInvocationStatus;
8075
8211
  export declare const ToolInvocationStatusInProgress: ToolInvocationStatus;
8076
8212
  export declare const ToolInvocationStatusAwaitingInput: ToolInvocationStatus;
8077
8213
  export declare const ToolInvocationStatusAwaitingApproval: ToolInvocationStatus;
8214
+ export declare const ToolInvocationStatusWaiting: ToolInvocationStatus;
8078
8215
  export declare const ToolInvocationStatusCompleted: ToolInvocationStatus;
8079
8216
  export declare const ToolInvocationStatusFailed: ToolInvocationStatus;
8080
8217
  export declare const ToolInvocationStatusCancelled: ToolInvocationStatus;
package/dist/types.js CHANGED
@@ -321,6 +321,14 @@ export const ScopeStorePricing = "store:pricing";
321
321
  * publisher's behalf. Held like ScopeStorePricing.
322
322
  */
323
323
  export const ScopeStoreSubmit = "store:submit";
324
+ /**
325
+ * ScopeContentWrite writes the site's content (/content): blog and docs
326
+ * pages, menus and the platform media library. Held like
327
+ * ScopeStorePricing: only in the platform's workspace, by its members,
328
+ * their keys and runs, and its own keys. Reads of published content take
329
+ * no scope.
330
+ */
331
+ export const ScopeContentWrite = "content:write";
324
332
  export const ScopeGroupAgents = "agents";
325
333
  export const ScopeGroupApps = "apps";
326
334
  export const ScopeGroupConversations = "conversations";
@@ -342,6 +350,7 @@ export const ScopeGroupSettings = "settings";
342
350
  export const ScopeGroupApprovals = "approvals";
343
351
  export const ScopeGroupAdmin = "admin";
344
352
  export const ScopeGroupStore = "store";
353
+ export const ScopeGroupContent = "content";
345
354
  /**
346
355
  * AlwaysAllowScopeExact: this call exactly (each piece of the command,
347
356
  * the file, the domain).
@@ -485,6 +494,13 @@ export const ErrorCodeInvalidTTL = "invalid_ttl";
485
494
  * has not proved it gets otp_required instead: re-authenticate with it.
486
495
  */
487
496
  export const ErrorCodeAdminAuthenticatorRequired = "admin_authenticator_required";
497
+ /**
498
+ * ErrorCodeLastAuthenticator (409): the change would leave two-step
499
+ * verification on with no method to prove it (removing the last
500
+ * authenticator app or passkey), or turn it on with none enrolled.
501
+ * Turn two-step verification off first, or enroll a method.
502
+ */
503
+ export const ErrorCodeLastAuthenticator = "last_authenticator";
488
504
  /**
489
505
  * Entitlements. LimitExceeded (402) and FeatureNotAvailable (403) carry
490
506
  * EntitlementErrorMeta. EntitlementUnavailable (500) means the plan could
@@ -870,6 +886,11 @@ export const EntitlementRequestWithdrawn = "withdrawn";
870
886
  export const ChatStatusBusy = "busy";
871
887
  export const ChatStatusIdle = "idle";
872
888
  export const ChatStatusAwaitingInput = "awaiting_input";
889
+ /**
890
+ * ChatStatusWaiting: the run is paused on the agent's own wait call. A
891
+ * message ends the wait early; nobody has to act on it.
892
+ */
893
+ export const ChatStatusWaiting = "waiting";
873
894
  export const ChatStatusCompleted = "completed";
874
895
  export const PlanStepStatusPending = "pending";
875
896
  export const PlanStepStatusInProgress = "in_progress";
@@ -907,6 +928,26 @@ export const ChannelTypeDiscord = "discord";
907
928
  export const ChannelTypeTeams = "teams";
908
929
  export const ChannelTypeTelegram = "telegram";
909
930
  export const ChatEventTypeHook = "hook";
931
+ /**
932
+ * ChatEventTypeRunFailed marks the point a run ended in failure; the
933
+ * content's text is the run's error.
934
+ */
935
+ export const ChatEventTypeRunFailed = "run_failed";
936
+ /**
937
+ * ChatEventTypeRunEnded marks the point a run completed or was stopped;
938
+ * the event's run says how, and the content's text, when set, why.
939
+ */
940
+ export const ChatEventTypeRunEnded = "run_ended";
941
+ /**
942
+ * RunEndReasonOutputLimit: the model's last turn hit its output limit
943
+ * (max_tokens) before it replied or called a tool.
944
+ */
945
+ export const RunEndReasonOutputLimit = "output_limit";
946
+ /**
947
+ * RunEndReasonNoReply: the model ended its last turn with no reply and
948
+ * no tool call.
949
+ */
950
+ export const RunEndReasonNoReply = "no_reply";
910
951
  /**
911
952
  * DescriptionLimitListing bounds the description of an app, agent, flow,
912
953
  * MCP server or knowledge entry. A description is shown in listings and
@@ -994,8 +1035,8 @@ export const GraphEdgeTypeOutput = "output";
994
1035
  export const InterruptResourceTurn = "turn";
995
1036
  /**
996
1037
  * InterruptReasonWait is a tool call the agent made to wait: the run is
997
- * paused until the interrupt's deadline, when its own expiry trigger settles
998
- * it (allow), or until a person ends the wait sooner. Its resource is the
1038
+ * paused until the interrupt's deadline, when the expiry sweep settles it
1039
+ * (allow), or until a person ends the wait sooner. Its resource is the
999
1040
  * wait call (InterruptResourceToolInvocation).
1000
1041
  */
1001
1042
  export const InterruptReasonWait = "wait";
@@ -1111,6 +1152,26 @@ export const VideoRes4K = "4k";
1111
1152
  export const MCPServerAuthOAuth = "oauth";
1112
1153
  export const MCPServerAuthAPIKey = "api_key";
1113
1154
  export const MCPServerAuthNone = "none";
1155
+ /**
1156
+ * SecondFactorTOTP: a code from an enrolled authenticator app.
1157
+ */
1158
+ export const SecondFactorTOTP = "totp";
1159
+ /**
1160
+ * SecondFactorPasskey: a WebAuthn assertion from an enrolled passkey.
1161
+ */
1162
+ export const SecondFactorPasskey = "passkey";
1163
+ /**
1164
+ * SecondFactorRecovery: one of the account's single-use recovery codes.
1165
+ * Not enrolled on its own: issued once an authenticator exists.
1166
+ */
1167
+ export const SecondFactorRecovery = "recovery";
1168
+ /**
1169
+ * SecondFactorEmail: a code emailed to the account. The weakest: the
1170
+ * same mailbox a magic link lands in, so it is offered only to an
1171
+ * account with two-step verification off (a platform admin's first
1172
+ * sign-in, re-auth before they enroll).
1173
+ */
1174
+ export const SecondFactorEmail = "email";
1114
1175
  export const TeamInviteStatusPending = "pending";
1115
1176
  export const TeamInviteStatusAccepted = "accepted";
1116
1177
  export const TeamInviteStatusDeclined = "declined";
@@ -1483,6 +1544,13 @@ export const TaskStatusRejected = 13;
1483
1544
  export const InfraPrivate = "private";
1484
1545
  export const InfraCloud = "cloud";
1485
1546
  export const InfraPrivateFirst = "private_first";
1547
+ /**
1548
+ * InfraRemote is a model call a harness on the caller's own remote
1549
+ * answers (an agent whose model app is a harness model app). The
1550
+ * scheduler never takes it: the remote model service sends it to the
1551
+ * remote's daemon, whose frames end it.
1552
+ */
1553
+ export const InfraRemote = "remote";
1486
1554
  export const TaskLogTypeBuild = 0;
1487
1555
  export const TaskLogTypeRun = 1;
1488
1556
  export const TaskLogTypeServe = 2;
@@ -1672,6 +1740,7 @@ export const ToolInvocationStatusPending = "pending";
1672
1740
  export const ToolInvocationStatusInProgress = "in_progress";
1673
1741
  export const ToolInvocationStatusAwaitingInput = "awaiting_input";
1674
1742
  export const ToolInvocationStatusAwaitingApproval = "awaiting_approval";
1743
+ export const ToolInvocationStatusWaiting = "waiting";
1675
1744
  export const ToolInvocationStatusCompleted = "completed";
1676
1745
  export const ToolInvocationStatusFailed = "failed";
1677
1746
  export const ToolInvocationStatusCancelled = "cancelled";
package/dist/utils.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import type { InterruptDTO } from './types.js';
6
6
  import { TaskStatus } from './types.js';
7
- import type { AgentRunState, ChatDTO, ChatMessageStatus } from './types.js';
7
+ import type { AgentRunDTO, AgentRunState, ChatDTO, ChatMessageStatus } from './types.js';
8
8
  /**
9
9
  * Parse task status from int or string to TaskStatus number.
10
10
  * Handles both current int-based API and future string-based API.
@@ -18,12 +18,14 @@ export declare function isTerminalStatus(status: number | string | undefined | n
18
18
  export declare function isRunTerminal(state: AgentRunState | null | undefined): boolean;
19
19
  /** Parked on a human: a tool approval or input (input_required) or an authorization (auth_required). */
20
20
  export declare function isRunInterrupted(state: AgentRunState | null | undefined): boolean;
21
+ /** Paused on the agent's own wait call: it resumes at its deadline or on a message, so nobody has to act. */
22
+ export declare function isRunWaiting(run: Pick<AgentRunDTO, 'state' | 'interrupt_reason'> | null | undefined): boolean;
21
23
  /** The run produces no further events this turn: terminal or interrupted. */
22
24
  export declare function isRunSettled(state: AgentRunState | null | undefined): boolean;
23
25
  /** The run is executing: submitted or working. */
24
26
  export declare function isRunWorking(state: AgentRunState | null | undefined): boolean;
25
27
  export declare function isMessageTerminal(status: ChatMessageStatus | null | undefined): boolean;
26
- /** The turn is still open: the run is working or parked on a human (approval, input, authorization). */
28
+ /** The turn is still open: the run is working, waiting, or parked on a human (approval, input, authorization). */
27
29
  export declare function isChatBusy(chat: ChatDTO | null | undefined): boolean;
28
30
  /** The chat is blocked on a human: nothing more arrives until someone approves, answers or authorizes. */
29
31
  export declare function isAwaitingHuman(chat: ChatDTO | null | undefined): boolean;
package/dist/utils.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Provides future compatibility when API migrates from int to string status.
4
4
  */
5
5
  import { InterruptReasonToolApproval, InterruptReasonWait, 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';
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, ChatStatusWaiting, } 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,
@@ -54,6 +54,10 @@ export function isRunTerminal(state) {
54
54
  export function isRunInterrupted(state) {
55
55
  return state === AgentRunStateInputRequired || state === AgentRunStateAuthRequired;
56
56
  }
57
+ /** Paused on the agent's own wait call: it resumes at its deadline or on a message, so nobody has to act. */
58
+ export function isRunWaiting(run) {
59
+ return !!run && isRunInterrupted(run.state) && run.interrupt_reason === InterruptReasonWait;
60
+ }
57
61
  /** The run produces no further events this turn: terminal or interrupted. */
58
62
  export function isRunSettled(state) {
59
63
  return isRunTerminal(state) || isRunInterrupted(state);
@@ -65,19 +69,19 @@ export function isRunWorking(state) {
65
69
  export function isMessageTerminal(status) {
66
70
  return status === ChatMessageStatusReady || status === ChatMessageStatusFailed || status === ChatMessageStatusCancelled;
67
71
  }
68
- /** The turn is still open: the run is working or parked on a human (approval, input, authorization). */
72
+ /** The turn is still open: the run is working, waiting, or parked on a human (approval, input, authorization). */
69
73
  export function isChatBusy(chat) {
70
74
  const run = chat?.active_run;
71
75
  if (run) {
72
76
  return isRunWorking(run.state) || isRunInterrupted(run.state);
73
77
  }
74
- return chat?.status === ChatStatusBusy || chat?.status === ChatStatusAwaitingInput;
78
+ return chat?.status === ChatStatusBusy || chat?.status === ChatStatusAwaitingInput || chat?.status === ChatStatusWaiting;
75
79
  }
76
80
  /** The chat is blocked on a human: nothing more arrives until someone approves, answers or authorizes. */
77
81
  export function isAwaitingHuman(chat) {
78
82
  const run = chat?.active_run;
79
83
  if (run)
80
- return isRunInterrupted(run.state);
84
+ return isRunInterrupted(run.state) && !isRunWaiting(run);
81
85
  return chat?.status === ChatStatusAwaitingInput;
82
86
  }
83
87
  /** An interrupt's meta, which arrives as an object or a JSON string. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inferencesh/sdk",
3
- "version": "0.32.0",
3
+ "version": "0.34.0",
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",