@blazingagents/sdk 0.12.0 → 0.14.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/README.md CHANGED
@@ -87,40 +87,59 @@ use `result.toStream()` on chat or terminal continuation results to read the
87
87
  original SSE bytes. It shares one-shot ownership with `toResponse()`; choose one
88
88
  accessor per result. Stream errors and cancellation retain the same behavior.
89
89
 
90
- ### Direct native chat
90
+ ### Relay browser chat
91
91
 
92
- For a direct SDK integration, use `BlazingAgentsDirectChatTransport` with AI SDK
93
- `useChat`. It sends through `client.chat()` and uses AI SDK's stream decoder
94
- without constructing a streaming `Response`. Inject your native streaming fetch
95
- implementation into `BlazingAgents` when the runtime requires one.
92
+ Tenant browser apps use `BlazingAgentsChatTransport` with their own backend.
93
+ The backend holds the Tenant API key and authorizes each Session. The transport
94
+ sends the newest user message and resumes with the server-minted Session ID.
95
+
96
+ ### Direct chat with the SDK
97
+
98
+ For the platform dashboard or another runtime with an authorized credential,
99
+ use `BlazingAgentsDirectChatTransport` with AI SDK `useChat`. It sends through
100
+ `client.chat()` and decodes the stream without constructing a streaming
101
+ `Response`. Inject a native streaming fetch implementation into `BlazingAgents`
102
+ when the runtime requires one.
96
103
 
97
104
  ```tsx
98
105
  import { useMemo } from "react";
99
106
  import { useChat } from "@ai-sdk/react";
100
- import { BlazingAgentsDirectChatTransport } from "@blazingagents/sdk";
107
+ import { BlazingAgents, BlazingAgentsDirectChatTransport } from "@blazingagents/sdk";
101
108
 
102
- function Chat({ client, agentId, initialSessionId, saveSessionId }) {
109
+ function Chat({ getCredential, agentId, initialSessionId, saveSessionId }) {
103
110
  const transport = useMemo(
104
111
  () => new BlazingAgentsDirectChatTransport({
105
- client,
112
+ getClient: async () => new BlazingAgents({ apiKey: await getCredential() }),
106
113
  agentId,
107
114
  sessionId: initialSessionId,
108
115
  onSessionId: saveSessionId,
109
116
  }),
110
- [client, agentId, initialSessionId, saveSessionId],
117
+ [getCredential, agentId, initialSessionId, saveSessionId],
111
118
  );
112
119
  const chat = useChat({ transport });
113
120
  // Render chat.messages and submit using chat.sendMessage({ text }).
114
121
  }
115
122
  ```
116
123
 
117
- Install `@ai-sdk/react` for the React hook. Keep the transport stable for one chat;
118
- remount the chat with a new transport when switching credentials, Agents, or
119
- Sessions. `onSessionId` runs once for a newly created Session before stream
120
- consumption, so it can be saved even if streaming later fails. The adapter
121
- preserves user message IDs, regeneration targets, and `useChat` cancellation.
122
- Regeneration requires an existing Session. Reconnection returns `null`; the
123
- adapter does not retry interrupted Turns or resume their streams.
124
+ Install `@ai-sdk/react` for the React hook. Keep the transport stable for one
125
+ Session; remount the chat with a new transport when switching Agents or
126
+ Sessions. `getClient` runs before each request, so it can read a current
127
+ dashboard credential. Return a `BlazingAgents` client with that credential.
128
+
129
+ On Session creation, `version` pins the Agent Version, and `userId` and
130
+ `metadata` set attribution. To invoke a stored Prompt, pass `promptId` and
131
+ optional `variables` to the transport. Its first Turn sends those fields in
132
+ place of the `useChat` user message. Later Turns send user messages and omit
133
+ the create options, including `version`.
134
+
135
+ `onSessionId` runs once for a newly created Session before stream consumption,
136
+ so it can be saved even if streaming later fails. The transport preserves user
137
+ message IDs, regeneration targets, and `useChat` cancellation. Regeneration
138
+ requires an existing Session. When `useChat` submits tool approval responses,
139
+ the transport sends each decision in order and streams the continuation. After
140
+ reload, `reconnectToStream` joins a queued or running continuation for the
141
+ supplied `sessionId`. It returns `null` when there is no active continuation.
142
+ It does not retry an interrupted ordinary Turn.
124
143
 
