@inferencesh/sdk 0.20.1 → 0.22.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/dist/agent/actions.js +1 -4
  3. package/dist/agent/api.d.ts +37 -6
  4. package/dist/agent/api.js +37 -3
  5. package/dist/agent/reducer.js +23 -7
  6. package/dist/agent/types.d.ts +30 -5
  7. package/dist/api/agents.d.ts +9 -3
  8. package/dist/api/agents.js +87 -65
  9. package/dist/api/api-keys.d.ts +2 -5
  10. package/dist/api/apps.d.ts +9 -2
  11. package/dist/api/apps.js +9 -1
  12. package/dist/api/chats.d.ts +13 -3
  13. package/dist/api/chats.js +13 -2
  14. package/dist/api/engines.d.ts +4 -2
  15. package/dist/api/engines.js +3 -2
  16. package/dist/api/flow-runs.d.ts +7 -2
  17. package/dist/api/flow-runs.js +7 -2
  18. package/dist/api/flows.d.ts +13 -2
  19. package/dist/api/flows.js +15 -1
  20. package/dist/api/knowledge.d.ts +7 -4
  21. package/dist/api/knowledge.js +6 -4
  22. package/dist/api/mcp-servers.d.ts +2 -1
  23. package/dist/api/projects.d.ts +5 -3
  24. package/dist/api/projects.js +3 -2
  25. package/dist/api/secrets.d.ts +2 -2
  26. package/dist/api/tasks.js +39 -60
  27. package/dist/api/teams.d.ts +4 -2
  28. package/dist/api/teams.js +3 -2
  29. package/dist/api/write-bodies.d.ts +110 -0
  30. package/dist/api/write-bodies.js +1 -0
  31. package/dist/http/client.d.ts +68 -7
  32. package/dist/http/client.js +138 -97
  33. package/dist/http/index.d.ts +2 -2
  34. package/dist/http/loopback.d.ts +8 -0
  35. package/dist/http/loopback.js +18 -0
  36. package/dist/http/stream-until-terminal.d.ts +55 -0
  37. package/dist/http/stream-until-terminal.js +88 -0
  38. package/dist/http/stream.d.ts +1 -0
  39. package/dist/http/stream.js +7 -3
  40. package/dist/http/streamable.d.ts +25 -5
  41. package/dist/http/streamable.js +28 -40
  42. package/dist/index.d.ts +4 -2
  43. package/dist/index.js +1 -0
  44. package/dist/proxy/endpoints.json +156 -0
  45. package/dist/proxy/express.d.ts +5 -6
  46. package/dist/proxy/express.js +18 -2
  47. package/dist/proxy/hono.d.ts +5 -3
  48. package/dist/proxy/hono.js +4 -3
  49. package/dist/proxy/index.d.ts +165 -6
  50. package/dist/proxy/index.js +409 -25
  51. package/dist/proxy/nextjs.d.ts +29 -17
  52. package/dist/proxy/nextjs.js +72 -62
  53. package/dist/proxy/remix.d.ts +5 -3
  54. package/dist/proxy/remix.js +4 -3
  55. package/dist/proxy/svelte.d.ts +5 -4
  56. package/dist/proxy/svelte.js +4 -4
  57. package/dist/types.d.ts +591 -271
  58. package/dist/types.js +117 -252
  59. package/dist/version.d.ts +1 -0
  60. package/dist/version.js +7 -0
  61. package/package.json +2 -1
package/dist/api/tasks.js CHANGED
@@ -1,4 +1,4 @@
1
- import { StreamableManager } from '../http/streamable';
1
+ import { streamUntilTerminal } from '../http/stream-until-terminal';
2
2
  import { PollManager } from '../http/poll';
3
3
  import { TaskStatusCompleted, TaskStatusFailed, TaskStatusCancelled, } from '../types';
4
4
  import { parseStatus } from '../utils';
@@ -16,6 +16,20 @@ function stripTask(task) {
16
16
  session_id: task.session_id,
17
17
  };
18
18
  }
19
+ /** Settles a watch when `data` carries a terminal status; no-op otherwise. */
20
+ function settleTerminal(data, stripped, settle) {
21
+ switch (parseStatus(data.status)) {
22
+ case TaskStatusCompleted:
23
+ settle.resolve(stripped);
24
+ break;
25
+ case TaskStatusFailed:
26
+ settle.reject(new Error(data.error || 'task failed'));
27
+ break;
28
+ case TaskStatusCancelled:
29
+ settle.reject(new Error('task cancelled'));
30
+ break;
31
+ }
32
+ }
19
33
  /**
20
34
  * Tasks API
21
35
  */
