@blazingagents/sdk 0.22.0 → 0.24.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/dist/chat-transport.d.ts +6 -0
- package/dist/chat-transport.js +15 -8
- package/dist/contracts/entities/spending-limits.d.ts +0 -2
- package/dist/contracts/entities/spending-limits.js +0 -2
- package/dist/direct-chat-transport.d.ts +6 -0
- package/dist/direct-chat-transport.js +19 -2
- package/dist/generation.js +20 -4
- package/dist/types.d.ts +6 -0
- package/package.json +1 -1
package/dist/chat-transport.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ export type BlazingAgentsChatTransportOptions<UI_MESSAGE extends UIMessage = UIM
|
|
|
5
5
|
* @param sessionId - Session to look up or record.
|
|
6
6
|
*/
|
|
7
7
|
onSessionId?: (sessionId: string) => Promise<void> | void;
|
|
8
|
+
/**
|
|
9
|
+
* Receives the running Turn ID from each response that names one, before
|
|
10
|
+
* its stream is consumed. Pass it to Stop.
|
|
11
|
+
* @param turnId - Turn the response runs.
|
|
12
|
+
*/
|
|
13
|
+
onTurnId?: (turnId: string) => Promise<void> | void;
|
|
8
14
|
/** An authorized Session ID used to resume after a remount or reload. */
|
|
9
15
|
sessionId?: string;
|
|
10
16
|
};
|
package/dist/chat-transport.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { lastAssistantMessageIsCompleteWithApprovalResponses, } from "ai";
|
|
2
2
|
import { ChatStreamTransport } from "./chat-stream-transport.js";
|
|
3
|
-
import { sessionIdSchema } from "./contracts/ids.js";
|
|
3
|
+
import { sessionIdSchema, turnIdSchema } from "./contracts/ids.js";
|
|
4
4
|
/**
|
|
5
5
|
* Adapts AI SDK chat requests to the Blazing Agents backend-relay shape and
|
|
6
6
|
* resumes with the server-minted Session ID returned in `Location`.
|
|
@@ -13,27 +13,34 @@ export class BlazingAgentsChatTransport {
|
|
|
13
13
|
* @param options - Configuration for this operation.
|
|
14
14
|
*/
|
|
15
15
|
constructor(options = {}) {
|
|
16
|
-
const { onSessionId, sessionId, ...transportOptions } = options;
|
|
16
|
+
const { onSessionId, onTurnId, sessionId, ...transportOptions } = options;
|
|
17
17
|
const transportFetch = transportOptions.fetch ?? globalThis.fetch;
|
|
18
18
|
this.#sessionId =
|
|
19
19
|
sessionId === undefined ? undefined : sessionIdSchema.parse(sessionId);
|
|
20
20
|
this.#transport = new ChatStreamTransport({
|
|
21
21
|
...transportOptions,
|
|
22
|
-
/** Reads the first Session ID
|
|
22
|
+
/** Reads the first Session ID and each Turn ID before returning the response. */
|
|
23
23
|
fetch: async (input, init) => {
|
|
24
24
|
const response = await transportFetch(input, init);
|
|
25
|
-
if (response.ok
|
|
26
|
-
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
return response;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
if (this.#sessionId === undefined) {
|
|
27
30
|
const location = response.headers.get("location");
|
|
28
31
|
const candidate = location?.split("/").pop();
|
|
29
32
|
this.#sessionId = sessionIdSchema.parse(candidate);
|
|
30
33
|
await onSessionId?.(this.#sessionId);
|
|
31
34
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const turnId = turnIdSchema.safeParse(response.headers.get("x-ba-turn-id"));
|
|
36
|
+
if (turnId.success) {
|
|
37
|
+
await onTurnId?.(turnId.data);
|
|
35
38
|
}
|
|
36
39
|
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
await response.body?.cancel(error).catch(() => undefined);
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
37
44
|
return response;
|
|
38
45
|
},
|
|
39
46
|
/** Selects the user message or complete approval round for the relay request. */
|
|
@@ -53,7 +53,6 @@ export declare const spendingLimitResponseSchema: z.ZodObject<{
|
|
|
53
53
|
availableUsd: z.ZodNumber;
|
|
54
54
|
}, z.core.$strict>>;
|
|
55
55
|
nextResetAt: z.ZodNullable<z.ZodISODateTime>;
|
|
56
|
-
scheduleChangeAt: z.ZodNullable<z.ZodISODateTime>;
|
|
57
56
|
}, z.core.$strict>;
|
|
58
57
|
export declare const spendingLimitStopDetailsSchema: z.ZodObject<{
|
|
59
58
|
scope: z.ZodEnum<{
|
|
@@ -76,7 +75,6 @@ export type SpendingLimit = z.infer<typeof spendingLimitSchema>;
|
|
|
76
75
|
export type SpendingLimitResponse = z.infer<typeof spendingLimitResponseSchema>;
|
|
77
76
|
export type SpendingLimitStopDetails = z.infer<typeof spendingLimitStopDetailsSchema>;
|
|
78
77
|
export type UpdateSpendingLimitBody = z.infer<typeof updateSpendingLimitBodySchema>;
|
|
79
|
-
/** A schedule edit uses the active period end as `after` for its first new boundary. */
|
|
80
78
|
export declare function nextSpendingLimitReset(schedule: Pick<SpendingLimit, "resetStartDate" | "resetInterval">, after: string | Date): string;
|
|
81
79
|
export declare const spendingLimitStopEventSchema: z.ZodObject<{
|
|
82
80
|
type: z.ZodLiteral<"data-model-spending-limit">;
|
|
@@ -34,7 +34,6 @@ export const spendingLimitResponseSchema = z
|
|
|
34
34
|
spendingLimit: spendingLimitSchema.nullable(),
|
|
35
35
|
period: spendingLimitPeriodSchema.nullable(),
|
|
36
36
|
nextResetAt: z.iso.datetime({ offset: true }).nullable(),
|
|
37
|
-
scheduleChangeAt: z.iso.datetime({ offset: true }).nullable(),
|
|
38
37
|
})
|
|
39
38
|
.strict()
|
|
40
39
|
.meta({ id: "ModelSpendingLimitStatus" });
|
|
@@ -48,7 +47,6 @@ export const spendingLimitStopDetailsSchema = z
|
|
|
48
47
|
nextResetAt: z.iso.datetime({ offset: true }).nullable(),
|
|
49
48
|
})
|
|
50
49
|
.strict();
|
|
51
|
-
/** A schedule edit uses the active period end as `after` for its first new boundary. */
|
|
52
50
|
export function nextSpendingLimitReset(schedule, after) {
|
|
53
51
|
const anchor = new Date(`${schedule.resetStartDate}T00:00:00.000Z`);
|
|
54
52
|
const instant = new Date(after).getTime();
|
|
@@ -17,6 +17,12 @@ export type BlazingAgentsDirectChatTransportOptions = {
|
|
|
17
17
|
* @param sessionId - Session to look up or record.
|
|
18
18
|
*/
|
|
19
19
|
onSessionId?: (sessionId: string) => Promise<void> | void;
|
|
20
|
+
/**
|
|
21
|
+
* Receives the running Turn ID before the response stream is consumed.
|
|
22
|
+
* Pass it to Stop.
|
|
23
|
+
* @param turnId - Turn the response runs.
|
|
24
|
+
*/
|
|
25
|
+
onTurnId?: (turnId: string) => Promise<void> | void;
|
|
20
26
|
sessionId?: string;
|
|
21
27
|
userId?: string;
|
|
22
28
|
} & ({
|
|
@@ -96,7 +96,8 @@ export class BlazingAgentsDirectChatTransport extends ChatStreamTransport {
|
|
|
96
96
|
return this.#processChatResult(result);
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
|
-
* Claims the chat stream and records the first Session ID
|
|
99
|
+
* Claims the chat stream and records the first Session ID and the Turn ID
|
|
100
|
+
* before decoding chunks.
|
|
100
101
|
*/
|
|
101
102
|
async #processChatResult(result) {
|
|
102
103
|
const stream = result.toStream();
|
|
@@ -106,6 +107,7 @@ export class BlazingAgentsDirectChatTransport extends ChatStreamTransport {
|
|
|
106
107
|
this.#sessionId = sessionId;
|
|
107
108
|
await this.#options.onSessionId?.(sessionId);
|
|
108
109
|
}
|
|
110
|
+
await this.#reportTurnId(result);
|
|
109
111
|
}
|
|
110
112
|
catch (error) {
|
|
111
113
|
await stream.cancel(error).catch(() => undefined);
|
|
@@ -141,6 +143,21 @@ export class BlazingAgentsDirectChatTransport extends ChatStreamTransport {
|
|
|
141
143
|
decisions,
|
|
142
144
|
functions: this.#options.functions ?? {},
|
|
143
145
|
});
|
|
144
|
-
|
|
146
|
+
const stream = continuation.toStream();
|
|
147
|
+
try {
|
|
148
|
+
await this.#reportTurnId(continuation);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
await stream.cancel(error).catch(() => undefined);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
return this.processResponseStream(stream);
|
|
155
|
+
}
|
|
156
|
+
/** Reports the Turn ID when the response names one. */
|
|
157
|
+
async #reportTurnId(result) {
|
|
158
|
+
const turnId = await result.turnId.catch(() => undefined);
|
|
159
|
+
if (turnId !== undefined) {
|
|
160
|
+
await this.#options.onTurnId?.(turnId);
|
|
161
|
+
}
|
|
145
162
|
}
|
|
146
163
|
}
|
package/dist/generation.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createTextStreamResponse, parsePartialJson } from "ai";
|
|
2
|
-
import { sessionIdSchema } from "./contracts/ids.js";
|
|
2
|
+
import { sessionIdSchema, turnIdSchema } from "./contracts/ids.js";
|
|
3
3
|
import { BlazingAgentsError } from "./errors.js";
|
|
4
4
|
import { dispatchChatFunctions, toChatFunctionDefinitions, } from "./functions.js";
|
|
5
5
|
import { requestStream } from "./http.js";
|
|
@@ -165,12 +165,24 @@ function buildChatResult(config, response, resumeSessionId, dispatch) {
|
|
|
165
165
|
sessionIdPromise.catch(() => {
|
|
166
166
|
/* no-op — prevents unhandled rejection if the caller never awaits */
|
|
167
167
|
});
|
|
168
|
+
const turnId = turnIdSchema.safeParse(response.headers.get("x-ba-turn-id"));
|
|
169
|
+
const turnIdPromise = turnId.success
|
|
170
|
+
? Promise.resolve(turnId.data)
|
|
171
|
+
: Promise.reject(new BlazingAgentsError({
|
|
172
|
+
code: "stream_error",
|
|
173
|
+
message: "The server did not return a valid turn id (X-BA-Turn-Id header).",
|
|
174
|
+
requestId: response.headers.get("x-request-id") ?? undefined,
|
|
175
|
+
}, { cause: turnId.error }));
|
|
176
|
+
turnIdPromise.catch(() => {
|
|
177
|
+
/* no-op — prevents unhandled rejection if the caller never awaits */
|
|
178
|
+
});
|
|
168
179
|
const { functions } = dispatch;
|
|
169
180
|
const streamResponse = functions && sessionId !== undefined
|
|
170
181
|
? withFilteredBody(response, (body) => dispatchChatFunctions(config, { ...dispatch, functions, sessionId }, body))
|
|
171
182
|
: response;
|
|
172
183
|
return {
|
|
173
184
|
sessionId: sessionIdPromise,
|
|
185
|
+
turnId: turnIdPromise,
|
|
174
186
|
...buildTerminalStreamResult(streamResponse, "chat"),
|
|
175
187
|
};
|
|
176
188
|
}
|
|
@@ -183,6 +195,7 @@ function buildChatResult(config, response, resumeSessionId, dispatch) {
|
|
|
183
195
|
export function buildTerminalStreamResult(response, resourceName, filter) {
|
|
184
196
|
const requestId = response.headers.get("x-request-id") ?? undefined;
|
|
185
197
|
const location = response.headers.get("location");
|
|
198
|
+
const turnId = response.headers.get("x-ba-turn-id");
|
|
186
199
|
let bodyClaimed = false;
|
|
187
200
|
/**
|
|
188
201
|
* Claims the response body once and normalizes stream failures.
|
|
@@ -207,7 +220,7 @@ export function buildTerminalStreamResult(response, resourceName, filter) {
|
|
|
207
220
|
toStream: claimBody,
|
|
208
221
|
/** Claims the response relay once. */
|
|
209
222
|
toResponse: () => {
|
|
210
|
-
const headers = replacementResponseHeaders(requestId, location);
|
|
223
|
+
const headers = replacementResponseHeaders(requestId, location, turnId);
|
|
211
224
|
headers.set("content-type", "text/event-stream");
|
|
212
225
|
headers.set("cache-control", "no-cache");
|
|
213
226
|
headers.set("connection", "keep-alive");
|
|
@@ -318,7 +331,7 @@ function responseBodyStream(response, requestId, resourceName) {
|
|
|
318
331
|
/**
|
|
319
332
|
* Copies request correlation and Session location into relay response headers.
|
|
320
333
|
*/
|
|
321
|
-
function replacementResponseHeaders(requestId, location) {
|
|
334
|
+
function replacementResponseHeaders(requestId, location, turnId) {
|
|
322
335
|
const headers = new Headers();
|
|
323
336
|
if (requestId !== undefined) {
|
|
324
337
|
headers.set("x-request-id", requestId);
|
|
@@ -326,6 +339,9 @@ function replacementResponseHeaders(requestId, location) {
|
|
|
326
339
|
if (location !== null) {
|
|
327
340
|
headers.set("location", location);
|
|
328
341
|
}
|
|
342
|
+
if (turnId !== null) {
|
|
343
|
+
headers.set("x-ba-turn-id", turnId);
|
|
344
|
+
}
|
|
329
345
|
return headers;
|
|
330
346
|
}
|
|
331
347
|
/**
|
|
@@ -501,7 +517,7 @@ function buildStatelessGenerationStreams(response, resourceName) {
|
|
|
501
517
|
}, { cause: new Error(message) });
|
|
502
518
|
}
|
|
503
519
|
responseBodyClaimed = true;
|
|
504
|
-
const headers = replacementResponseHeaders(requestId, location);
|
|
520
|
+
const headers = replacementResponseHeaders(requestId, location, null);
|
|
505
521
|
headers.set("content-type", "text/plain; charset=utf-8");
|
|
506
522
|
try {
|
|
507
523
|
return createTextStreamResponse({
|
package/dist/types.d.ts
CHANGED
|
@@ -200,6 +200,12 @@ export interface ChatResult {
|
|
|
200
200
|
* @throws BlazingAgentsError - If the response body has already been claimed.
|
|
201
201
|
*/
|
|
202
202
|
toStream: () => ReadableStream<Uint8Array>;
|
|
203
|
+
/**
|
|
204
|
+
* Resolves to the id of the Turn this response runs, read from the
|
|
205
|
+
* `X-BA-Turn-Id` header. Pass it to `sessions.stop()` to stop the Turn.
|
|
206
|
+
* Rejects with `stream_error` when the header is missing or malformed.
|
|
207
|
+
*/
|
|
208
|
+
turnId: Promise<string>;
|
|
203
209
|
}
|
|
204
210
|
export interface TerminalStreamResult {
|
|
205
211
|
requestId?: string;
|