@inferencesh/sdk 0.6.50 → 0.6.52
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/README.md +18 -18
- package/dist/agent/actions.js +28 -13
- package/dist/agent/reducer.js +10 -7
- package/dist/agent/types.d.ts +4 -1
- package/dist/api/agents.d.ts +21 -1
- package/dist/api/agents.js +103 -16
- package/dist/api/integrations.d.ts +6 -6
- package/dist/http/client.js +5 -1
- package/dist/index.d.ts +7 -1
- package/dist/types.d.ts +335 -126
- package/dist/types.js +112 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -363,7 +363,7 @@ import {
|
|
|
363
363
|
mcpTool,
|
|
364
364
|
internalTools,
|
|
365
365
|
string,
|
|
366
|
-
|
|
366
|
+
CredentialProviderGoogle,
|
|
367
367
|
} from '@inferencesh/sdk';
|
|
368
368
|
|
|
369
369
|
const clientTool = tool('get_weather')
|
|
@@ -375,7 +375,7 @@ const clientTool = tool('get_weather')
|
|
|
375
375
|
const gmailSend = httpTool('gmail_send', 'https://gmail.googleapis.com/gmail/v1/users/me/messages/send')
|
|
376
376
|
.describe('Send an email via Gmail')
|
|
377
377
|
.method('POST')
|
|
378
|
-
.auth({ integration:
|
|
378
|
+
.auth({ integration: CredentialProviderGoogle, integrationId: 'your-integration-id' })
|
|
379
379
|
.build();
|
|
380
380
|
|
|
381
381
|
// API key or bearer auth
|
|
@@ -606,24 +606,24 @@ if (task.status === TaskStatusCompleted) {
|
|
|
606
606
|
|
|
607
607
|
## Integration Constants
|
|
608
608
|
|
|
609
|
-
`
|
|
609
|
+
`CredentialDTO` fields (`provider`, `type`, `auth`, `status`) use typed string unions exported as constants:
|
|
610
610
|
|
|
611
611
|
```typescript
|
|
612
|
-
import type {
|
|
612
|
+
import type { CredentialDTO } from '@inferencesh/sdk';
|
|
613
613
|
import {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
614
|
+
CredentialProviderGoogle,
|
|
615
|
+
CredentialTypeOAuth,
|
|
616
|
+
CredentialStatusConnected,
|
|
617
|
+
CredentialStatusDisconnected,
|
|
618
|
+
CredentialStatusExpired,
|
|
619
|
+
CredentialStatusError,
|
|
620
620
|
isRequirementsNotMetException,
|
|
621
621
|
} from '@inferencesh/sdk';
|
|
622
622
|
|
|
623
|
-
function isGoogleConnected(integration:
|
|
623
|
+
function isGoogleConnected(integration: CredentialDTO): boolean {
|
|
624
624
|
return (
|
|
625
|
-
integration.provider ===
|
|
626
|
-
integration.status ===
|
|
625
|
+
integration.provider === CredentialProviderGoogle &&
|
|
626
|
+
integration.status === CredentialStatusConnected
|
|
627
627
|
);
|
|
628
628
|
}
|
|
629
629
|
|
|
@@ -633,7 +633,7 @@ try {
|
|
|
633
633
|
} catch (error) {
|
|
634
634
|
if (isRequirementsNotMetException(error)) {
|
|
635
635
|
for (const req of error.errors) {
|
|
636
|
-
if (req.type === 'integration' && req.action?.provider ===
|
|
636
|
+
if (req.type === 'integration' && req.action?.provider === CredentialProviderGoogle) {
|
|
637
637
|
// User must connect Google — see https://inference.sh/docs/extend/integrations
|
|
638
638
|
}
|
|
639
639
|
}
|
|
@@ -643,9 +643,9 @@ try {
|
|
|
643
643
|
|
|
644
644
|
| Constant group | Values |
|
|
645
645
|
|----------------|--------|
|
|
646
|
-
| `
|
|
647
|
-
| `
|
|
648
|
-
| `
|
|
646
|
+
| `CredentialProvider*` | `google`, `slack`, `notion`, `github`, `x`, `microsoft`, `salesforce`, `discord`, `gcp`, `mcp`, `reddit` |
|
|
647
|
+
| `CredentialType*` | `service_account`, `oauth`, `api_key`, `wif`, `mcp` |
|
|
648
|
+
| `CredentialStatus*` | `connected`, `disconnected`, `expired`, `error` |
|
|
649
649
|
|
|
650
650
|
## Instance Status Constants
|
|
651
651
|
|
|
@@ -698,7 +698,7 @@ import type {
|
|
|
698
698
|
Task,
|
|
699
699
|
ApiAppRunRequest,
|
|
700
700
|
RunOptions,
|
|
701
|
-
|
|
701
|
+
CredentialDTO,
|
|
702
702
|
AgentTool,
|
|
703
703
|
} from '@inferencesh/sdk';
|
|
704
704
|
```
|
package/dist/agent/actions.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Action creators that handle side effects (API calls, streaming).
|
|
5
5
|
* These are created once per provider instance with access to dispatch.
|
|
6
6
|
*/
|
|
7
|
-
import { AgentRunStateWorking, AgentRunStateSubmitted, AgentRunStateInputRequired, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, ToolTypeClient, } from '../types';
|
|
7
|
+
import { AgentRunStateWorking, AgentRunStateSubmitted, AgentRunStateInputRequired, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, ToolTypeClient, ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled, } from '../types';
|
|
8
8
|
import { isChatBusy } from '../utils';
|
|
9
9
|
import { StreamableManager } from '../http/streamable';
|
|
10
10
|
import { PollManager } from '../http/poll';
|
|
@@ -139,17 +139,19 @@ export function createActions(ctx) {
|
|
|
139
139
|
checkTurnEnd(chatData);
|
|
140
140
|
}
|
|
141
141
|
});
|
|
142
|
-
// Token-by-token streaming state,
|
|
143
|
-
|
|
142
|
+
// Token-by-token streaming state, one accumulator per message being
|
|
143
|
+
// streamed. Deltas name their message (DeltaEvent.resource_id), so state
|
|
144
|
+
// never leaks between messages the way a single shared accumulator allowed.
|
|
145
|
+
const deltaAccums = new Map();
|
|
144
146
|
// Listen for ChatMessage updates
|
|
145
147
|
manager.addEventListener('chat_messages', (message, fields) => {
|
|
146
|
-
// A
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
// A message that has reached a terminal state will receive no further
|
|
149
|
+
// deltas, so its accumulator is done. This bounds the map by the number
|
|
150
|
+
// of messages streaming at once rather than by chat length.
|
|
151
|
+
if (message.status === ChatMessageStatusReady
|
|
152
|
+
|| message.status === ChatMessageStatusFailed
|
|
153
|
+
|| message.status === ChatMessageStatusCancelled) {
|
|
154
|
+
deltaAccums.delete(message.id);
|
|
153
155
|
}
|
|
154
156
|
updateMessage(message, fields);
|
|
155
157
|
});
|
|
@@ -163,10 +165,23 @@ export function createActions(ctx) {
|
|
|
163
165
|
checkTurnEnd({ ...currentChat, active_run: run });
|
|
164
166
|
});
|
|
165
167
|
manager.addEventListener('delta', (evt) => {
|
|
166
|
-
if (evt
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
if (!evt || !evt.delta)
|
|
169
|
+
return;
|
|
170
|
+
// On a chat stream every task is created with an execution edge, so a
|
|
171
|
+
// delta with no resource id means something is wrong upstream — a missing
|
|
172
|
+
// or ambiguous edge, or a failed lookup. Guessing a target there would
|
|
173
|
+
// reintroduce exactly the misattribution this field exists to end, so
|
|
174
|
+
// drop it: the text still lands when the message itself arrives.
|
|
175
|
+
const messageId = evt.resource_id;
|
|
176
|
+
if (!messageId)
|
|
177
|
+
return;
|
|
178
|
+
let accum = deltaAccums.get(messageId);
|
|
179
|
+
if (!accum) {
|
|
180
|
+
accum = createLLMDeltaAccumulator();
|
|
181
|
+
deltaAccums.set(messageId, accum);
|
|
169
182
|
}
|
|
183
|
+
accum.apply(evt.delta);
|
|
184
|
+
dispatch({ type: 'DELTA_TOKEN', payload: { messageId, output: accum.toOutput() } });
|
|
170
185
|
});
|
|
171
186
|
setStreamManager(manager);
|
|
172
187
|
manager.start();
|
package/dist/agent/reducer.js
CHANGED
|
@@ -85,16 +85,19 @@ export function chatReducer(state, action) {
|
|
|
85
85
|
messages: [...state.messages, action.payload].sort((a, b) => a.order - b.order),
|
|
86
86
|
};
|
|
87
87
|
case 'DELTA_TOKEN': {
|
|
88
|
-
const output = action.payload;
|
|
88
|
+
const { messageId, output } = action.payload;
|
|
89
89
|
const msgs = state.messages;
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
// Apply to the message the delta names — never to a guessed one. A
|
|
91
|
+
// message we have not received yet (or an unnamed delta) is dropped
|
|
92
|
+
// rather than misattributed; the text still arrives with the message.
|
|
93
|
+
const target = msgs.find(m => m.id === messageId);
|
|
94
|
+
if (!target)
|
|
92
95
|
return state;
|
|
93
|
-
const textBlock =
|
|
96
|
+
const textBlock = target.content?.find(c => c.type === 'text');
|
|
94
97
|
const newContent = textBlock
|
|
95
|
-
?
|
|
96
|
-
: [{ type: 'text', text: output.response }, ...
|
|
97
|
-
const newMessages = msgs.map(m => m.id ===
|
|
98
|
+
? target.content.map(c => c.type === 'text' ? { ...c, text: output.response } : c)
|
|
99
|
+
: [{ type: 'text', text: output.response }, ...target.content];
|
|
100
|
+
const newMessages = msgs.map(m => m.id === target.id ? { ...target, content: newContent } : m);
|
|
98
101
|
return { ...state, messages: newMessages };
|
|
99
102
|
}
|
|
100
103
|
case 'SET_CONNECTION_STATUS':
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -220,7 +220,10 @@ export type ChatAction = {
|
|
|
220
220
|
payload: ChatMessageDTO;
|
|
221
221
|
} | {
|
|
222
222
|
type: 'DELTA_TOKEN';
|
|
223
|
-
payload:
|
|
223
|
+
payload: {
|
|
224
|
+
messageId: string;
|
|
225
|
+
output: Record<string, any>;
|
|
226
|
+
};
|
|
224
227
|
} | {
|
|
225
228
|
type: 'SET_CONNECTION_STATUS';
|
|
226
229
|
payload: ChatStatus;
|
package/dist/api/agents.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HttpClient } from '../http/client';
|
|
2
2
|
import type { Response } from '../http/response';
|
|
3
3
|
import { FilesAPI } from './files';
|
|
4
|
-
import { ChatDTO, ChatMessageDTO, AgentConfigInput as AgentConfig, AgentDTO, AgentVersionDTO, CreateAgentRequest, FileDTO as File, InterruptDTO, CursorListRequest, CursorListResponse } from '../types';
|
|
4
|
+
import { ChatDTO, ChatMessageDTO, LLMDelta, LLMOutput, AgentConfigInput as AgentConfig, AgentDTO, AgentVersionDTO, CreateAgentRequest, FileDTO as File, InterruptDTO, CursorListRequest, CursorListResponse } from '../types';
|
|
5
5
|
/** Internal tool definition returned by getInternalTools */
|
|
6
6
|
export interface InternalToolDefinition {
|
|
7
7
|
id: string;
|
|
@@ -20,6 +20,20 @@ export interface AgentOptions {
|
|
|
20
20
|
/** Per-chat context variables — resolved in call tool URL templates ({{context.X}}) */
|
|
21
21
|
context?: Record<string, string>;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* One streamed token batch for a message, with everything received for that
|
|
25
|
+
* message so far. `output.response` is the assistant text as it grows.
|
|
26
|
+
*/
|
|
27
|
+
export interface AgentDelta {
|
|
28
|
+
/** The chat message the tokens belong to (normally this turn's assistant message) */
|
|
29
|
+
messageId: string;
|
|
30
|
+
/** This batch alone */
|
|
31
|
+
delta: LLMDelta;
|
|
32
|
+
/** All batches for the message merged, in the shape of the message's final output */
|
|
33
|
+
output: LLMOutput;
|
|
34
|
+
/** Producer sequence number, monotonically increasing per message */
|
|
35
|
+
seq: number;
|
|
36
|
+
}
|
|
23
37
|
export interface SendMessageOptions {
|
|
24
38
|
/** File attachments - Blob (will be uploaded) or FileDTO (already uploaded, has uri) */
|
|
25
39
|
files?: (Blob | File)[];
|
|
@@ -27,6 +41,12 @@ export interface SendMessageOptions {
|
|
|
27
41
|
onMessage?: (message: ChatMessageDTO) => void;
|
|
28
42
|
/** Callback for chat updates */
|
|
29
43
|
onChat?: (chat: ChatDTO) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Callback for token-by-token output while the assistant message is being
|
|
46
|
+
* generated. Streaming mode only: with `stream: false` there are no deltas
|
|
47
|
+
* and the message arrives whole through onMessage.
|
|
48
|
+
*/
|
|
49
|
+
onDelta?: (delta: AgentDelta) => void;
|
|
30
50
|
/** Callback when a client tool needs execution */
|
|
31
51
|
onToolCall?: (invocation: {
|
|
32
52
|
id: string;
|
package/dist/api/agents.js
CHANGED
|
@@ -1,7 +1,39 @@
|
|
|
1
1
|
import { StreamableManager } from '../http/streamable';
|
|
2
2
|
import { PollManager } from '../http/poll';
|
|
3
|
-
import {
|
|
3
|
+
import { createLLMDeltaAccumulator } from '../delta';
|
|
4
|
+
import { ChatMessageStatusCancelled, ChatMessageStatusFailed, ChatMessageStatusReady, ToolTypeClient, ToolInvocationStatusAwaitingInput, ToolInvocationStatusInProgress, } from '../types';
|
|
4
5
|
import { isChatBusy } from '../utils';
|
|
6
|
+
const terminalMessageStatuses = new Set([ChatMessageStatusReady, ChatMessageStatusFailed, ChatMessageStatusCancelled]);
|
|
7
|
+
/**
|
|
8
|
+
* Decides when one sendMessage() turn is over.
|
|
9
|
+
*
|
|
10
|
+
* For an existing chat the stream/poll is opened before the POST so nothing is
|
|
11
|
+
* missed, but its first snapshot is the previous turn's idle state. Resolving on
|
|
12
|
+
* that made sendMessage return before the new run had started. An idle snapshot
|
|
13
|
+
* only counts once the chat was seen busy, or once this turn's assistant message
|
|
14
|
+
* reached a terminal status (runs that finish between two observations).
|
|
15
|
+
*/
|
|
16
|
+
class TurnGate {
|
|
17
|
+
constructor(existingChat) {
|
|
18
|
+
this.existingChat = existingChat;
|
|
19
|
+
this.assistantMessageId = null;
|
|
20
|
+
this.sawBusy = false;
|
|
21
|
+
this.assistantDone = false;
|
|
22
|
+
}
|
|
23
|
+
observeChat(chat) {
|
|
24
|
+
if (isChatBusy(chat))
|
|
25
|
+
this.sawBusy = true;
|
|
26
|
+
}
|
|
27
|
+
observeMessage(message) {
|
|
28
|
+
if (message.id === this.assistantMessageId && terminalMessageStatuses.has(message.status)) {
|
|
29
|
+
this.assistantDone = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Whether an idle observation may end the turn. */
|
|
33
|
+
get settled() {
|
|
34
|
+
return !this.existingChat || this.sawBusy || this.assistantDone;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
5
37
|
/**
|
|
6
38
|
* Agent for chat interactions
|
|
7
39
|
*
|
|
@@ -28,7 +60,7 @@ export class Agent {
|
|
|
28
60
|
async sendMessage(text, options = {}) {
|
|
29
61
|
this.dispatchedToolCalls.clear();
|
|
30
62
|
const isTemplate = typeof this.config === 'string';
|
|
31
|
-
const hasCallbacks = !!(options.onMessage || options.onChat || options.onToolCall);
|
|
63
|
+
const hasCallbacks = !!(options.onMessage || options.onChat || options.onToolCall || options.onDelta);
|
|
32
64
|
// Process files - either already uploaded (FileDTO with uri) or needs upload (Blob)
|
|
33
65
|
let imageUris;
|
|
34
66
|
let fileUris;
|
|
@@ -68,17 +100,28 @@ export class Agent {
|
|
|
68
100
|
};
|
|
69
101
|
const useStream = options.stream ?? this.http.getStreamDefault();
|
|
70
102
|
const shouldWait = useStream === false || hasCallbacks;
|
|
103
|
+
const gate = new TurnGate(!!this.chatId);
|
|
71
104
|
const waitFn = useStream === false
|
|
72
|
-
? (opts) => this.pollUntilIdle(opts)
|
|
73
|
-
: (opts) => this.streamUntilIdle(opts);
|
|
105
|
+
? (opts) => this.pollUntilIdle(opts, gate)
|
|
106
|
+
: (opts) => this.streamUntilIdle(opts, gate);
|
|
74
107
|
// For existing chats: Start waiting BEFORE POST so we don't miss updates
|
|
75
108
|
let waitPromise = null;
|
|
76
109
|
if (this.chatId && shouldWait) {
|
|
77
110
|
waitPromise = waitFn(options);
|
|
78
111
|
}
|
|
79
112
|
// Make the POST request
|
|
80
|
-
|
|
81
|
-
|
|
113
|
+
let response;
|
|
114
|
+
try {
|
|
115
|
+
const resp = await this.http.request('post', '/agents/run', { data: body });
|
|
116
|
+
response = resp.data;
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
// Nothing to wait for; don't leave the pre-opened stream/poller running.
|
|
120
|
+
if (waitPromise)
|
|
121
|
+
this.disconnect();
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
gate.assistantMessageId = response.assistant_message?.id ?? null;
|
|
82
125
|
// For new chats: Set chatId and start waiting immediately after POST
|
|
83
126
|
const isNewChat = !this.chatId && response.assistant_message.chat_id;
|
|
84
127
|
if (isNewChat) {
|
|
@@ -145,10 +188,10 @@ export class Agent {
|
|
|
145
188
|
startStreaming(options = {}) {
|
|
146
189
|
if (!this.chatId)
|
|
147
190
|
return;
|
|
148
|
-
this.streamUntilIdle(options);
|
|
191
|
+
this.streamUntilIdle(options, new TurnGate(false));
|
|
149
192
|
}
|
|
150
193
|
/** Stream events until chat becomes idle */
|
|
151
|
-
streamUntilIdle(options) {
|
|
194
|
+
streamUntilIdle(options, gate) {
|
|
152
195
|
if (!this.chatId)
|
|
153
196
|
return Promise.resolve();
|
|
154
197
|
const { url, headers, credentials } = this.http.getStreamableConfig(`/chats/${this.chatId}/stream`);
|
|
@@ -159,21 +202,60 @@ export class Agent {
|
|
|
159
202
|
headers,
|
|
160
203
|
credentials,
|
|
161
204
|
});
|
|
205
|
+
// Last chat/run observation was idle but the gate wasn't settled yet;
|
|
206
|
+
// a terminal message for this turn can settle it.
|
|
207
|
+
let idlePending = false;
|
|
208
|
+
const onIdle = () => {
|
|
209
|
+
if (gate.settled)
|
|
210
|
+
resolve();
|
|
211
|
+
else
|
|
212
|
+
idlePending = true;
|
|
213
|
+
};
|
|
162
214
|
this.stream.addEventListener('chats', (chat) => {
|
|
163
215
|
options.onChat?.(chat);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
216
|
+
gate.observeChat(chat);
|
|
217
|
+
if (!isChatBusy(chat))
|
|
218
|
+
onIdle();
|
|
219
|
+
else
|
|
220
|
+
idlePending = false;
|
|
167
221
|
});
|
|
168
222
|
this.stream.addEventListener('agent_runs', (run) => {
|
|
169
223
|
const asChat = { active_run: run };
|
|
170
224
|
options.onChat?.(asChat);
|
|
171
|
-
|
|
172
|
-
|
|
225
|
+
gate.observeChat(asChat);
|
|
226
|
+
if (!isChatBusy(asChat))
|
|
227
|
+
onIdle();
|
|
228
|
+
else
|
|
229
|
+
idlePending = false;
|
|
230
|
+
});
|
|
231
|
+
// One accumulator per message being streamed, keyed by the message id
|
|
232
|
+
// the delta names, so a tool-call-only turn never shows the previous
|
|
233
|
+
// message's text. Same attribution rule as the React hooks.
|
|
234
|
+
const deltaAccums = new Map();
|
|
235
|
+
this.stream.addEventListener('delta', (evt) => {
|
|
236
|
+
if (!options.onDelta || !evt?.delta || !evt.resource_id)
|
|
237
|
+
return;
|
|
238
|
+
let accum = deltaAccums.get(evt.resource_id);
|
|
239
|
+
if (!accum) {
|
|
240
|
+
accum = createLLMDeltaAccumulator();
|
|
241
|
+
deltaAccums.set(evt.resource_id, accum);
|
|
173
242
|
}
|
|
243
|
+
accum.apply(evt.delta);
|
|
244
|
+
options.onDelta({
|
|
245
|
+
messageId: evt.resource_id,
|
|
246
|
+
delta: evt.delta,
|
|
247
|
+
output: accum.toOutput(),
|
|
248
|
+
seq: evt.seq,
|
|
249
|
+
});
|
|
174
250
|
});
|
|
175
251
|
this.stream.addEventListener('chat_messages', (message) => {
|
|
252
|
+
// A terminal message receives no further deltas.
|
|
253
|
+
if (terminalMessageStatuses.has(message.status))
|
|
254
|
+
deltaAccums.delete(message.id);
|
|
255
|
+
gate.observeMessage(message);
|
|
176
256
|
options.onMessage?.(message);
|
|
257
|
+
if (idlePending && gate.settled)
|
|
258
|
+
resolve();
|
|
177
259
|
if (message.tool_invocations && options.onToolCall) {
|
|
178
260
|
for (const inv of message.tool_invocations) {
|
|
179
261
|
if (this.dispatchedToolCalls.has(inv.id))
|
|
@@ -193,7 +275,7 @@ export class Agent {
|
|
|
193
275
|
});
|
|
194
276
|
}
|
|
195
277
|
/** Poll until chat becomes idle, dispatching callbacks on changes */
|
|
196
|
-
pollUntilIdle(options) {
|
|
278
|
+
pollUntilIdle(options, gate) {
|
|
197
279
|
if (!this.chatId)
|
|
198
280
|
return Promise.resolve();
|
|
199
281
|
const intervalMs = options.pollIntervalMs ?? this.http.getPollIntervalMs();
|
|
@@ -206,7 +288,9 @@ export class Agent {
|
|
|
206
288
|
// Lightweight status check first
|
|
207
289
|
const statusResp = await this.http.request('get', `/chats/${this.chatId}/status`);
|
|
208
290
|
const status = statusResp.data;
|
|
209
|
-
|
|
291
|
+
// Unchanged status is skipped — unless the turn is still ungated: a run
|
|
292
|
+
// that started and finished between two polls only shows in the messages.
|
|
293
|
+
if (status.status === prevStatus && gate.settled) {
|
|
210
294
|
// No change — return a stub to skip processing
|
|
211
295
|
return { status: status.status };
|
|
212
296
|
}
|
|
@@ -220,6 +304,9 @@ export class Agent {
|
|
|
220
304
|
return;
|
|
221
305
|
prevStatus = chat.status;
|
|
222
306
|
options.onChat?.(chat);
|
|
307
|
+
gate.observeChat(chat);
|
|
308
|
+
for (const message of chat.chat_messages ?? [])
|
|
309
|
+
gate.observeMessage(message);
|
|
223
310
|
// Dispatch new/updated messages
|
|
224
311
|
if (chat.chat_messages && options.onMessage) {
|
|
225
312
|
for (const message of chat.chat_messages) {
|
|
@@ -248,7 +335,7 @@ export class Agent {
|
|
|
248
335
|
}
|
|
249
336
|
}
|
|
250
337
|
}
|
|
251
|
-
if (!isChatBusy(chat)) {
|
|
338
|
+
if (!isChatBusy(chat) && gate.settled) {
|
|
252
339
|
this.poller?.stop();
|
|
253
340
|
this.poller = null;
|
|
254
341
|
resolve();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HttpClient } from '../http/client';
|
|
2
2
|
import type { Response } from '../http/response';
|
|
3
|
-
import {
|
|
3
|
+
import { CredentialDTO, CredentialConfigDTO, CredentialConnectRequest, CredentialConnectResponse, CursorListRequest, CursorListResponse } from '../types';
|
|
4
4
|
/**
|
|
5
5
|
* Integrations API
|
|
6
6
|
*/
|
|
@@ -10,15 +10,15 @@ export declare class IntegrationsAPI {
|
|
|
10
10
|
/**
|
|
11
11
|
* List integrations with cursor-based pagination
|
|
12
12
|
*/
|
|
13
|
-
list(params?: Partial<CursorListRequest>): Promise<Response<CursorListResponse<
|
|
13
|
+
list(params?: Partial<CursorListRequest>): Promise<Response<CursorListResponse<CredentialDTO>>>;
|
|
14
14
|
/**
|
|
15
15
|
* Get available integrations
|
|
16
16
|
*/
|
|
17
|
-
listAvailable(): Promise<Response<
|
|
17
|
+
listAvailable(): Promise<Response<CredentialConfigDTO[]>>;
|
|
18
18
|
/**
|
|
19
19
|
* Get integration configs
|
|
20
20
|
*/
|
|
21
|
-
getConfigs(): Promise<Response<
|
|
21
|
+
getConfigs(): Promise<Response<CredentialConfigDTO[]>>;
|
|
22
22
|
/**
|
|
23
23
|
* Get capabilities
|
|
24
24
|
*/
|
|
@@ -30,11 +30,11 @@ export declare class IntegrationsAPI {
|
|
|
30
30
|
/**
|
|
31
31
|
* Connect an integration
|
|
32
32
|
*/
|
|
33
|
-
connect(data:
|
|
33
|
+
connect(data: CredentialConnectRequest): Promise<Response<CredentialConnectResponse>>;
|
|
34
34
|
/**
|
|
35
35
|
* Get an integration by provider key
|
|
36
36
|
*/
|
|
37
|
-
get(provider: string): Promise<Response<
|
|
37
|
+
get(provider: string): Promise<Response<CredentialDTO>>;
|
|
38
38
|
/**
|
|
39
39
|
* Disconnect an integration
|
|
40
40
|
*/
|
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
|
@@ -7,7 +7,7 @@ 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 } from './api/tasks';
|
|
9
9
|
export { FilesAPI, type UploadFileOptions } from './api/files';
|
|
10
|
-
export { AgentsAPI, Agent, type AgentOptions, type SendMessageOptions, type AgentRunOptions } from './api/agents';
|
|
10
|
+
export { AgentsAPI, Agent, type AgentOptions, type SendMessageOptions, type AgentRunOptions, type AgentDelta } from './api/agents';
|
|
11
11
|
export { SessionsAPI } from './api/sessions';
|
|
12
12
|
export { AppsAPI } from './api/apps';
|
|
13
13
|
export { ChatsAPI } from './api/chats';
|
|
@@ -32,6 +32,7 @@ export { parseStatus, isTerminalStatus, isChatBusy, pendingApprovals } from './u
|
|
|
32
32
|
export type { PendingApproval } from './utils';
|
|
33
33
|
export * from './types';
|
|
34
34
|
export type { TaskDTO as Task } from './types';
|
|
35
|
+
export type { CredentialDTO as IntegrationDTO, CredentialConfigDTO as IntegrationConfigDTO, CredentialConnectRequest as IntegrationConnectRequest, CredentialConnectResponse as IntegrationConnectResponse, CredentialCompleteOAuthRequest as IntegrationCompleteOAuthRequest, CredentialRequirement as IntegrationRequirement, CredentialStatus as IntegrationStatus, CredentialScope as IntegrationScope, CredentialGrant as IntegrationGrant, CredentialType as IntegrationAuthType, CredentialProvider as IntegrationProvider, } from './types';
|
|
35
36
|
import { HttpClient, type HttpClientConfig } from './http/client';
|
|
36
37
|
import { TasksAPI, RunOptions } from './api/tasks';
|
|
37
38
|
import { FilesAPI, UploadFileOptions } from './api/files';
|
|
@@ -71,6 +72,11 @@ export interface InferenceConfig {
|
|
|
71
72
|
* Polling interval in milliseconds when stream is false (default: 2000).
|
|
72
73
|
*/
|
|
73
74
|
pollIntervalMs?: number;
|
|
75
|
+
/**
|
|
76
|
+
* fetch() credentials mode. Defaults to 'omit' with an apiKey and 'include'
|
|
77
|
+
* for proxyUrl / getToken flows that rely on cookies.
|
|
78
|
+
*/
|
|
79
|
+
credentials?: RequestCredentials;
|
|
74
80
|
}
|
|
75
81
|
/**
|
|
76
82
|
* Inference.sh SDK Client
|