125
144
  ### Cancel requests
126
145
 
@@ -30,11 +30,13 @@ export declare const usageSummarySchema: z.ZodObject<{
30
30
  metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
31
31
  modelId: z.ZodString;
32
32
  outputTokens: z.ZodNumber;
33
+ reasoningTokens: z.ZodNullable<z.ZodNumber>;
33
34
  turnId: z.ZodString;
34
35
  sessionId: z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"">]>;
35
36
  stepUsages: z.ZodArray<z.ZodObject<{
36
37
  inputTokens: z.ZodNumber;
37
38
  outputTokens: z.ZodNumber;
39
+ reasoningTokens: z.ZodNullable<z.ZodNumber>;
38
40
  stepNumber: z.ZodNumber;
39
41
  }, z.core.$strip>>;
40
42
  startedAt: z.ZodISODateTime;
@@ -61,11 +63,13 @@ export declare const blazingAgentsChatMessageMetadataSchema: z.ZodObject<{
61
63
  metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
62
64
  modelId: z.ZodString;
63
65
  outputTokens: z.ZodNumber;
66
+ reasoningTokens: z.ZodNullable<z.ZodNumber>;
64
67
  turnId: z.ZodString;
65
68
  sessionId: z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"">]>;
66
69
  stepUsages: z.ZodArray<z.ZodObject<{
67
70
  inputTokens: z.ZodNumber;
68
71
  outputTokens: z.ZodNumber;
72
+ reasoningTokens: z.ZodNullable<z.ZodNumber>;
69
73
  stepNumber: z.ZodNumber;
70
74
  }, z.core.$strip>>;
71
75
  startedAt: z.ZodISODateTime;
@@ -31,12 +31,14 @@ export const usageSummarySchema = z
31
31
  metadata: z.record(z.string(), z.unknown()),
32
32
  modelId: agentModelIdSchema,
33
33
  outputTokens: z.number().int().min(0),
34
+ reasoningTokens: z.number().int().min(0).nullable(),
34
35
  turnId: turnIdSchema,
35
36
  sessionId: z.union([sessionIdSchema, z.literal("")]),
36
37
  stepUsages: z.array(z
37
38
  .object({
38
39
  inputTokens: z.number().int().min(0),
39
40
  outputTokens: z.number().int().min(0),
41
+ reasoningTokens: z.number().int().min(0).nullable(),
40
42
  stepNumber: z.number().int().min(0),
41
43
  })
42
44
  .strip()),
@@ -154,6 +154,7 @@ export declare const taskSchema: z.ZodObject<{
154
154
  deletedAt: z.ZodNullable<z.ZodISODateTime>;
155
155
  createdAt: z.ZodISODateTime;
156
156
  updatedAt: z.ZodISODateTime;
157
+ nextFireAt: z.ZodNullable<z.ZodISODateTime>;
157
158
  }, z.core.$strip>;