@@ -110,50 +124,26 @@ export class TasksAPI {
110
124
  const { onUpdate, onPartialUpdate, onDelta } = options;
111
125
  // Accumulate state across partial updates to preserve fields like session_id
112
126
  let accumulatedTask = { ...task };
113
- const { url, headers, credentials } = this.http.getStreamableConfig(`/tasks/${task.id}/stream`);
114
- let streamManager;
115
- const done = new Promise((resolve, reject) => {
116
- const settle = (data, stripped) => {
117
- if (parseStatus(data.status) === TaskStatusCompleted) {
118
- streamManager.stop();
119
- resolve(stripped);
120
- }
121
- else if (parseStatus(data.status) === TaskStatusFailed) {
122
- streamManager.stop();
123
- reject(new Error(data.error || 'task failed'));
124
- }
125
- else if (parseStatus(data.status) === TaskStatusCancelled) {
126
- streamManager.stop();
127
- reject(new Error('task cancelled'));
128
- }
127
+ return streamUntilTerminal((settle) => {
128
+ const observe = (data, fields) => {
129
+ // Merge new data, preserving existing fields if not in update
130
+ accumulatedTask = { ...accumulatedTask, ...data };
131
+ const stripped = stripTask(accumulatedTask);
132
+ if (fields)
133
+ onPartialUpdate?.(stripped, fields);
134
+ else
135
+ onUpdate?.(stripped);
136
+ settleTerminal(data, stripped, settle);
129
137
  };
130
- streamManager = new StreamableManager({
131
- url,
132
- headers,
133
- credentials,
138
+ return {
139
+ request: (init) => this.http.fetch(`/tasks/${task.id}/stream`, init),
134
140
  onDelta,
135
- onData: (data) => {
136
- // Merge new data, preserving existing fields if not in update
137
- accumulatedTask = { ...accumulatedTask, ...data };
138
- const stripped = stripTask(accumulatedTask);
139
- onUpdate?.(stripped);
140
- settle(data, stripped);
141
- },
142
- onPartialData: (data, fields) => {
143
- // Merge partial update, preserving fields not in this update
144
- accumulatedTask = { ...accumulatedTask, ...data };
145
- const stripped = stripTask(accumulatedTask);
146
- onPartialUpdate?.(stripped, fields);
147
- settle(data, stripped);
148
- },
149
- onError: (error) => {
150
- reject(error);
151
- streamManager.stop();
152
- },
153
- });
154
- streamManager.start();
141
+ onData: (data) => observe(data),
142
+ onPartialData: (data, fields) => observe(data, fields),
143
+ reconcile: async () => observe((await this.get(task.id)).data),
144
+ closedMessage: `Task stream closed before task ${task.id} finished`,
145
+ };
155
146
  });
156
- return { done, stop: () => streamManager.stop() };
157
147
  }
158
148
  /** Poll GET /tasks/{id}/status until terminal, full-fetch on status change. */
159
149
  watchPoll(task, options) {
@@ -162,6 +152,10 @@ export class TasksAPI {
162
152
  let prevStatus = task.status;
163
153
  let poller;
164
154
  const done = new Promise((resolve, reject) => {
155
+ const settle = {
156
+ resolve: (value) => { poller.stop(); resolve(value); },
157
+ reject: (error) => { poller.stop(); reject(error); },
158
+ };
165
159
  poller = new PollManager({
166
160
  pollFunction: async () => {
167
161
  const resp = await this.http.request('get', `/tasks/${task.id}/status`);
@@ -179,28 +173,13 @@ export class TasksAPI {
179
173
  const fullTask = fullResp.data;
180
174
  const stripped = stripTask(fullTask);
181
175
  onUpdate?.(stripped);
182
- if (parseStatus(fullTask.status) === TaskStatusCompleted) {
183
- poller.stop();
184
- resolve(stripped);
185
- }
186
- else if (parseStatus(fullTask.status) === TaskStatusFailed) {
187
- poller.stop();
188
- reject(new Error(fullTask.error || 'task failed'));
189
- }
190
- else if (parseStatus(fullTask.status) === TaskStatusCancelled) {
191
- poller.stop();
192
- reject(new Error('task cancelled'));
193
- }
176
+ settleTerminal(fullTask, stripped, settle);
194
177
  }
195
178
  catch (err) {
196
- poller.stop();
197
- reject(err instanceof Error ? err : new Error(String(err)));
179
+ settle.reject(err instanceof Error ? err : new Error(String(err)));
198
180
  }
199
181
  },
200
- onError: (error) => {
201
- reject(error);
202
- poller.stop();
203
- },
182
+ onError: (error) => settle.reject(error),
204
183
  });
205
184
  poller.start();
206
185
  });
@@ -1,5 +1,6 @@
1
1
  import { HttpClient } from '../http/client';
2
2
  import type { Response } from '../http/response';
3
+ import type { TeamUpdateBody } from './write-bodies';
3
4
  import { MeResponse, TeamDTO, TeamMemberDTO, TeamInviteDTO, TeamCreateRequest, TeamMemberAddRequest, TeamInviteCreateRequest, AvailabilityResponse } from '../types';
4
5
  /**
5
6
  * Teams API
@@ -24,9 +25,10 @@ export declare class TeamsAPI {
24
25
  */
25
26
  create(data: TeamCreateRequest): Promise<Response<TeamDTO>>;
26
27
  /**
27
- * Update a team
28
+ * Update a team's profile (PATCH): only the fields sent are written, the
29
+ * others keep their value.
28
30
  */
29
- update(teamId: string, data: Partial<TeamCreateRequest>): Promise<Response<TeamDTO>>;
31
+ update(teamId: string, data: TeamUpdateBody): Promise<Response<TeamDTO>>;
30
32
  /**
31
33
  * Delete a team
32
34
  */
package/dist/api/teams.js CHANGED
@@ -30,10 +30,11 @@ export class TeamsAPI {
30
30
  return this.http.request('post', '/teams', { data });
31
31
  }
32
32
  /**
33
- * Update a team
33
+ * Update a team's profile (PATCH): only the fields sent are written, the
34
+ * others keep their value.
34
35
  */
35
36
  async update(teamId, data) {
36
- return this.http.request('post', `/teams/${teamId}`, { data });
37
+ return this.http.request('patch', `/teams/${teamId}`, { data });
37
38
  }
38
39
  /**
39
40
  * Delete a team
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Request bodies of the generic create/update routes.
3
+ *
4
+ * Each type names exactly the fields its route writes; the API leaves every
5
+ * other field of the body alone (a full DTO sent back is fine, its other
6
+ * fields are ignored). A field with its own endpoint is listed next to the
7
+ * type that cannot set it.
8
+ *
9
+ * A POST /{resource}/{id} update writes every field below that the route
10
+ * takes: a field left out of the body is written empty. A PATCH writes only
11
+ * the fields sent. The SDK's update methods for projects, knowledge, skills,
12
+ * chats, engines and teams send PATCH; apps.patch and flows.patch are the
13
+ * partial siblings of the POST updates that also edit a version.
14
+ */
15
+ import type { AgentConfigInput, AgentImages, AppDTO, ChatDTO, EngineDTO, FlowDTO, FlowVersionDTO, KnowledgeDTO, MCPServerAuthType, ProjectDTO, TeamDTO, Visibility } from '../types';
16
+ /**
17
+ * POST /agents/{id}. Visibility and images, and a new version when
18
+ * `version` is set. Name, title, harness, placement: set at creation.
19
+ * Project: `agents.moveToProject`; owner: `agents.transferOwnership`.
20
+ */
21
+ export interface AgentUpdateBody {
22
+ visibility?: Visibility;
23
+ images?: AgentImages;
24
+ version?: AgentConfigInput;
25
+ }
26
+ /**
27
+ * PATCH /apps/{id}: only the fields sent are written. The app's copy;
28
+ * the version is edited through POST (`apps.update`).
29
+ */
30
+ export type AppPatchBody = Partial<Pick<AppDTO, 'title' | 'description' | 'agent_description' | 'category' | 'images' | 'tags'>>;
31
+ /**
32
+ * POST /apps/{id}. The app's copy, plus an in-place edit of the version
33
+ * named by `version_id` (its metadata, required secrets and required
34
+ * credentials). Status: `apps.updateStatus`; visibility:
35
+ * `apps.updateVisibility`; name, namespace and version contents: a deploy.
36
+ */
37
+ export type AppUpdateBody = AppPatchBody & Partial<Pick<AppDTO, 'version_id' | 'version'>>;
38
+ /**
39
+ * PATCH /chats/{id}. Name and description. Visibility and the chat's
40
+ * settings: `chats.updateSettings`.
41
+ */
42
+ export type ChatUpdateBody = Partial<Pick<ChatDTO, 'name' | 'description'>>;
43
+ /** PATCH /engines/{id}. The engine's name; the rest is the engine's own report. */
44
+ export type EngineUpdateBody = Partial<Pick<EngineDTO, 'name'>>;
45
+ /** PATCH /flows/{id}: only the fields sent are written. */
46
+ export type FlowPatchBody = Partial<Pick<FlowDTO, 'name' | 'title' | 'description' | 'card_image' | 'thumbnail' | 'banner_image'>>;
47
+ /**
48
+ * POST /flows/{id}. The flow's copy and images (as PATCH), plus
49
+ * `draft_version`, naming the flow's own draft by id, which saves that
50
+ * draft's graph. Visibility: `flows.updateVisibility`; viewport:
51
+ * `flows.saveViewport`.
52
+ */
53
+ export type FlowUpdateBody = FlowPatchBody & {
54
+ draft_version?: Partial<FlowVersionDTO> & {
55
+ id: string;
56
+ };
57
+ };
58
+ /** Where the flow editor's canvas looks (POST /flows/{id}/viewport). */
59
+ export interface FlowViewportBody {
60
+ x: number;
61
+ y: number;
62
+ zoom: number;
63
+ }
64
+ /**
65
+ * POST /projects and PATCH /projects/{id}. Visibility is taken on create
66
+ * only; no route changes it afterwards. Parent: none.
67
+ */
68
+ export type ProjectWriteBody = Partial<Pick<ProjectDTO, 'name' | 'description' | 'type' | 'color' | 'icon'>> & {
69
+ visibility?: Visibility;
70
+ };
71
+ /**
72
+ * PATCH /knowledge/{id} and PATCH /skills/{id}. Copy and lifecycle. Name and
73
+ * type: fixed at creation; content: a new version (`create` with the same
74
+ * name); visibility: `updateVisibility`.
75
+ */
76
+ export interface KnowledgeUpdateBody {
77
+ title?: string;
78
+ description?: string;
79
+ repo_url?: string;
80
+ lifecycle?: KnowledgeDTO['lifecycle'];
81
+ }
82
+ /**
83
+ * PATCH /teams/{id}. A team admin changes the profile; status and
84
+ * concurrency are platform staff's. The username is the team's namespace
85
+ * and does not change here.
86
+ */
87
+ export type TeamUpdateBody = Partial<Pick<TeamDTO, 'name' | 'email' | 'avatar_url'>>;
88
+ /**
89
+ * PUT /mcp-servers/{id}. A field left out keeps its value. Title,
90
+ * description, icon URL and documentation URL take what is sent, and ""
91
+ * clears them; slug, name, server URL, auth type and the OAuth client
92
+ * change only to a non-empty value. Headers sent replace the set ({}
93
+ * clears it). Visibility: `POST /mcp-servers/{id}/visibility`.
94
+ */
95
+ export interface MCPServerUpdateBody {
96
+ slug?: string;
97
+ name?: string;
98
+ title?: string;
99
+ description?: string;
100
+ icon_url?: string;
101
+ server_url?: string;
102
+ auth_type?: MCPServerAuthType;
103
+ oauth_client_id?: string;
104
+ oauth_secret_key?: string;
105
+ default_scopes?: string[];
106
+ headers?: {
107
+ [key: string]: string;
108
+ };
109
+ documentation_url?: string;
110
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -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>) => 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
- /** Dynamic token getter (alternative to apiKey) */
20
- getToken?: () => string | null | undefined;
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
- /** Get authorization token */
75
- private getAuthToken;
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' | 'patch' | '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 getStreamableConfig() with StreamableManager instead
164
+ * @deprecated Use StreamableManager with a StreamRequest instead
104
165
  */
105
166
  createEventSource(endpoint: string): Promise<EventSource | null>;
106
167
  }