@inferencesh/sdk 0.20.0 → 0.21.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 +57 -0
- package/dist/agent/actions.js +1 -4
- package/dist/agent/api.d.ts +2 -5
- package/dist/agent/api.js +2 -2
- package/dist/agent/types.d.ts +1 -1
- package/dist/api/agents.js +2 -4
- package/dist/api/tasks.js +1 -4
- package/dist/http/client.d.ts +68 -7
- package/dist/http/client.js +136 -96
- package/dist/http/index.d.ts +2 -2
- package/dist/http/streamable.d.ts +25 -5
- package/dist/http/streamable.js +28 -40
- package/dist/index.d.ts +2 -2
- package/dist/types.d.ts +183 -2
- package/dist/types.js +10 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.21.0] - 2026-10-08
|
|
11
|
+
|
|
12
|
+
Breaking: `AgentClient.http` requires `fetch`, the `AppTag*` constants are removed, and `StreamableManagerOptions` is a type alias. See Changed and Removed.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `HttpClient.fetch(endpoint, init?)`: fetches an endpoint with the client's auth, headers and credentials mode and resolves with the raw `Response`, for bodies `request()` does not parse (streams, text). A refused response throws the error `request()` would (`InferenceError`, `RequirementsNotMetException`). Type `HttpFetchInit`.
|
|
17
|
+
- `StreamRequest` and `StreamRequestInit`: a function that sends a stream's request. `StreamableManager` takes `{ request }` in place of `{ url, headers, credentials }`, and `streamable()` / `streamableRaw()` take one in place of the URL. With `(init) => http.fetch(endpoint, init)` the stream carries the token of the moment it connects and a refusal goes through `onError`. Type `StreamableSource`.
|
|
18
|
+
- `onError` gets a third argument, `FailedRequest` (`{ token }`): the bearer token the failed request carried, so a handler that refreshes credentials can tell a request sent before the refresh from one sent after it.
|
|
19
|
+
- `getToken` may be async (`() => string | null | undefined | Promise<string | null | undefined>`). `request()`, `fetch()` and the EventSource handshake wait for it.
|
|
20
|
+
- `HttpClient.request()` takes `handleErrors` (default `true`). With `handleErrors: false` the caller handles the request's failure itself: `onError` is not called for it, nothing is retried, and the error is thrown as it is.
|
|
21
|
+
|
|
22
|
+
- Types: `StoreCategoryDTO` and `StoreTagDTO` (`GET /store/categories`, `GET /store/tags`); the decision app contract (`DecisionInput`, `DecisionVisionInput`, `DecisionOutput` and its question and answer types); `ErrorCodeImpersonationReasonRequired`.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- `AgentClient.http` requires `fetch` and no longer requires `getStreamableConfig`. A hand-built `AgentClient` must add `http.fetch`; `Inference` and `HttpClient` already have it.
|
|
27
|
+
- The streams the SDK opens itself (`tasks.run()` and `tasks.watch()`, `Agent` chat streams, the agent chat in `@inferencesh/sdk/agent`) go through `HttpClient.fetch`. A stream the api refuses now reaches `onError` like a refused request, and fails with an `InferenceError` (`statusCode`, `responseBody`) where it failed with `Error('HTTP <status>: <body>')`.
|
|
28
|
+
- A request that got no response (the network failed) goes to `onError` from `fetch()` and the EventSource handshake too, as it already did from `request()`. The failure is thrown unless the handler's retry resolves with a response. A request aborted through its signal is not handed to `onError`.
|
|
29
|
+
- The EventSource handshake and `fetch()` take what `onError` resolves with only when it is a `Response`; anything else leaves the refused response in place.
|
|
30
|
+
- `StreamableManagerOptions` is a type alias (`StreamableSource & { ... }`), no longer an interface: it cannot be extended with `interface X extends StreamableManagerOptions<T>`; use an intersection.
|
|
31
|
+
|
|
32
|
+
### Removed
|
|
33
|
+
|
|
34
|
+
- The `AppTag*` constants (`AppTagTextToImage` and the rest). App tags come from the store: `GET /store/tags`, typed `StoreTagDTO`.
|
|
35
|
+
|
|
36
|
+
### Deprecated
|
|
37
|
+
|
|
38
|
+
- `HttpClient.getStreamableConfig()`: a request made from the config bypasses `onError` and carries the token of the moment the config was read. Use `fetch()` or a `StreamRequest`. It throws when `getToken` is async.
|
|
39
|
+
|
|
40
|
+
## [0.20.1] - 2026-10-08
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- Types: app tags and the decision app category.
|
|
45
|
+
|
|
46
|
+
## [0.20.0] - 2026-10-07
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- `tasks.files(id)`, `tasks.deleteFiles(id)` and `tasks.delete(id, { files })`: list a task's files and delete them with or without the task.
|
|
51
|
+
- Types: task files, MCP Apps (`_meta.ui`, `AppUIRef`, the MCP tool call UI fields), remote tags and policy rules, `AppDTO.resolved_function`, `DescriptionLimit`.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- Types: forms lose the bounty and reward fields; a bounty's proof form drops `proof_min_length`.
|
|
56
|
+
|
|
57
|
+
### Security
|
|
58
|
+
|
|
59
|
+
- `next` ^16.3.6 (resolves 16.3.8) for GHSA-vcvr-r3jv-pc5j.
|
|
60
|
+
|
|
61
|
+
## [0.19.0] - 2026-10-04
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- Types regenerated; the run parameters docs drop `params.variant`.
|
|
66
|
+
|
|
10
67
|
## [0.18.0] - 2026-10-04
|
|
11
68
|
|
|
12
69
|
### Added
|
package/dist/agent/actions.js
CHANGED
|
@@ -109,11 +109,8 @@ export function createActions(ctx) {
|
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
// Single unified stream with TypedEvents (both Chat and ChatMessage events)
|
|
112
|
-
const { url, headers, credentials } = api.getChatStreamConfig(client, id);
|
|
113
112
|
const manager = new StreamableManager({
|
|
114
|
-
|
|
115
|
-
headers,
|
|
116
|
-
credentials,
|
|
113
|
+
request: api.chatStreamRequest(client, id),
|
|
117
114
|
onError: (error) => {
|
|
118
115
|
console.warn('[AgentSDK] Stream error:', error);
|
|
119
116
|
callbacks.onError?.(error);
|
package/dist/agent/api.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { AlwaysAllowOptionsDTO, AlwaysAllowResultDTO, ChatAgentDTO, ChatDTO, ChatMessageDTO, ChatSettingsDTO, ChatSettingsRequest, InterruptDTO, ToolExplanationDTO } from '../types';
|
|
11
11
|
import type { AgentOptions, AgentClient, AgentInfo, FileRef } from './types';
|
|
12
|
+
import type { StreamRequest } from '../http/streamable';
|
|
12
13
|
export interface SendResult {
|
|
13
14
|
chatId: string;
|
|
14
15
|
userMessage: ChatMessageDTO;
|
|
@@ -69,8 +70,4 @@ export declare function updateChatSettings(client: AgentClient, chatId: string,
|
|
|
69
70
|
export declare function resolveInterrupt(client: AgentClient, interruptId: string, decision: 'allow' | 'deny'): Promise<InterruptDTO>;
|
|
70
71
|
export declare function listRunInterrupts(client: AgentClient, runId: string): Promise<InterruptDTO[]>;
|
|
71
72
|
export declare function uploadFile(client: AgentClient, file: globalThis.File): Promise<FileRef>;
|
|
72
|
-
export declare function
|
|
73
|
-
url: string;
|
|
74
|
-
headers: Record<string, string>;
|
|
75
|
-
credentials: RequestCredentials;
|
|
76
|
-
};
|
|
73
|
+
export declare function chatStreamRequest(client: AgentClient, chatId: string): StreamRequest;
|
package/dist/agent/api.js
CHANGED
|
@@ -203,6 +203,6 @@ export async function listRunInterrupts(client, runId) {
|
|
|
203
203
|
export async function uploadFile(client, file) {
|
|
204
204
|
return client.files.upload(file);
|
|
205
205
|
}
|
|
206
|
-
export function
|
|
207
|
-
return client.http.
|
|
206
|
+
export function chatStreamRequest(client, chatId) {
|
|
207
|
+
return (init) => client.http.fetch(`/chats/${chatId}/stream`, init);
|
|
208
208
|
}
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface AlwaysAllowChoice {
|
|
|
19
19
|
*/
|
|
20
20
|
export interface AgentClient {
|
|
21
21
|
/** HTTP client for API requests */
|
|
22
|
-
http: Pick<HttpClient, 'request' | '
|
|
22
|
+
http: Pick<HttpClient, 'request' | 'fetch' | 'getStreamDefault' | 'getPollIntervalMs'>;
|
|
23
23
|
/** Files API for uploads */
|
|
24
24
|
files: {
|
|
25
25
|
upload: (data: string | Blob | globalThis.File) => Promise<FileRef>;
|
package/dist/api/agents.js
CHANGED
|
@@ -209,13 +209,11 @@ export class Agent {
|
|
|
209
209
|
streamUntilIdle(options, gate) {
|
|
210
210
|
if (!this.chatId)
|
|
211
211
|
return Promise.resolve();
|
|
212
|
-
const
|
|
212
|
+
const endpoint = `/chats/${this.chatId}/stream`;
|
|
213
213
|
return new Promise((resolve) => {
|
|
214
214
|
this.stream?.stop();
|
|
215
215
|
this.stream = new StreamableManager({
|
|
216
|
-
|
|
217
|
-
headers,
|
|
218
|
-
credentials,
|
|
216
|
+
request: (init) => this.http.fetch(endpoint, init),
|
|
219
217
|
});
|
|
220
218
|
// Last chat/run observation was idle but the gate wasn't settled yet;
|
|
221
219
|
// a terminal message for this turn can settle it.
|
package/dist/api/tasks.js
CHANGED
|
@@ -110,7 +110,6 @@ export class TasksAPI {
|
|
|
110
110
|
const { onUpdate, onPartialUpdate, onDelta } = options;
|
|
111
111
|
// Accumulate state across partial updates to preserve fields like session_id
|
|
112
112
|
let accumulatedTask = { ...task };
|
|
113
|
-
const { url, headers, credentials } = this.http.getStreamableConfig(`/tasks/${task.id}/stream`);
|
|
114
113
|
let streamManager;
|
|
115
114
|
const done = new Promise((resolve, reject) => {
|
|
116
115
|
const settle = (data, stripped) => {
|
|
@@ -128,9 +127,7 @@ export class TasksAPI {
|
|
|
128
127
|
}
|
|
129
128
|
};
|
|
130
129
|
streamManager = new StreamableManager({
|
|
131
|
-
|
|
132
|
-
headers,
|
|
133
|
-
credentials,
|
|
130
|
+
request: (init) => this.http.fetch(`/tasks/${task.id}/stream`, init),
|
|
134
131
|
onDelta,
|
|
135
132
|
onData: (data) => {
|
|
136
133
|
// Merge new data, preserving existing fields if not in update
|
package/dist/http/client.d.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
import type { Response } from './response';
|
|
2
2
|
import { EventSource } from 'eventsource';
|
|
3
|
+
/** What a failed request was sent with, for an error handler that acts on it. */
|
|
4
|
+
export interface FailedRequest {
|
|
5
|
+
/**
|
|
6
|
+
* The bearer token the request carried, or undefined when it carried none
|
|
7
|
+
* (proxy mode, or no apiKey and getToken returned nothing). A handler that
|
|
8
|
+
* refreshes credentials compares it with the token in hand: when they
|
|
9
|
+
* differ, the credentials were already replaced and a retry is enough.
|
|
10
|
+
*/
|
|
11
|
+
token: string | undefined;
|
|
12
|
+
}
|
|
3
13
|
/**
|
|
4
14
|
* Error handler that can intercept errors and optionally retry the request.
|
|
5
15
|
* Return a promise to retry with a new result, or throw/rethrow to propagate the error.
|
|
16
|
+
* `retry` sends the request again with the token of that moment and does not
|
|
17
|
+
* come back through the handler. `request` describes the attempt that failed.
|
|
6
18
|
*/
|
|
7
|
-
export type ErrorHandler = (error: unknown, retry: () => Promise<unknown
|
|
19
|
+
export type ErrorHandler = (error: unknown, retry: () => Promise<unknown>, request: FailedRequest) => Promise<unknown>;
|
|
20
|
+
/** Options of HttpClient.fetch: a fetch init whose credentials mode is the client's. */
|
|
21
|
+
export type HttpFetchInit = Omit<RequestInit, 'headers' | 'credentials'> & {
|
|
22
|
+
headers?: Record<string, string>;
|
|
23
|
+
};
|
|
8
24
|
export type MessageHandler = (messages: import('../types').ResponseMessage[]) => void;
|
|
9
25
|
export interface HttpClientConfig {
|
|
10
26
|
/** Your inference.sh API key (required unless using proxyUrl) */
|
|
@@ -16,8 +32,11 @@ export interface HttpClientConfig {
|
|
|
16
32
|
* When set, requests are routed through your proxy server to protect API keys.
|
|
17
33
|
*/
|
|
18
34
|
proxyUrl?: string;
|
|
19
|
-
/**
|
|
20
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Dynamic token getter (alternative to apiKey), asked before every request.
|
|
37
|
+
* It may be async: the request waits for the token.
|
|
38
|
+
*/
|
|
39
|
+
getToken?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
21
40
|
/** Dynamic headers */
|
|
22
41
|
headers?: Record<string, string | (() => string | undefined)>;
|
|
23
42
|
/** Request credentials mode */
|
|
@@ -71,15 +90,53 @@ export declare class HttpClient {
|
|
|
71
90
|
isProxyMode(): boolean;
|
|
72
91
|
/** Resolve dynamic headers */
|
|
73
92
|
private resolveHeaders;
|
|
74
|
-
/**
|
|
75
|
-
private
|
|
93
|
+
/** The bearer token a request sent now carries; none through a proxy, which adds its own. */
|
|
94
|
+
private bearerToken;
|
|
95
|
+
/** The configured headers plus what identifies the request: its bearer, or through a proxy its target. */
|
|
96
|
+
private requestHeaders;
|
|
97
|
+
/**
|
|
98
|
+
* Where a request whose caller cannot set headers (EventSource) or reads
|
|
99
|
+
* the URL (streams) goes: the API, or the proxy with the target as a query
|
|
100
|
+
* parameter.
|
|
101
|
+
*/
|
|
102
|
+
private streamUrl;
|
|
76
103
|
/**
|
|
77
104
|
* Make an HTTP request to the API
|
|
78
105
|
*/
|
|
79
|
-
request<T, P extends object = Record<string, unknown>>(method: 'get' | 'post' | 'put' | 'delete', endpoint: string, options?: {
|
|
106
|
+
request<T, P extends object = Record<string, unknown>>(method: 'get' | 'post' | 'put' | 'delete', endpoint: string, { handleErrors, ...options }?: {
|
|
80
107
|
params?: P;
|
|
81
108
|
data?: unknown;
|
|
109
|
+
/**
|
|
110
|
+
* `false` when the caller handles this request's failure itself: the
|
|
111
|
+
* client's error handler (onError) is not consulted, so there is no
|
|
112
|
+
* prompt, no redirect and no retry, and the error is thrown as it is.
|
|
113
|
+
*/
|
|
114
|
+
handleErrors?: boolean;
|
|
82
115
|
}): Promise<Response<T>>;
|
|
116
|
+
/**
|
|
117
|
+
* Fetch an API endpoint with the client's auth, headers and credentials
|
|
118
|
+
* mode and resolve with the raw response, for bodies request() does not
|
|
119
|
+
* parse (streams, text). A failure goes through onError like one of
|
|
120
|
+
* request() does: a refused response, or a request that got no response.
|
|
121
|
+
* It resolves with the response onError's retry got; when onError resolves
|
|
122
|
+
* with anything else the failure stands and is thrown, the error request()
|
|
123
|
+
* would throw. A request aborted through `init.signal` rejects with the
|
|
124
|
+
* abort and is not an error for onError.
|
|
125
|
+
*/
|
|
126
|
+
fetch(endpoint: string, init?: HttpFetchInit): Promise<globalThis.Response>;
|
|
127
|
+
/**
|
|
128
|
+
* One fetch of `url` on behalf of `targetUrl`. A refused response, or a
|
|
129
|
+
* request that got none, goes to onError; the result is the response its
|
|
130
|
+
* retry got. Without one the failure stands: the error of a request that
|
|
131
|
+
* got no response is thrown, and a refusal is thrown as the error its body
|
|
132
|
+
* was read into or, for a caller that passes the response on
|
|
133
|
+
* (`refused: 'return'`), handed back with its body unread.
|
|
134
|
+
*/
|
|
135
|
+
private fetchHandled;
|
|
136
|
+
/** The error a refused response stands for, read from its body. */
|
|
137
|
+
private readError;
|
|
138
|
+
/** HTTP errors → RFC 9457 problem+json */
|
|
139
|
+
private responseError;
|
|
83
140
|
/**
|
|
84
141
|
* Execute the actual HTTP request (internal)
|
|
85
142
|
*/
|
|
@@ -87,6 +144,10 @@ export declare class HttpClient {
|
|
|
87
144
|
/**
|
|
88
145
|
* Get URL and headers for NDJSON streaming.
|
|
89
146
|
* Returns the full URL and auth headers needed for streamable requests.
|
|
147
|
+
* It answers synchronously, so it throws when getToken is async.
|
|
148
|
+
* @deprecated Use fetch(), or a StreamRequest built on it
|
|
149
|
+
* (`(init) => http.fetch(endpoint, init)`): a request made from this config
|
|
150
|
+
* bypasses onError and carries the token of the moment the config was read.
|
|
90
151
|
*/
|
|
91
152
|
getStreamableConfig(endpoint: string): {
|
|
92
153
|
url: string;
|
|
@@ -100,7 +161,7 @@ export declare class HttpClient {
|
|
|
100
161
|
private extractErrorDetail;
|
|
101
162
|
/**
|
|
102
163
|
* Create an EventSource for SSE streaming
|
|
103
|
-
* @deprecated Use
|
|
164
|
+
* @deprecated Use StreamableManager with a StreamRequest instead
|
|
104
165
|
*/
|
|
105
166
|
createEventSource(endpoint: string): Promise<EventSource | null>;
|
|
106
167
|
}
|
package/dist/http/client.js
CHANGED
|
@@ -54,32 +54,139 @@ export class HttpClient {
|
|
|
54
54
|
}
|
|
55
55
|
return resolved;
|
|
56
56
|
}
|
|
57
|
-
/**
|
|
58
|
-
|
|
59
|
-
if (this.
|
|
60
|
-
return
|
|
57
|
+
/** The bearer token a request sent now carries; none through a proxy, which adds its own. */
|
|
58
|
+
async bearerToken() {
|
|
59
|
+
if (this.proxyUrl)
|
|
60
|
+
return undefined;
|
|
61
|
+
return (this.getToken ? await this.getToken() : this.apiKey) || undefined;
|
|
62
|
+
}
|
|
63
|
+
/** The configured headers plus what identifies the request: its bearer, or through a proxy its target. */
|
|
64
|
+
requestHeaders(targetUrl, token) {
|
|
65
|
+
const headers = this.resolveHeaders();
|
|
66
|
+
if (this.proxyUrl) {
|
|
67
|
+
headers['x-inf-target-url'] = targetUrl.toString();
|
|
68
|
+
}
|
|
69
|
+
else if (token) {
|
|
70
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
61
71
|
}
|
|
62
|
-
return
|
|
72
|
+
return headers;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Where a request whose caller cannot set headers (EventSource) or reads
|
|
76
|
+
* the URL (streams) goes: the API, or the proxy with the target as a query
|
|
77
|
+
* parameter.
|
|
78
|
+
*/
|
|
79
|
+
streamUrl(targetUrl) {
|
|
80
|
+
if (!this.proxyUrl)
|
|
81
|
+
return targetUrl.toString();
|
|
82
|
+
const proxyUrlWithQuery = new URL(this.proxyUrl, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
|
|
83
|
+
proxyUrlWithQuery.searchParams.set('__inf_target', targetUrl.toString());
|
|
84
|
+
return proxyUrlWithQuery.toString();
|
|
63
85
|
}
|
|
64
86
|
/**
|
|
65
87
|
* Make an HTTP request to the API
|
|
66
88
|
*/
|
|
67
|
-
async request(method, endpoint, options = {}) {
|
|
68
|
-
const
|
|
89
|
+
async request(method, endpoint, { handleErrors = true, ...options } = {}) {
|
|
90
|
+
const send = (token) => this.executeRequest(method, endpoint, options, token);
|
|
91
|
+
const token = await this.bearerToken();
|
|
69
92
|
try {
|
|
70
|
-
return await
|
|
93
|
+
return await send(token);
|
|
71
94
|
}
|
|
72
95
|
catch (error) {
|
|
73
|
-
if (this.onError) {
|
|
74
|
-
return await this.onError(error,
|
|
96
|
+
if (this.onError && handleErrors) {
|
|
97
|
+
return await this.onError(error, async () => send(await this.bearerToken()), { token });
|
|
75
98
|
}
|
|
76
99
|
throw error;
|
|
77
100
|
}
|
|
78
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Fetch an API endpoint with the client's auth, headers and credentials
|
|
104
|
+
* mode and resolve with the raw response, for bodies request() does not
|
|
105
|
+
* parse (streams, text). A failure goes through onError like one of
|
|
106
|
+
* request() does: a refused response, or a request that got no response.
|
|
107
|
+
* It resolves with the response onError's retry got; when onError resolves
|
|
108
|
+
* with anything else the failure stands and is thrown, the error request()
|
|
109
|
+
* would throw. A request aborted through `init.signal` rejects with the
|
|
110
|
+
* abort and is not an error for onError.
|
|
111
|
+
*/
|
|
112
|
+
async fetch(endpoint, init = {}) {
|
|
113
|
+
const targetUrl = new URL(`${this.baseUrl}${endpoint}`);
|
|
114
|
+
const response = await this.fetchHandled(this.streamUrl(targetUrl), targetUrl, init, 'throw');
|
|
115
|
+
// What onError's retry got is handed over unread, and can be a refusal too.
|
|
116
|
+
if (!response.ok)
|
|
117
|
+
throw await this.readError(response);
|
|
118
|
+
return response;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* One fetch of `url` on behalf of `targetUrl`. A refused response, or a
|
|
122
|
+
* request that got none, goes to onError; the result is the response its
|
|
123
|
+
* retry got. Without one the failure stands: the error of a request that
|
|
124
|
+
* got no response is thrown, and a refusal is thrown as the error its body
|
|
125
|
+
* was read into or, for a caller that passes the response on
|
|
126
|
+
* (`refused: 'return'`), handed back with its body unread.
|
|
127
|
+
*/
|
|
128
|
+
async fetchHandled(url, targetUrl, init, refused) {
|
|
129
|
+
const send = (token) => fetch(url, {
|
|
130
|
+
...init,
|
|
131
|
+
headers: { ...init.headers, ...this.requestHeaders(targetUrl, token) },
|
|
132
|
+
credentials: this.credentials,
|
|
133
|
+
});
|
|
134
|
+
const retry = async () => send(await this.bearerToken());
|
|
135
|
+
const token = await this.bearerToken();
|
|
136
|
+
let response;
|
|
137
|
+
try {
|
|
138
|
+
response = await send(token);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
// The caller aborted the request; nothing failed.
|
|
142
|
+
if (!this.onError || init.signal?.aborted)
|
|
143
|
+
throw error;
|
|
144
|
+
const handled = await this.onError(error, retry, { token });
|
|
145
|
+
if (handled instanceof globalThis.Response)
|
|
146
|
+
return handled;
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
if (response.ok || (refused === 'return' && !this.onError))
|
|
150
|
+
return response;
|
|
151
|
+
// The body is read once: from a clone only when the response is handed back.
|
|
152
|
+
const error = await this.readError(refused === 'return' ? response.clone() : response);
|
|
153
|
+
const handled = await this.onError?.(error, retry, { token });
|
|
154
|
+
if (handled instanceof globalThis.Response)
|
|
155
|
+
return handled;
|
|
156
|
+
if (refused === 'return')
|
|
157
|
+
return response;
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
/** The error a refused response stands for, read from its body. */
|
|
161
|
+
async readError(response) {
|
|
162
|
+
const responseText = await response.text().catch(() => '');
|
|
163
|
+
let data = null;
|
|
164
|
+
try {
|
|
165
|
+
data = JSON.parse(responseText);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// Not JSON
|
|
169
|
+
}
|
|
170
|
+
return this.responseError(response.status, responseText, data);
|
|
171
|
+
}
|
|
172
|
+
/** HTTP errors → RFC 9457 problem+json */
|
|
173
|
+
responseError(status, responseText, data) {
|
|
174
|
+
if (status === 412 && data && typeof data === 'object' && 'errors' in data && Array.isArray(data.errors)) {
|
|
175
|
+
return RequirementsNotMetException.fromResponse(data, status);
|
|
176
|
+
}
|
|
177
|
+
let errorDetail;
|
|
178
|
+
if (data && typeof data === 'object') {
|
|
179
|
+
errorDetail = this.extractErrorDetail(data) ?? JSON.stringify(data);
|
|
180
|
+
}
|
|
181
|
+
else if (responseText) {
|
|
182
|
+
errorDetail = responseText.slice(0, 500);
|
|
183
|
+
}
|
|
184
|
+
return new InferenceError(status, errorDetail || 'Request failed', responseText);
|
|
185
|
+
}
|
|
79
186
|
/**
|
|
80
187
|
* Execute the actual HTTP request (internal)
|
|
81
188
|
*/
|
|
82
|
-
async executeRequest(method, endpoint, options
|
|
189
|
+
async executeRequest(method, endpoint, options, token) {
|
|
83
190
|
// Build the target URL (always points to the API)
|
|
84
191
|
const targetUrl = new URL(`${this.baseUrl}${endpoint}`);
|
|
85
192
|
if (options.params) {
|
|
@@ -92,23 +199,11 @@ export class HttpClient {
|
|
|
92
199
|
});
|
|
93
200
|
}
|
|
94
201
|
// In proxy mode, requests go to the proxy with target URL in a header
|
|
95
|
-
const
|
|
96
|
-
const fetchUrl = isProxyMode ? this.proxyUrl : targetUrl.toString();
|
|
202
|
+
const fetchUrl = this.proxyUrl ?? targetUrl.toString();
|
|
97
203
|
const headers = {
|
|
98
204
|
'Content-Type': 'application/json',
|
|
99
|
-
...this.
|
|
205
|
+
...this.requestHeaders(targetUrl, token),
|
|
100
206
|
};
|
|
101
|
-
if (isProxyMode) {
|
|
102
|
-
// Proxy mode: send target URL as header, no auth (proxy handles it)
|
|
103
|
-
headers['x-inf-target-url'] = targetUrl.toString();
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
// Direct mode: include authorization header
|
|
107
|
-
const token = this.getAuthToken();
|
|
108
|
-
if (token) {
|
|
109
|
-
headers['Authorization'] = `Bearer ${token}`;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
207
|
const fetchOptions = {
|
|
113
208
|
method: method.toUpperCase(),
|
|
114
209
|
headers,
|
|
@@ -126,19 +221,8 @@ export class HttpClient {
|
|
|
126
221
|
catch {
|
|
127
222
|
// Not JSON
|
|
128
223
|
}
|
|
129
|
-
// HTTP errors → RFC 9457 problem+json
|
|
130
224
|
if (!response.ok) {
|
|
131
|
-
|
|
132
|
-
throw RequirementsNotMetException.fromResponse(data, response.status);
|
|
133
|
-
}
|
|
134
|
-
let errorDetail;
|
|
135
|
-
if (data && typeof data === 'object') {
|
|
136
|
-
errorDetail = this.extractErrorDetail(data) ?? JSON.stringify(data);
|
|
137
|
-
}
|
|
138
|
-
else if (responseText) {
|
|
139
|
-
errorDetail = responseText.slice(0, 500);
|
|
140
|
-
}
|
|
141
|
-
throw new InferenceError(response.status, errorDetail || 'Request failed', responseText);
|
|
225
|
+
throw this.responseError(response.status, responseText, data);
|
|
142
226
|
}
|
|
143
227
|
if (response.status === 204 || !responseText) {
|
|
144
228
|
return { data: undefined, messages: [] };
|
|
@@ -156,26 +240,22 @@ export class HttpClient {
|
|
|
156
240
|
/**
|
|
157
241
|
* Get URL and headers for NDJSON streaming.
|
|
158
242
|
* Returns the full URL and auth headers needed for streamable requests.
|
|
243
|
+
* It answers synchronously, so it throws when getToken is async.
|
|
244
|
+
* @deprecated Use fetch(), or a StreamRequest built on it
|
|
245
|
+
* (`(init) => http.fetch(endpoint, init)`): a request made from this config
|
|
246
|
+
* bypasses onError and carries the token of the moment the config was read.
|
|
159
247
|
*/
|
|
160
248
|
getStreamableConfig(endpoint) {
|
|
161
249
|
const targetUrl = new URL(`${this.baseUrl}${endpoint}`);
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (isProxyMode) {
|
|
166
|
-
const proxyUrlWithQuery = new URL(this.proxyUrl, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
|
|
167
|
-
proxyUrlWithQuery.searchParams.set('__inf_target', targetUrl.toString());
|
|
168
|
-
url = proxyUrlWithQuery.toString();
|
|
169
|
-
headers['x-inf-target-url'] = targetUrl.toString();
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
url = targetUrl.toString();
|
|
173
|
-
const token = this.getAuthToken();
|
|
174
|
-
if (token) {
|
|
175
|
-
headers['Authorization'] = `Bearer ${token}`;
|
|
176
|
-
}
|
|
250
|
+
const token = this.proxyUrl ? undefined : this.getToken ? this.getToken() : this.apiKey;
|
|
251
|
+
if (token instanceof Promise) {
|
|
252
|
+
throw new Error('getStreamableConfig() cannot wait for an async getToken; use fetch() instead');
|
|
177
253
|
}
|
|
178
|
-
return {
|
|
254
|
+
return {
|
|
255
|
+
url: this.streamUrl(targetUrl),
|
|
256
|
+
headers: this.requestHeaders(targetUrl, token || undefined),
|
|
257
|
+
credentials: this.credentials,
|
|
258
|
+
};
|
|
179
259
|
}
|
|
180
260
|
/**
|
|
181
261
|
* Pull a human-readable detail string from a parsed problem+json / API error
|
|
@@ -189,56 +269,16 @@ export class HttpClient {
|
|
|
189
269
|
}
|
|
190
270
|
/**
|
|
191
271
|
* Create an EventSource for SSE streaming
|
|
192
|
-
* @deprecated Use
|
|
272
|
+
* @deprecated Use StreamableManager with a StreamRequest instead
|
|
193
273
|
*/
|
|
194
274
|
createEventSource(endpoint) {
|
|
195
275
|
const targetUrl = new URL(`${this.baseUrl}${endpoint}`);
|
|
196
|
-
const isProxyMode = !!this.proxyUrl;
|
|
197
|
-
// For proxy mode: Browser EventSource can't send custom headers,
|
|
198
|
-
// so append target URL as query param instead
|
|
199
|
-
let fetchUrl;
|
|
200
|
-
if (isProxyMode) {
|
|
201
|
-
const proxyUrlWithQuery = new URL(this.proxyUrl, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
|
|
202
|
-
proxyUrlWithQuery.searchParams.set('__inf_target', targetUrl.toString());
|
|
203
|
-
fetchUrl = proxyUrlWithQuery.toString();
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
fetchUrl = targetUrl.toString();
|
|
207
|
-
}
|
|
208
|
-
const resolvedHeaders = this.resolveHeaders();
|
|
209
276
|
// The EventSource error event omits the response body, so a failed initial
|
|
210
277
|
// connection (e.g. 403 otp_required) is handled here in the fetch wrapper:
|
|
211
278
|
// route it through onError like request() does, and hand the retried
|
|
212
279
|
// response (e.g. after OTP verification) back so the stream connects.
|
|
213
|
-
const doFetch =
|
|
214
|
-
|
|
215
|
-
...init?.headers,
|
|
216
|
-
...resolvedHeaders,
|
|
217
|
-
};
|
|
218
|
-
if (isProxyMode) {
|
|
219
|
-
headers['x-inf-target-url'] = targetUrl.toString();
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
const token = this.getAuthToken();
|
|
223
|
-
if (token) {
|
|
224
|
-
headers['Authorization'] = `Bearer ${token}`;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
const response = await fetch(input, { ...init, headers, credentials: this.credentials });
|
|
228
|
-
if (!response.ok && this.onError) {
|
|
229
|
-
const body = await response.clone().text().catch(() => '');
|
|
230
|
-
let data;
|
|
231
|
-
try {
|
|
232
|
-
data = JSON.parse(body);
|
|
233
|
-
}
|
|
234
|
-
catch { /* non-JSON body */ }
|
|
235
|
-
const error = new InferenceError(response.status, this.extractErrorDetail(data) ?? 'Request failed', body);
|
|
236
|
-
const handled = await this.onError(error, () => doFetch(input, init));
|
|
237
|
-
return handled ?? response;
|
|
238
|
-
}
|
|
239
|
-
return response;
|
|
240
|
-
};
|
|
241
|
-
return Promise.resolve(new EventSource(fetchUrl, { fetch: doFetch }));
|
|
280
|
+
const doFetch = (input, init) => this.fetchHandled(input, targetUrl, init ?? {}, 'return');
|
|
281
|
+
return Promise.resolve(new EventSource(this.streamUrl(targetUrl), { fetch: doFetch }));
|
|
242
282
|
}
|
|
243
283
|
}
|
|
244
284
|
/**
|
package/dist/http/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { HttpClient, type HttpClientConfig, type ErrorHandler, createHttpClient } from './client';
|
|
1
|
+
export { HttpClient, type HttpClientConfig, type ErrorHandler, type FailedRequest, type HttpFetchInit, createHttpClient } from './client';
|
|
2
2
|
export { StreamManager, type StreamManagerOptions, type PartialDataWrapper } from './stream';
|
|
3
|
-
export { streamable, streamableRaw, StreamableManager, type StreamableOptions, type StreamableMessage, type StreamableManagerOptions } from './streamable';
|
|
3
|
+
export { streamable, streamableRaw, StreamableManager, type StreamableOptions, type StreamableMessage, type StreamableManagerOptions, type StreamableSource, type StreamRequest, type StreamRequestInit } from './streamable';
|
|
4
4
|
export { InferenceError, RequirementsNotMetException } from './errors';
|
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
* This is the NDJSON alternative to SSE/EventSource that avoids
|
|
4
4
|
* the browser's ~6 connection limit per domain.
|
|
5
5
|
*/
|
|
6
|
+
/** What a stream asks of whatever sends its request. */
|
|
7
|
+
export interface StreamRequestInit {
|
|
8
|
+
method: 'GET' | 'POST';
|
|
9
|
+
headers: Record<string, string>;
|
|
10
|
+
body?: string;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Sends a stream's request in place of a plain fetch of a URL. With
|
|
15
|
+
* `(init) => http.fetch(endpoint, init)` the request carries the client's
|
|
16
|
+
* auth and a refusal goes through its error handler.
|
|
17
|
+
*/
|
|
18
|
+
export type StreamRequest = (init: StreamRequestInit) => Promise<Response>;
|
|
6
19
|
export interface StreamableOptions {
|
|
7
20
|
/** Additional headers to include */
|
|
8
21
|
headers?: Record<string, string>;
|
|
@@ -14,7 +27,7 @@ export interface StreamableOptions {
|
|
|
14
27
|
signal?: AbortSignal;
|
|
15
28
|
/** Skip heartbeat messages (default: true) */
|
|
16
29
|
skipHeartbeats?: boolean;
|
|
17
|
-
/** Request credentials mode (for cookie-based auth) */
|
|
30
|
+
/** Request credentials mode (for cookie-based auth); a StreamRequest brings its own */
|
|
18
31
|
credentials?: RequestCredentials;
|
|
19
32
|
}
|
|
20
33
|
export interface StreamableMessage<T = unknown> {
|
|
@@ -30,19 +43,26 @@ export interface StreamableMessage<T = unknown> {
|
|
|
30
43
|
/**
|
|
31
44
|
* Stream NDJSON from an HTTP endpoint using fetch + ReadableStream.
|
|
32
45
|
* Yields parsed JSON objects, automatically filtering heartbeats.
|
|
46
|
+
* `source` is the URL to fetch, or a StreamRequest that sends the request.
|
|
33
47
|
*/
|
|
34
|
-
export declare function streamable<T = unknown>(
|
|
48
|
+
export declare function streamable<T = unknown>(source: string | StreamRequest, options?: StreamableOptions): AsyncGenerator<T>;
|
|
35
49
|
/**
|
|
36
50
|
* StreamableManager provides a callback-based API similar to StreamManager
|
|
37
51
|
* but uses fetch + ReadableStream instead of EventSource.
|
|
38
52
|
*/
|
|
39
|
-
|
|
53
|
+
/** Where a StreamableManager's stream comes from: a URL it fetches, or a StreamRequest. */
|
|
54
|
+
export type StreamableSource = {
|
|
40
55
|
/** URL to connect to */
|
|
41
56
|
url: string;
|
|
42
57
|
/** Additional headers */
|
|
43
58
|
headers?: Record<string, string>;
|
|
44
59
|
/** Request credentials mode (for cookie-based auth) */
|
|
45
60
|
credentials?: RequestCredentials;
|
|
61
|
+
} | {
|
|
62
|
+
/** Sends the request, e.g. `(init) => http.fetch(endpoint, init)` */
|
|
63
|
+
request: StreamRequest;
|
|
64
|
+
};
|
|
65
|
+
export type StreamableManagerOptions<T> = StreamableSource & {
|
|
46
66
|
/** Request body */
|
|
47
67
|
body?: unknown;
|
|
48
68
|
/** Called for each message */
|
|
@@ -57,7 +77,7 @@ export interface StreamableManagerOptions<T> {
|
|
|
57
77
|
onEnd?: () => void;
|
|
58
78
|
/** Called for delta events (streaming token deltas) */
|
|
59
79
|
onDelta?: (delta: Record<string, any>, seq: number) => void;
|
|
60
|
-
}
|
|
80
|
+
};
|
|
61
81
|
export declare class StreamableManager<T> {
|
|
62
82
|
private options;
|
|
63
83
|
private abortController;
|
|
@@ -76,4 +96,4 @@ export declare class StreamableManager<T> {
|
|
|
76
96
|
* Raw streamable that yields the full message including wrapper.
|
|
77
97
|
* Use this when you need access to event type or fields.
|
|
78
98
|
*/
|
|
79
|
-
export declare function streamableRaw<T = unknown>(
|
|
99
|
+
export declare function streamableRaw<T = unknown>(source: string | StreamRequest, options?: StreamableOptions): AsyncGenerator<StreamableMessage<T> | T>;
|
package/dist/http/streamable.js
CHANGED
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
* This is the NDJSON alternative to SSE/EventSource that avoids
|
|
4
4
|
* the browser's ~6 connection limit per domain.
|
|
5
5
|
*/
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
* Yields parsed JSON objects, automatically filtering heartbeats.
|
|
9
|
-
*/
|
|
10
|
-
export async function* streamable(url, options = {}) {
|
|
11
|
-
const { headers = {}, body, method = body ? 'POST' : 'GET', signal, skipHeartbeats = true, credentials, } = options;
|
|
6
|
+
/** Send the stream's request and hand back the body to read. */
|
|
7
|
+
async function openStream(source, { headers = {}, body, method = body ? 'POST' : 'GET', signal, credentials }) {
|
|
12
8
|
const requestHeaders = {
|
|
13
9
|
Accept: 'application/x-ndjson',
|
|
14
10
|
...headers,
|
|
@@ -16,13 +12,13 @@ export async function* streamable(url, options = {}) {
|
|
|
16
12
|
if (body) {
|
|
17
13
|
requestHeaders['Content-Type'] = 'application/json';
|
|
18
14
|
}
|
|
19
|
-
const
|
|
15
|
+
const init = {
|
|
20
16
|
method,
|
|
21
17
|
headers: requestHeaders,
|
|
22
18
|
body: body ? JSON.stringify(body) : undefined,
|
|
23
19
|
signal,
|
|
24
|
-
|
|
25
|
-
});
|
|
20
|
+
};
|
|
21
|
+
const res = typeof source === 'string' ? await fetch(source, { ...init, credentials }) : await source(init);
|
|
26
22
|
if (!res.ok) {
|
|
27
23
|
const text = await res.text();
|
|
28
24
|
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
@@ -30,7 +26,16 @@ export async function* streamable(url, options = {}) {
|
|
|
30
26
|
if (!res.body) {
|
|
31
27
|
throw new Error('No response body');
|
|
32
28
|
}
|
|
33
|
-
|
|
29
|
+
return res.body;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Stream NDJSON from an HTTP endpoint using fetch + ReadableStream.
|
|
33
|
+
* Yields parsed JSON objects, automatically filtering heartbeats.
|
|
34
|
+
* `source` is the URL to fetch, or a StreamRequest that sends the request.
|
|
35
|
+
*/
|
|
36
|
+
export async function* streamable(source, options = {}) {
|
|
37
|
+
const { skipHeartbeats = true } = options;
|
|
38
|
+
const reader = (await openStream(source, options)).getReader();
|
|
34
39
|
const decoder = new TextDecoder();
|
|
35
40
|
let buffer = '';
|
|
36
41
|
try {
|
|
@@ -109,12 +114,16 @@ export class StreamableManager {
|
|
|
109
114
|
this.abortController = new AbortController();
|
|
110
115
|
try {
|
|
111
116
|
this.options.onStart?.();
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
body:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
const { options } = this;
|
|
118
|
+
const stream = 'request' in options
|
|
119
|
+
? streamableRaw(options.request, { body: options.body, signal: this.abortController.signal })
|
|
120
|
+
: streamableRaw(options.url, {
|
|
121
|
+
headers: options.headers,
|
|
122
|
+
body: options.body,
|
|
123
|
+
signal: this.abortController.signal,
|
|
124
|
+
credentials: options.credentials,
|
|
125
|
+
});
|
|
126
|
+
for await (const message of stream) {
|
|
118
127
|
if (!this.isRunning)
|
|
119
128
|
break;
|
|
120
129
|
const wrapper = message;
|
|
@@ -179,30 +188,9 @@ export class StreamableManager {
|
|
|
179
188
|
* Raw streamable that yields the full message including wrapper.
|
|
180
189
|
* Use this when you need access to event type or fields.
|
|
181
190
|
*/
|
|
182
|
-
export async function* streamableRaw(
|
|
183
|
-
const {
|
|
184
|
-
const
|
|
185
|
-
Accept: 'application/x-ndjson',
|
|
186
|
-
...headers,
|
|
187
|
-
};
|
|
188
|
-
if (body) {
|
|
189
|
-
requestHeaders['Content-Type'] = 'application/json';
|
|
190
|
-
}
|
|
191
|
-
const res = await fetch(url, {
|
|
192
|
-
method,
|
|
193
|
-
headers: requestHeaders,
|
|
194
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
195
|
-
signal,
|
|
196
|
-
credentials,
|
|
197
|
-
});
|
|
198
|
-
if (!res.ok) {
|
|
199
|
-
const text = await res.text();
|
|
200
|
-
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
201
|
-
}
|
|
202
|
-
if (!res.body) {
|
|
203
|
-
throw new Error('No response body');
|
|
204
|
-
}
|
|
205
|
-
const reader = res.body.getReader();
|
|
191
|
+
export async function* streamableRaw(source, options = {}) {
|
|
192
|
+
const { skipHeartbeats = true } = options;
|
|
193
|
+
const reader = (await openStream(source, options)).getReader();
|
|
206
194
|
const decoder = new TextDecoder();
|
|
207
195
|
let buffer = '';
|
|
208
196
|
try {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { HttpClient, type HttpClientConfig, type ErrorHandler, type MessageHandler, createHttpClient } from './http/client';
|
|
1
|
+
export { HttpClient, type HttpClientConfig, type ErrorHandler, type FailedRequest, type HttpFetchInit, type MessageHandler, createHttpClient } from './http/client';
|
|
2
2
|
export type { Response } from './http/response';
|
|
3
3
|
import type { Response } from './http/response';
|
|
4
4
|
export { StreamManager, type StreamManagerOptions, type PartialDataWrapper } from './http/stream';
|
|
5
|
-
export { StreamableManager, type StreamableManagerOptions, type StreamableMessage, streamable, streamableRaw } from './http/streamable';
|
|
5
|
+
export { StreamableManager, type StreamableManagerOptions, type StreamableSource, type StreamRequest, type StreamRequestInit, type StreamableMessage, streamable, streamableRaw } from './http/streamable';
|
|
6
6
|
export { PollManager, type PollManagerOptions } from './http/poll';
|
|
7
7
|
export { InferenceError, RequirementsNotMetException, SessionError, SessionNotFoundError, SessionExpiredError, SessionEndedError, WorkerLostError, isRequirementsNotMetException, isInferenceError, isSessionError, } from './http/errors';
|
|
8
8
|
export { TasksAPI, type RunOptions, type WatchOptions, type TaskWatch } from './api/tasks';
|
package/dist/types.d.ts
CHANGED
|
@@ -481,6 +481,12 @@ export interface CreateAppRequest {
|
|
|
481
481
|
agent_description?: string;
|
|
482
482
|
category?: AppCategory;
|
|
483
483
|
images?: AppImages;
|
|
484
|
+
/**
|
|
485
|
+
* Tags replace the app's tags when given; omitted, a deploy takes them
|
|
486
|
+
* from the version's metadata.tags, and keeps the stored ones if that is
|
|
487
|
+
* empty too.
|
|
488
|
+
*/
|
|
489
|
+
tags?: string[];
|
|
484
490
|
version?: AppVersionInput;
|
|
485
491
|
preserve_current_version?: boolean;
|
|
486
492
|
}
|
|
@@ -1220,6 +1226,12 @@ export interface AppDTO extends BaseModelDTO, PermissionModelDTO {
|
|
|
1220
1226
|
agent_description: string;
|
|
1221
1227
|
category: AppCategory;
|
|
1222
1228
|
images: AppImages;
|
|
1229
|
+
/**
|
|
1230
|
+
* Tags name what the app does and its traits, as lowercase slugs
|
|
1231
|
+
* (text-to-image, open-weights). GET /store/tags lists the ones in use
|
|
1232
|
+
* with their titles.
|
|
1233
|
+
*/
|
|
1234
|
+
tags: string[];
|
|
1223
1235
|
version_id: string;
|
|
1224
1236
|
version?: AppVersionDTO;
|
|
1225
1237
|
status: AppStatus;
|
|
@@ -2427,7 +2439,7 @@ export interface DecideEntitlementRequestRequest {
|
|
|
2427
2439
|
* and APIError.Code on the legacy envelope. Clients branch on these, so a
|
|
2428
2440
|
* code is a named const here, where it generates into models and the SDKs.
|
|
2429
2441
|
*/
|
|
2430
|
-
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" | "mcp_auth_expired" | "limit_exceeded" | "feature_not_available" | "entitlement_unavailable" | "payment_required" | "payment_method_required" | "form_closed" | "already_submitted" | "already_claimed" | "already_entitled" | "request_open" | "agents_disabled" | "remote_offline" | "remote_timeout" | "harness_not_drivable" | "harness_too_old";
|
|
2442
|
+
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" | "impersonation_reason_required" | "mcp_auth_expired" | "limit_exceeded" | "feature_not_available" | "entitlement_unavailable" | "payment_required" | "payment_method_required" | "form_closed" | "already_submitted" | "already_claimed" | "already_entitled" | "request_open" | "agents_disabled" | "remote_offline" | "remote_timeout" | "harness_not_drivable" | "harness_too_old";
|
|
2431
2443
|
export declare const ErrorCodeInvalidRequest: ErrorCode;
|
|
2432
2444
|
export declare const ErrorCodeValidationError: ErrorCode;
|
|
2433
2445
|
export declare const ErrorCodeUnauthorized: ErrorCode;
|
|
@@ -2471,6 +2483,12 @@ export declare const ErrorCodeAccountBanned: ErrorCode;
|
|
|
2471
2483
|
*/
|
|
2472
2484
|
export declare const ErrorCodePersonRequired: ErrorCode;
|
|
2473
2485
|
export declare const ErrorCodeOTPRequired: ErrorCode;
|
|
2486
|
+
/**
|
|
2487
|
+
* ErrorCodeImpersonationReasonRequired (403): a platform admin named a
|
|
2488
|
+
* team they are not a member of without a live impersonation grant.
|
|
2489
|
+
* Clients stop viewing as the team on it.
|
|
2490
|
+
*/
|
|
2491
|
+
export declare const ErrorCodeImpersonationReasonRequired: ErrorCode;
|
|
2474
2492
|
export declare const ErrorCodeMCPAuthExpired: ErrorCode;
|
|
2475
2493
|
/**
|
|
2476
2494
|
* Entitlements. LimitExceeded (402) and FeatureNotAvailable (403) carry
|
|
@@ -4077,6 +4095,23 @@ export interface StatBuckets {
|
|
|
4077
4095
|
this_week: number;
|
|
4078
4096
|
all_time: number;
|
|
4079
4097
|
}
|
|
4098
|
+
export interface StoreCategoryDTO {
|
|
4099
|
+
slug: string;
|
|
4100
|
+
name: string;
|
|
4101
|
+
description: string;
|
|
4102
|
+
icon: string;
|
|
4103
|
+
rank: number;
|
|
4104
|
+
count: number;
|
|
4105
|
+
}
|
|
4106
|
+
/**
|
|
4107
|
+
* StoreTagDTO is one app tag the store lists: a tag at least
|
|
4108
|
+
* shared.MinAppsPerListedTag public apps carry.
|
|
4109
|
+
*/
|
|
4110
|
+
export interface StoreTagDTO {
|
|
4111
|
+
slug: string;
|
|
4112
|
+
title: string;
|
|
4113
|
+
count: number;
|
|
4114
|
+
}
|
|
4080
4115
|
/**
|
|
4081
4116
|
* SubscriptionDTO for API responses
|
|
4082
4117
|
*/
|
|
@@ -4833,7 +4868,7 @@ export declare const ApiKeyScopeUser: ApiKeyScope;
|
|
|
4833
4868
|
* service account, not a person, and outlives the admin who created it.
|
|
4834
4869
|
*/
|
|
4835
4870
|
export declare const ApiKeyScopeWorkspace: ApiKeyScope;
|
|
4836
|
-
export type AppCategory = "image" | "video" | "audio" | "text" | "chat" | "3d" | "other" | "flow";
|
|
4871
|
+
export type AppCategory = "image" | "video" | "audio" | "text" | "chat" | "3d" | "other" | "flow" | "decision";
|
|
4837
4872
|
export declare const AppCategoryImage: AppCategory;
|
|
4838
4873
|
export declare const AppCategoryVideo: AppCategory;
|
|
4839
4874
|
export declare const AppCategoryAudio: AppCategory;
|
|
@@ -4842,6 +4877,10 @@ export declare const AppCategoryChat: AppCategory;
|
|
|
4842
4877
|
export declare const AppCategory3D: AppCategory;
|
|
4843
4878
|
export declare const AppCategoryOther: AppCategory;
|
|
4844
4879
|
export declare const AppCategoryFlow: AppCategory;
|
|
4880
|
+
/**
|
|
4881
|
+
* Decision models: typed questions in, a probability for every answer out, no generation.
|
|
4882
|
+
*/
|
|
4883
|
+
export declare const AppCategoryDecision: AppCategory;
|
|
4845
4884
|
export type AppStatus = "active" | "maintenance" | "deprecated" | "retired";
|
|
4846
4885
|
export declare const AppStatusActive: AppStatus;
|
|
4847
4886
|
export declare const AppStatusMaintenance: AppStatus;
|
|
@@ -5045,6 +5084,148 @@ export interface ChannelContext {
|
|
|
5045
5084
|
channel_type?: ChannelType;
|
|
5046
5085
|
channel_metadata?: any;
|
|
5047
5086
|
}
|
|
5087
|
+
/**
|
|
5088
|
+
* DecisionChoiceOption is one answer option of a choice question.
|
|
5089
|
+
*/
|
|
5090
|
+
export interface DecisionChoiceOption {
|
|
5091
|
+
/**
|
|
5092
|
+
* Name is returned as the choice and keys the probabilities.
|
|
5093
|
+
*/
|
|
5094
|
+
name: string;
|
|
5095
|
+
/**
|
|
5096
|
+
* Description says what the option covers.
|
|
5097
|
+
*/
|
|
5098
|
+
description?: any;
|
|
5099
|
+
}
|
|
5100
|
+
/**
|
|
5101
|
+
* DecisionChoiceQuestion asks which one of a fixed set of options holds.
|
|
5102
|
+
*/
|
|
5103
|
+
export interface DecisionChoiceQuestion {
|
|
5104
|
+
/**
|
|
5105
|
+
* ID is the caller's key for the question; its answer comes back under it.
|
|
5106
|
+
*/
|
|
5107
|
+
id: string;
|
|
5108
|
+
instructions: any;
|
|
5109
|
+
options: DecisionChoiceOption[];
|
|
5110
|
+
}
|
|
5111
|
+
/**
|
|
5112
|
+
* DecisionScoreQuestion asks where the state sits on ordered levels.
|
|
5113
|
+
*/
|
|
5114
|
+
export interface DecisionScoreQuestion {
|
|
5115
|
+
id: string;
|
|
5116
|
+
instructions: any;
|
|
5117
|
+
/**
|
|
5118
|
+
* Levels are described low end to high end; a level's number is its index.
|
|
5119
|
+
*/
|
|
5120
|
+
levels: any[];
|
|
5121
|
+
}
|
|
5122
|
+
/**
|
|
5123
|
+
* DecisionNoulCriteria pins down what yes and no mean for a noul question.
|
|
5124
|
+
*/
|
|
5125
|
+
export interface DecisionNoulCriteria {
|
|
5126
|
+
true?: any;
|
|
5127
|
+
false?: any;
|
|
5128
|
+
}
|
|
5129
|
+
/**
|
|
5130
|
+
* DecisionNoulQuestion asks for the probability that something is true.
|
|
5131
|
+
*/
|
|
5132
|
+
export interface DecisionNoulQuestion {
|
|
5133
|
+
id: string;
|
|
5134
|
+
instructions: any;
|
|
5135
|
+
criteria?: DecisionNoulCriteria;
|
|
5136
|
+
}
|
|
5137
|
+
/**
|
|
5138
|
+
* DecisionInput is one state and the questions asked of it.
|
|
5139
|
+
*/
|
|
5140
|
+
export interface DecisionInput {
|
|
5141
|
+
state: any;
|
|
5142
|
+
choices?: DecisionChoiceQuestion[];
|
|
5143
|
+
scores?: DecisionScoreQuestion[];
|
|
5144
|
+
nouls?: DecisionNoulQuestion[];
|
|
5145
|
+
}
|
|
5146
|
+
/**
|
|
5147
|
+
* DecisionVisionInput is the input of a decision model that also sees
|
|
5148
|
+
* images: a DecisionInput plus the images the questions are about.
|
|
5149
|
+
*/
|
|
5150
|
+
export interface DecisionVisionInput extends DecisionInput {
|
|
5151
|
+
/**
|
|
5152
|
+
* Images are file URIs. Every question sees them.
|
|
5153
|
+
*/
|
|
5154
|
+
images?: string[];
|
|
5155
|
+
}
|
|
5156
|
+
/**
|
|
5157
|
+
* DecisionChoiceAnswer is the answer to a choice question.
|
|
5158
|
+
*/
|
|
5159
|
+
export interface DecisionChoiceAnswer {
|
|
5160
|
+
/**
|
|
5161
|
+
* Choice is the highest-probability option.
|
|
5162
|
+
*/
|
|
5163
|
+
choice: string;
|
|
5164
|
+
confidence: number;
|
|
5165
|
+
/**
|
|
5166
|
+
* Probabilities maps every option name to its probability.
|
|
5167
|
+
*/
|
|
5168
|
+
probabilities: {
|
|
5169
|
+
[key: string]: number;
|
|
5170
|
+
};
|
|
5171
|
+
}
|
|
5172
|
+
/**
|
|
5173
|
+
* DecisionScoreAnswer is the answer to a score question.
|
|
5174
|
+
*/
|
|
5175
|
+
export interface DecisionScoreAnswer {
|
|
5176
|
+
/**
|
|
5177
|
+
* Score is the probability-weighted level, 0 to the top level number.
|
|
5178
|
+
*/
|
|
5179
|
+
score: number;
|
|
5180
|
+
/**
|
|
5181
|
+
* Normalized is Score over the top level number: 0 to 1.
|
|
5182
|
+
*/
|
|
5183
|
+
normalized: number;
|
|
5184
|
+
confidence: number;
|
|
5185
|
+
/**
|
|
5186
|
+
* Probabilities maps each level number, as a string, to its probability.
|
|
5187
|
+
*/
|
|
5188
|
+
probabilities: {
|
|
5189
|
+
[key: string]: number;
|
|
5190
|
+
};
|
|
5191
|
+
/**
|
|
5192
|
+
* Legend maps each level number back to its description.
|
|
5193
|
+
*/
|
|
5194
|
+
legend: {
|
|
5195
|
+
[key: string]: any;
|
|
5196
|
+
};
|
|
5197
|
+
}
|
|
5198
|
+
/**
|
|
5199
|
+
* DecisionNoulAnswer is the answer to a noul question.
|
|
5200
|
+
*/
|
|
5201
|
+
export interface DecisionNoulAnswer {
|
|
5202
|
+
/**
|
|
5203
|
+
* Noul is the probability that the answer is yes.
|
|
5204
|
+
*/
|
|
5205
|
+
noul: number;
|
|
5206
|
+
}
|
|
5207
|
+
/**
|
|
5208
|
+
* DecisionOutput is the answers, keyed by question id within each kind.
|
|
5209
|
+
*/
|
|
5210
|
+
export interface DecisionOutput {
|
|
5211
|
+
choices: {
|
|
5212
|
+
[key: string]: DecisionChoiceAnswer;
|
|
5213
|
+
};
|
|
5214
|
+
scores: {
|
|
5215
|
+
[key: string]: DecisionScoreAnswer;
|
|
5216
|
+
};
|
|
5217
|
+
nouls: {
|
|
5218
|
+
[key: string]: DecisionNoulAnswer;
|
|
5219
|
+
};
|
|
5220
|
+
/**
|
|
5221
|
+
* Model is the model that answered.
|
|
5222
|
+
*/
|
|
5223
|
+
model: string;
|
|
5224
|
+
/**
|
|
5225
|
+
* InputTokens is what the model read; decision models write none.
|
|
5226
|
+
*/
|
|
5227
|
+
input_tokens: number;
|
|
5228
|
+
}
|
|
5048
5229
|
/**
|
|
5049
5230
|
* DescriptionLimit is the most characters a resource's description may have.
|
|
5050
5231
|
*/
|
package/dist/types.js
CHANGED
|
@@ -379,6 +379,12 @@ export const ErrorCodeAccountBanned = "account_banned";
|
|
|
379
379
|
*/
|
|
380
380
|
export const ErrorCodePersonRequired = "person_required";
|
|
381
381
|
export const ErrorCodeOTPRequired = "otp_required";
|
|
382
|
+
/**
|
|
383
|
+
* ErrorCodeImpersonationReasonRequired (403): a platform admin named a
|
|
384
|
+
* team they are not a member of without a live impersonation grant.
|
|
385
|
+
* Clients stop viewing as the team on it.
|
|
386
|
+
*/
|
|
387
|
+
export const ErrorCodeImpersonationReasonRequired = "impersonation_reason_required";
|
|
382
388
|
export const ErrorCodeMCPAuthExpired = "mcp_auth_expired";
|
|
383
389
|
/**
|
|
384
390
|
* Entitlements. LimitExceeded (402) and FeatureNotAvailable (403) carry
|
|
@@ -598,6 +604,10 @@ export const AppCategoryChat = "chat";
|
|
|
598
604
|
export const AppCategory3D = "3d";
|
|
599
605
|
export const AppCategoryOther = "other";
|
|
600
606
|
export const AppCategoryFlow = "flow";
|
|
607
|
+
/**
|
|
608
|
+
* Decision models: typed questions in, a probability for every answer out, no generation.
|
|
609
|
+
*/
|
|
610
|
+
export const AppCategoryDecision = "decision";
|
|
601
611
|
export const AppStatusActive = "active";
|
|
602
612
|
export const AppStatusMaintenance = "maintenance";
|
|
603
613
|
export const AppStatusDeprecated = "deprecated";
|