158
159
  export declare const taskLatestRunSchema: z.ZodObject<{
159
160
  id: z.ZodString;
@@ -200,6 +201,7 @@ export declare const taskListItemSchema: z.ZodObject<{
200
201
  deletedAt: z.ZodNullable<z.ZodISODateTime>;
201
202
  createdAt: z.ZodISODateTime;
202
203
  updatedAt: z.ZodISODateTime;
204
+ nextFireAt: z.ZodNullable<z.ZodISODateTime>;
203
205
  latestRun: z.ZodNullable<z.ZodObject<{
204
206
  id: z.ZodString;
205
207
  status: z.ZodEnum<{
@@ -247,6 +249,7 @@ export declare const tasksListResponseSchema: z.ZodObject<{
247
249
  deletedAt: z.ZodNullable<z.ZodISODateTime>;
248
250
  createdAt: z.ZodISODateTime;
249
251
  updatedAt: z.ZodISODateTime;
252
+ nextFireAt: z.ZodNullable<z.ZodISODateTime>;
250
253
  latestRun: z.ZodNullable<z.ZodObject<{
251
254
  id: z.ZodString;
252
255
  status: z.ZodEnum<{
@@ -300,6 +303,7 @@ export declare const taskResponseSchema: z.ZodObject<{
300
303
  deletedAt: z.ZodNullable<z.ZodISODateTime>;
301
304
  createdAt: z.ZodISODateTime;
302
305
  updatedAt: z.ZodISODateTime;
306
+ nextFireAt: z.ZodNullable<z.ZodISODateTime>;
303
307
  }, z.core.$strip>;
304
308
  /**
305
309
  * Task run record. `userId`/`metadata` are copied from the task at enqueue
@@ -420,6 +424,7 @@ export declare const createTaskResponseSchema: z.ZodObject<{
420
424
  deletedAt: z.ZodNullable<z.ZodISODateTime>;
421
425
  createdAt: z.ZodISODateTime;
422
426
  updatedAt: z.ZodISODateTime;
427
+ nextFireAt: z.ZodNullable<z.ZodISODateTime>;
423
428
  }, z.core.$strip>;
424
429
  runId: z.ZodNullable<z.ZodString>;
425
430
  }, z.core.$strip>;
@@ -187,6 +187,7 @@ export const taskSchema = z
187
187
  deletedAt: z.iso.datetime({ offset: true }).nullable(),
188
188
  createdAt: z.iso.datetime({ offset: true }),
189
189
  updatedAt: z.iso.datetime({ offset: true }),
190
+ nextFireAt: z.iso.datetime({ offset: true }).nullable(),
190
191
  })
191
192
  .strip();
192
193
  // Compact run embed for list items — kills N+1 status polling.
@@ -11,7 +11,7 @@ export { chatConfigurationSchema, chatConnectionSchema, chatConnectionsResponseS
11
11
  export { approveMcpOauthAuthorizationBodySchema, createMcpConnectionBodySchema, mcpAttachmentResponseSchema, mcpAttachmentsResponseSchema, mcpConnectionAuthTypeSchema, mcpConnectionOauthConnectResponseSchema, mcpConnectionReconnectResultSchema, mcpConnectionResponseSchema, mcpConnectionStatusSchema, mcpConnectionsResponseSchema, mcpConnectionTestErrorCodeSchema, mcpConnectionTestResponseSchema, mcpOauthAuthorizationLaunchResponseSchema, reconnectMcpConnectionBodySchema, updateMcpAttachmentBodySchema, updateMcpConnectionBodySchema, } from "./entities/mcp-connections.ts";
12
12
  export { createMemoryBodySchema, memoriesListResponseSchema, memoryResponseSchema, memorySchema, updateMemoryBodySchema, } from "./entities/memories.ts";
13
13
  export { createMerchantConnectionBodySchema, merchantBindingResponseSchema, merchantBindingsResponseSchema, merchantConnectionResponseSchema, merchantConnectionSchema, merchantConnectionStatusSchema, merchantCustomerBindingSchema, merchantEnvironmentSchema, merchantGuardSchema, merchantProviderSchema, merchantUsageEventNextAction, merchantUsageEventNextActionSchema, merchantUsageEventSchema, merchantUsageEventStatusSchema, merchantUsageEventsResponseSchema, merchantUsageSummaryQuerySchema, merchantUsageSummaryResponseSchema, merchantUsageSummarySchema, merchantWorkflowIssueSchema, updateMerchantConnectionBodySchema, upsertMerchantBindingBodySchema, } from "./entities/merchant.ts";
14
- export { createPromptBodySchema, promptResponseSchema, promptSchema, promptsResponseSchema, updatePromptBodySchema, } from "./entities/prompts.ts";
14
+ export { createPromptBodySchema, parsePromptVariables, promptResponseSchema, promptSchema, promptsResponseSchema, promptTemplateSchema, renderPromptTemplate, updatePromptBodySchema, } from "./entities/prompts.ts";
15
15
  export { createProviderBodySchema, providerListItemSchema, providerModelsResponseSchema, providerResponseSchema, providersResponseSchema, providerTypeSchema, thinkingLevelsResponseSchema, updateProviderBodySchema, } from "./entities/providers.ts";
16
16
  export type { ToolApprovalDecisionResponse, ToolApprovalsResponse, } from "./entities/sessions.ts";
17
17
  export { decideToolApprovalBodySchema, latestSessionListItemSchema, latestSessionsListResponseSchema, sessionListItemSchema, sessionMessageSchema, sessionMessagesResponseSchema, sessionsListResponseSchema, toolApprovalContinuationStateSchema, toolApprovalDecisionResponseSchema, toolApprovalStateSchema, toolApprovalsResponseSchema, } from "./entities/sessions.ts";
@@ -10,7 +10,7 @@ export { chatConfigurationSchema, chatConnectionSchema, chatConnectionsResponseS
10
10
  export { approveMcpOauthAuthorizationBodySchema, createMcpConnectionBodySchema, mcpAttachmentResponseSchema, mcpAttachmentsResponseSchema, mcpConnectionAuthTypeSchema, mcpConnectionOauthConnectResponseSchema, mcpConnectionReconnectResultSchema, mcpConnectionResponseSchema, mcpConnectionStatusSchema, mcpConnectionsResponseSchema, mcpConnectionTestErrorCodeSchema, mcpConnectionTestResponseSchema, mcpOauthAuthorizationLaunchResponseSchema, reconnectMcpConnectionBodySchema, updateMcpAttachmentBodySchema, updateMcpConnectionBodySchema, } from "./entities/mcp-connections.js";
11
11
  export { createMemoryBodySchema, memoriesListResponseSchema, memoryResponseSchema, memorySchema, updateMemoryBodySchema, } from "./entities/memories.js";
12
12
  export { createMerchantConnectionBodySchema, merchantBindingResponseSchema, merchantBindingsResponseSchema, merchantConnectionResponseSchema, merchantConnectionSchema, merchantConnectionStatusSchema, merchantCustomerBindingSchema, merchantEnvironmentSchema, merchantGuardSchema, merchantProviderSchema, merchantUsageEventNextAction, merchantUsageEventNextActionSchema, merchantUsageEventSchema, merchantUsageEventStatusSchema, merchantUsageEventsResponseSchema, merchantUsageSummaryQuerySchema, merchantUsageSummaryResponseSchema, merchantUsageSummarySchema, merchantWorkflowIssueSchema, updateMerchantConnectionBodySchema, upsertMerchantBindingBodySchema, } from "./entities/merchant.js";
13
- export { createPromptBodySchema, promptResponseSchema, promptSchema, promptsResponseSchema, updatePromptBodySchema, } from "./entities/prompts.js";
13
+ export { createPromptBodySchema, parsePromptVariables, promptResponseSchema, promptSchema, promptsResponseSchema, promptTemplateSchema, renderPromptTemplate, updatePromptBodySchema, } from "./entities/prompts.js";
14
14
  export { createProviderBodySchema, providerListItemSchema, providerModelsResponseSchema, providerResponseSchema, providersResponseSchema, providerTypeSchema, thinkingLevelsResponseSchema, updateProviderBodySchema, } from "./entities/providers.js";
15
15
  export { decideToolApprovalBodySchema, latestSessionListItemSchema, latestSessionsListResponseSchema, sessionListItemSchema, sessionMessageSchema, sessionMessagesResponseSchema, sessionsListResponseSchema, toolApprovalContinuationStateSchema, toolApprovalDecisionResponseSchema, toolApprovalStateSchema, toolApprovalsResponseSchema, } from "./entities/sessions.js";
16
16
  export { copySkillBodySchema, createSkillBodySchema, skillCopyResultsSchema, skillDetailSchema, skillsListResponseSchema, } from "./entities/skills.js";
@@ -1,16 +1,25 @@
1
1
  import { type ChatTransport, DefaultChatTransport, type UIMessage } from "ai";
2
2
  import type { BlazingAgents } from "./client.ts";
3
- export interface BlazingAgentsDirectChatTransportOptions {
3
+ export type BlazingAgentsDirectChatTransportOptions = {
4
4
  agentId: string;
5
- client: BlazingAgents;
5
+ getClient: () => BlazingAgents | Promise<BlazingAgents>;
6
+ metadata?: Record<string, unknown>;
6
7
  /** Receives the Session ID before the response stream is consumed. */
7
8
  onSessionId?: (sessionId: string) => Promise<void> | void;
8
9
  sessionId?: string;
9
- }
10
+ userId?: string;
11
+ version?: number;
12
+ } & ({
13
+ promptId: string;
14
+ variables?: Record<string, string>;
15
+ } | {
16
+ promptId?: never;
17
+ variables?: never;
18
+ });
10
19
  /** Connects useChat directly to the SDK, including native streaming fetch clients. */
11
20
  export declare class BlazingAgentsDirectChatTransport<UI_MESSAGE extends UIMessage = UIMessage> extends DefaultChatTransport<UI_MESSAGE> {
12
21
  #private;
13
22
  constructor(options: BlazingAgentsDirectChatTransportOptions);
14
23
  sendMessages(input: Parameters<ChatTransport<UI_MESSAGE>["sendMessages"]>[0]): Promise<ReadableStream<import("ai").UIMessageChunk<unknown, import("ai").UIDataTypes>>>;
15
- reconnectToStream(_input: Parameters<ChatTransport<UI_MESSAGE>["reconnectToStream"]>[0]): Promise<null>;
24
+ reconnectToStream(_input: Parameters<ChatTransport<UI_MESSAGE>["reconnectToStream"]>[0]): Promise<ReadableStream<import("ai").UIMessageChunk<unknown, import("ai").UIDataTypes>> | null>;
16
25
  }
@@ -1,4 +1,4 @@
1
- import { DefaultChatTransport } from "ai";
1
+ import { DefaultChatTransport, isToolUIPart, lastAssistantMessageIsCompleteWithApprovalResponses, } from "ai";
2
2
  import { sessionIdSchema } from "./contracts/ids.js";
3
3
  /** Connects useChat directly to the SDK, including native streaming fetch clients. */
4
4
  export class BlazingAgentsDirectChatTransport extends DefaultChatTransport {
@@ -16,19 +16,55 @@ export class BlazingAgentsDirectChatTransport extends DefaultChatTransport {
16
16
  if (input.trigger === "regenerate-message" && !this.#sessionId) {
17
17
  throw new Error("Regeneration requires an existing Session.");
18
18
  }
19
- const message = input.messages.findLast((item) => item.role === "user");
20
- if (!message) {
21
- throw new Error("Chat submission requires a user message.");
19
+ const last = input.messages.at(-1);
20
+ if (last?.role === "assistant" &&
21
+ lastAssistantMessageIsCompleteWithApprovalResponses({
22
+ messages: input.messages,
23
+ })) {
24
+ return await this.#sendApprovalContinuation(input, last);
22
25
  }
23
- const result = await this.#options.client.chat({
26
+ const client = await this.#options.getClient();
27
+ const common = {
24
28
  agentId: this.#options.agentId,
25
- message,
26
29
  messageId: input.messageId,
27
- ...(this.#sessionId === undefined
28
- ? { trigger: "submit-message" }
29
- : { sessionId: this.#sessionId, trigger: input.trigger }),
30
30
  abortSignal: input.abortSignal,
31
- });
31
+ };
32
+ let result;
33
+ if (this.#sessionId === undefined) {
34
+ const create = {
35
+ ...common,
36
+ trigger: "submit-message",
37
+ version: this.#options.version,
38
+ userId: this.#options.userId,
39
+ metadata: this.#options.metadata,
40
+ };
41
+ if (this.#options.promptId === undefined) {
42
+ const message = input.messages.findLast((item) => item.role === "user");
43
+ if (!message) {
44
+ throw new Error("Chat submission requires a user message.");
45
+ }
46
+ result = await client.chat({ ...create, message });
47
+ }
48
+ else {
49
+ result = await client.chat({
50
+ ...create,
51
+ promptId: this.#options.promptId,
52
+ variables: this.#options.variables,
53
+ });
54
+ }
55
+ }
56
+ else {
57
+ const message = input.messages.findLast((item) => item.role === "user");
58
+ if (!message) {
59
+ throw new Error("Chat submission requires a user message.");
60
+ }
61
+ result = await client.chat({
62
+ ...common,
63
+ message,
64
+ sessionId: this.#sessionId,
65
+ trigger: input.trigger,
66
+ });
67
+ }
32
68
  const stream = result.toStream();
33
69
  try {
34
70
  const sessionId = await result.sessionId;
@@ -43,7 +79,52 @@ export class BlazingAgentsDirectChatTransport extends DefaultChatTransport {
43
79
  }
44
80
  return this.processResponseStream(stream);
45
81
  }
46
- reconnectToStream(_input) {
47
- return Promise.resolve(null);
82
+ async reconnectToStream(_input) {
83
+ if (this.#sessionId === undefined) {
84
+ return null;
85
+ }
86
+ const { continuation } = await (await this.#options.getClient()).sessions.toolApprovals({
87
+ agentId: this.#options.agentId,
88
+ sessionId: this.#sessionId,
89
+ });
90
+ if (continuation?.state !== "queued" && continuation?.state !== "running") {
91
+ return null;
92
+ }
93
+ const result = await (await this.#options.getClient()).sessions.joinToolApprovalContinuation({
94
+ agentId: this.#options.agentId,
95
+ sessionId: this.#sessionId,
96
+ continuationId: continuation.id,
97
+ });
98
+ return this.processResponseStream(result.toStream());
99
+ }
100
+ async #sendApprovalContinuation(input, last) {
101
+ if (this.#sessionId === undefined) {
102
+ throw new Error("Tool approval requires an existing Session.");
103
+ }
104
+ const lastStep = last.parts.findLastIndex((part) => part.type === "step-start");
105
+ let continuationId;
106
+ for (const part of last.parts.slice(lastStep + 1)) {
107
+ if (isToolUIPart(part) && part.state === "approval-responded") {
108
+ const decision = await (await this.#options.getClient()).sessions.decideToolApproval({
109
+ agentId: this.#options.agentId,
110
+ sessionId: this.#sessionId,
111
+ approvalId: part.approval.id,
112
+ approved: part.approval.approved,
113
+ reason: part.approval.reason,
114
+ abortSignal: input.abortSignal,
115
+ });
116
+ continuationId = decision.continuationId;
117
+ }
118
+ }
119
+ if (continuationId === undefined) {
120
+ throw new Error("Tool approval response is missing an approval.");
121
+ }
122
+ const continuation = await (await this.#options.getClient()).sessions.joinToolApprovalContinuation({
123
+ agentId: this.#options.agentId,
124
+ sessionId: this.#sessionId,
125
+ continuationId,
126
+ abortSignal: input.abortSignal,
127
+ });
128
+ return this.processResponseStream(continuation.toStream());
48
129
  }
49
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blazingagents/sdk",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "TypeScript SDK for the Blazing Agents API",
5
5
  "homepage": "https://docs.blazingagents.com",
6
6
  "bugs": {