@inferencesh/sdk 0.6.49 → 0.6.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/actions.js +10 -2
- package/dist/api/agents.js +79 -16
- package/dist/delta.d.ts +8 -0
- package/dist/delta.js +10 -0
- package/dist/http/client.js +5 -1
- package/dist/index.d.ts +5 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +5 -0
- package/package.json +1 -1
package/dist/agent/actions.js
CHANGED
|
@@ -139,8 +139,18 @@ export function createActions(ctx) {
|
|
|
139
139
|
checkTurnEnd(chatData);
|
|
140
140
|
}
|
|
141
141
|
});
|
|
142
|
+
// Token-by-token streaming state, reset at every assistant-message boundary.
|
|
143
|
+
const deltaAccum = createLLMDeltaAccumulator();
|
|
142
144
|
// Listen for ChatMessage updates
|
|
143
145
|
manager.addEventListener('chat_messages', (message, fields) => {
|
|
146
|
+
// A new assistant message starts a new accumulation. The accumulator is
|
|
147
|
+
// cumulative and shared across the whole connection, so without this the
|
|
148
|
+
// next message's deltas merge into the previous message's state — and
|
|
149
|
+
// because concat with "" is a no-op, a turn that is only tool calls
|
|
150
|
+
// would render the previous message's text as its own.
|
|
151
|
+
if (message.role === 'assistant' && !getState().messages.some(m => m.id === message.id)) {
|
|
152
|
+
deltaAccum.reset();
|
|
153
|
+
}
|
|
144
154
|
updateMessage(message, fields);
|
|
145
155
|
});
|
|
146
156
|
// Listen for AgentRun updates (state transitions, output)
|
|
@@ -152,8 +162,6 @@ export function createActions(ctx) {
|
|
|
152
162
|
if (currentChat)
|
|
153
163
|
checkTurnEnd({ ...currentChat, active_run: run });
|
|
154
164
|
});
|
|
155
|
-
// Listen for LLM delta events (token-by-token streaming)
|
|
156
|
-
const deltaAccum = createLLMDeltaAccumulator();
|
|
157
165
|
manager.addEventListener('delta', (evt) => {
|
|
158
166
|
if (evt && evt.delta) {
|
|
159
167
|
deltaAccum.apply(evt.delta);
|
package/dist/api/agents.js
CHANGED
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
import { StreamableManager } from '../http/streamable';
|
|
2
2
|
import { PollManager } from '../http/poll';
|
|
3
|
-
import { ToolTypeClient, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, } from '../types';
|
|
3
|
+
import { ChatMessageStatusCancelled, ChatMessageStatusFailed, ChatMessageStatusReady, ToolTypeClient, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, } from '../types';
|
|
4
4
|
import { isChatBusy } from '../utils';
|
|
5
|
+
const terminalMessageStatuses = new Set([ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled]);
|
|
6
|
+
/**
|
|
7
|
+
* Decides when one sendMessage() turn is over.
|
|
8
|
+
*
|
|
9
|
+
* For an existing chat the stream/poll is opened before the POST so nothing is
|
|
10
|
+
* missed, but its first snapshot is the previous turn's idle state. Resolving on
|
|
11
|
+
* that made sendMessage return before the new run had started. An idle snapshot
|
|
12
|
+
* only counts once the chat was seen busy, or once this turn's assistant message
|
|
13
|
+
* reached a terminal status (runs that finish between two observations).
|
|
14
|
+
*/
|
|
15
|
+
class TurnGate {
|
|
16
|
+
constructor(existingChat) {
|
|
17
|
+
this.existingChat = existingChat;
|
|
18
|
+
this.assistantMessageId = null;
|
|
19
|
+
this.sawBusy = false;
|
|
20
|
+
this.assistantDone = false;
|
|
21
|
+
}
|
|
22
|
+
observeChat(chat) {
|
|
23
|
+
if (isChatBusy(chat))
|
|
24
|
+
this.sawBusy = true;
|
|
25
|
+
}
|
|
26
|
+
observeMessage(message) {
|
|
27
|
+
if (message.id === this.assistantMessageId && terminalMessageStatuses.has(message.status)) {
|
|
28
|
+
this.assistantDone = true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Whether an idle observation may end the turn. */
|
|
32
|
+
get settled() {
|
|
33
|
+
return !this.existingChat || this.sawBusy || this.assistantDone;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
5
36
|
/**
|
|
6
37
|
* Agent for chat interactions
|
|
7
38
|
*
|
|
@@ -68,17 +99,28 @@ export class Agent {
|
|
|
68
99
|
};
|
|
69
100
|
const useStream = options.stream ?? this.http.getStreamDefault();
|
|
70
101
|
const shouldWait = useStream === false || hasCallbacks;
|
|
102
|
+
const gate = new TurnGate(!!this.chatId);
|
|
71
103
|
const waitFn = useStream === false
|
|
72
|
-
? (opts) => this.pollUntilIdle(opts)
|
|
73
|
-
: (opts) => this.streamUntilIdle(opts);
|
|
104
|
+
? (opts) => this.pollUntilIdle(opts, gate)
|
|
105
|
+
: (opts) => this.streamUntilIdle(opts, gate);
|
|
74
106
|
// For existing chats: Start waiting BEFORE POST so we don't miss updates
|
|
75
107
|
let waitPromise = null;
|
|
76
108
|
if (this.chatId && shouldWait) {
|
|
77
109
|
waitPromise = waitFn(options);
|
|
78
110
|
}
|
|
79
111
|
// Make the POST request
|
|
80
|
-
|
|
81
|
-
|
|
112
|
+
let response;
|
|
113
|
+
try {
|
|
114
|
+
const resp = await this.http.request('post', '/agents/run', { data: body });
|
|
115
|
+
response = resp.data;
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
// Nothing to wait for; don't leave the pre-opened stream/poller running.
|
|
119
|
+
if (waitPromise)
|
|
120
|
+
this.disconnect();
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
gate.assistantMessageId = response.assistant_message?.id ?? null;
|
|
82
124
|
// For new chats: Set chatId and start waiting immediately after POST
|
|
83
125
|
const isNewChat = !this.chatId && response.assistant_message.chat_id;
|
|
84
126
|
if (isNewChat) {
|
|
@@ -145,10 +187,10 @@ export class Agent {
|
|
|
145
187
|
startStreaming(options = {}) {
|
|
146
188
|
if (!this.chatId)
|
|
147
189
|
return;
|
|
148
|
-
this.streamUntilIdle(options);
|
|
190
|
+
this.streamUntilIdle(options, new TurnGate(false));
|
|
149
191
|
}
|
|
150
192
|
/** Stream events until chat becomes idle */
|
|
151
|
-
streamUntilIdle(options) {
|
|
193
|
+
streamUntilIdle(options, gate) {
|
|
152
194
|
if (!this.chatId)
|
|
153
195
|
return Promise.resolve();
|
|
154
196
|
const { url, headers, credentials } = this.http.getStreamableConfig(`/chats/${this.chatId}/stream`);
|
|
@@ -159,21 +201,37 @@ export class Agent {
|
|
|
159
201
|
headers,
|
|
160
202
|
credentials,
|
|
161
203
|
});
|
|
204
|
+
// Last chat/run observation was idle but the gate wasn't settled yet;
|
|
205
|
+
// a terminal message for this turn can settle it.
|
|
206
|
+
let idlePending = false;
|
|
207
|
+
const onIdle = () => {
|
|
208
|
+
if (gate.settled)
|
|
209
|
+
resolve();
|
|
210
|
+
else
|
|
211
|
+
idlePending = true;
|
|
212
|
+
};
|
|
162
213
|
this.stream.addEventListener('chats', (chat) => {
|
|
163
214
|
options.onChat?.(chat);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
215
|
+
gate.observeChat(chat);
|
|
216
|
+
if (!isChatBusy(chat))
|
|
217
|
+
onIdle();
|
|
218
|
+
else
|
|
219
|
+
idlePending = false;
|
|
167
220
|
});
|
|
168
221
|
this.stream.addEventListener('agent_runs', (run) => {
|
|
169
222
|
const asChat = { active_run: run };
|
|
170
223
|
options.onChat?.(asChat);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
224
|
+
gate.observeChat(asChat);
|
|
225
|
+
if (!isChatBusy(asChat))
|
|
226
|
+
onIdle();
|
|
227
|
+
else
|
|
228
|
+
idlePending = false;
|
|
174
229
|
});
|
|
175
230
|
this.stream.addEventListener('chat_messages', (message) => {
|
|
231
|
+
gate.observeMessage(message);
|
|
176
232
|
options.onMessage?.(message);
|
|
233
|
+
if (idlePending && gate.settled)
|
|
234
|
+
resolve();
|
|
177
235
|
if (message.tool_invocations && options.onToolCall) {
|
|
178
236
|
for (const inv of message.tool_invocations) {
|
|
179
237
|
if (this.dispatchedToolCalls.has(inv.id))
|
|
@@ -193,7 +251,7 @@ export class Agent {
|
|
|
193
251
|
});
|
|
194
252
|
}
|
|
195
253
|
/** Poll until chat becomes idle, dispatching callbacks on changes */
|
|
196
|
-
pollUntilIdle(options) {
|
|
254
|
+
pollUntilIdle(options, gate) {
|
|
197
255
|
if (!this.chatId)
|
|
198
256
|
return Promise.resolve();
|
|
199
257
|
const intervalMs = options.pollIntervalMs ?? this.http.getPollIntervalMs();
|
|
@@ -206,7 +264,9 @@ export class Agent {
|
|
|
206
264
|
// Lightweight status check first
|
|
207
265
|
const statusResp = await this.http.request('get', `/chats/${this.chatId}/status`);
|
|
208
266
|
const status = statusResp.data;
|
|
209
|
-
|
|
267
|
+
// Unchanged status is skipped — unless the turn is still ungated: a run
|
|
268
|
+
// that started and finished between two polls only shows in the messages.
|
|
269
|
+
if (status.status === prevStatus && gate.settled) {
|
|
210
270
|
// No change — return a stub to skip processing
|
|
211
271
|
return { status: status.status };
|
|
212
272
|
}
|
|
@@ -220,6 +280,9 @@ export class Agent {
|
|
|
220
280
|
return;
|
|
221
281
|
prevStatus = chat.status;
|
|
222
282
|
options.onChat?.(chat);
|
|
283
|
+
gate.observeChat(chat);
|
|
284
|
+
for (const message of chat.chat_messages ?? [])
|
|
285
|
+
gate.observeMessage(message);
|
|
223
286
|
// Dispatch new/updated messages
|
|
224
287
|
if (chat.chat_messages && options.onMessage) {
|
|
225
288
|
for (const message of chat.chat_messages) {
|
|
@@ -248,7 +311,7 @@ export class Agent {
|
|
|
248
311
|
}
|
|
249
312
|
}
|
|
250
313
|
}
|
|
251
|
-
if (!isChatBusy(chat)) {
|
|
314
|
+
if (!isChatBusy(chat) && gate.settled) {
|
|
252
315
|
this.poller?.stop();
|
|
253
316
|
this.poller = null;
|
|
254
317
|
resolve();
|
package/dist/delta.d.ts
CHANGED
|
@@ -8,6 +8,14 @@ export declare class DeltaAccumulator {
|
|
|
8
8
|
private tags;
|
|
9
9
|
private registry;
|
|
10
10
|
constructor(tags: FieldTags, registry?: FieldTagsRegistry);
|
|
11
|
+
/**
|
|
12
|
+
* Discard everything accumulated so far. Required at a message boundary: the
|
|
13
|
+
* accumulator is cumulative, so without a reset the next message's deltas
|
|
14
|
+
* merge into the previous message's state. Concat makes that invisible for
|
|
15
|
+
* text — appending "" leaves the old text in place, so a tool-call-only turn
|
|
16
|
+
* serves the previous message's answer as its own.
|
|
17
|
+
*/
|
|
18
|
+
reset(): void;
|
|
11
19
|
seed(output: Record<string, any>): void;
|
|
12
20
|
apply(delta: Record<string, any>): void;
|
|
13
21
|
toOutput(): Record<string, any>;
|
package/dist/delta.js
CHANGED
|
@@ -57,6 +57,16 @@ export class DeltaAccumulator {
|
|
|
57
57
|
this.tags = tags;
|
|
58
58
|
this.registry = registry;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Discard everything accumulated so far. Required at a message boundary: the
|
|
62
|
+
* accumulator is cumulative, so without a reset the next message's deltas
|
|
63
|
+
* merge into the previous message's state. Concat makes that invisible for
|
|
64
|
+
* text — appending "" leaves the old text in place, so a tool-call-only turn
|
|
65
|
+
* serves the previous message's answer as its own.
|
|
66
|
+
*/
|
|
67
|
+
reset() {
|
|
68
|
+
this.state = {};
|
|
69
|
+
}
|
|
60
70
|
seed(output) {
|
|
61
71
|
for (const [key, value] of Object.entries(output)) {
|
|
62
72
|
if (value != null)
|
package/dist/http/client.js
CHANGED
|
@@ -17,7 +17,11 @@ export class HttpClient {
|
|
|
17
17
|
this.proxyUrl = config.proxyUrl;
|
|
18
18
|
this.getToken = config.getToken;
|
|
19
19
|
this.customHeaders = { 'X-Client-Source': 'inference-sdk-js/0.5.13', ...config.headers };
|
|
20
|
-
|
|
20
|
+
// Bearer auth needs no cookies, and 'include' makes browsers reject the
|
|
21
|
+
// response unless the API answers with Allow-Credentials — which it does not
|
|
22
|
+
// for third-party origins (WebKit reports that as "Load failed"). Cookies
|
|
23
|
+
// matter only for the proxy / getToken flows, which keep 'include'.
|
|
24
|
+
this.credentials = config.credentials || (config.apiKey ? 'omit' : 'include');
|
|
21
25
|
this.onError = config.onError;
|
|
22
26
|
this.onMessage = config.onMessage;
|
|
23
27
|
this.streamDefault = config.stream ?? true;
|
package/dist/index.d.ts
CHANGED
|
@@ -71,6 +71,11 @@ export interface InferenceConfig {
|
|
|
71
71
|
* Polling interval in milliseconds when stream is false (default: 2000).
|
|
72
72
|
*/
|
|
73
73
|
pollIntervalMs?: number;
|
|
74
|
+
/**
|
|
75
|
+
* fetch() credentials mode. Defaults to 'omit' with an apiKey and 'include'
|
|
76
|
+
* for proxyUrl / getToken flows that rely on cookies.
|
|
77
|
+
*/
|
|
78
|
+
credentials?: RequestCredentials;
|
|
74
79
|
}
|
|
75
80
|
/**
|
|
76
81
|
* Inference.sh SDK Client
|
package/dist/types.d.ts
CHANGED
|
@@ -2709,6 +2709,11 @@ export interface MenuItem {
|
|
|
2709
2709
|
id: string;
|
|
2710
2710
|
label: string;
|
|
2711
2711
|
slug?: string;
|
|
2712
|
+
/**
|
|
2713
|
+
* Path is the linked page's path, filled in when a menu is read so a client
|
|
2714
|
+
* can build the link without fetching each page. Never stored.
|
|
2715
|
+
*/
|
|
2716
|
+
path?: string;
|
|
2712
2717
|
page_id?: string;
|
|
2713
2718
|
url?: string;
|
|
2714
2719
|
icon?: string;
|
|
@@ -2729,6 +2734,7 @@ export interface PageDTO extends BaseModelDTO, PermissionModelDTO {
|
|
|
2729
2734
|
type: PageType;
|
|
2730
2735
|
metadata: PageMetadata;
|
|
2731
2736
|
slug: string;
|
|
2737
|
+
path: string;
|
|
2732
2738
|
/**
|
|
2733
2739
|
* PublishAt mirrors Metadata.PublishAt, which remains the field clients write.
|
|
2734
2740
|
* Surfaced here so a reader does not have to reach into the metadata blob.
|
|
@@ -4381,6 +4387,11 @@ export type RefRouteType = string;
|
|
|
4381
4387
|
export declare const RefRouteTypeApp: RefRouteType;
|
|
4382
4388
|
export declare const RefRouteTypeAgent: RefRouteType;
|
|
4383
4389
|
export declare const RefRouteTypeSkill: RefRouteType;
|
|
4390
|
+
/**
|
|
4391
|
+
* RefRouteTypeURL routes a site path to another (/docs/api-files →
|
|
4392
|
+
* /docs/api/sdk/files). Alias and target are literal paths, not refs.
|
|
4393
|
+
*/
|
|
4394
|
+
export declare const RefRouteTypeURL: RefRouteType;
|
|
4384
4395
|
export type RefRouteMode = string;
|
|
4385
4396
|
export declare const RefRouteModeRewrite: RefRouteMode;
|
|
4386
4397
|
export declare const RefRouteModeRedirect: RefRouteMode;
|
package/dist/types.js
CHANGED
|
@@ -678,6 +678,11 @@ export const TeamInviteStatusRevoked = "revoked";
|
|
|
678
678
|
export const RefRouteTypeApp = "app";
|
|
679
679
|
export const RefRouteTypeAgent = "agent";
|
|
680
680
|
export const RefRouteTypeSkill = "skill";
|
|
681
|
+
/**
|
|
682
|
+
* RefRouteTypeURL routes a site path to another (/docs/api-files →
|
|
683
|
+
* /docs/api/sdk/files). Alias and target are literal paths, not refs.
|
|
684
|
+
*/
|
|
685
|
+
export const RefRouteTypeURL = "url";
|
|
681
686
|
export const RefRouteModeRewrite = "rewrite";
|
|
682
687
|
export const RefRouteModeRedirect = "redirect";
|
|
683
688
|
export const KnowledgeTypeConcept = "concept";
|