@blazingagents/sdk 0.42.1 → 0.43.1

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
@@ -10,19 +10,24 @@
10
10
  </p>
11
11
  </div>
12
12
 
13
- The official resource-style client SDK for the Blazing Agents `/v1` API. It
14
- requires Node.js 24 or newer.
13
+ The official TypeScript SDK is a client for the Blazing Agents `/v1` API that
14
+ your backend uses to manage Agents and run them for your users. It requires
15
+ Node.js 24 or newer.
15
16
 
16
17
  ## Features
17
18
 
18
- - Typed clients for Agents, Workspaces, Skills, Providers, Prompts, Tasks,
19
- Sessions, Artifacts, Slack and Telegram Chat Connections, usage, Tenant settings, and merchant monetization.
20
- - Stateful chat with explicit message batches, steer receipts, and one-call Tool approvals.
21
- - Stateless text or structured-object generation.
22
- - Public Zod contracts for validating API requests and responses.
23
- - Cursor pagination and binary transfers.
24
- - Request correlation and a typed, forward-compatible error model.
25
- - End-user scoped clients for user-owned resources and generation.
19
+ - A typed method for every `/v1` operation an API key can call: Agents,
20
+ Skills, Sessions, Memories, Prompts, Tasks, Workspaces, Artifacts,
21
+ Providers, MCP Connections, Chat Connections, usage, spending limits, Tenant
22
+ settings, and merchant monetization.
23
+ - Chat streams in the AI SDK UI message stream format, with steering, Tool
24
+ approvals, and backend functions that run in your process.
25
+ - Text and structured-object generation.
26
+ - End-user scoped clients through `forUser`.
27
+ - Cursor pagination, uploads, and downloads.
28
+ - Request IDs and typed errors.
29
+ - `BlazingAgentsChatTransport` and `createChatRelay` connect AI SDK `useChat`
30
+ to your backend.
26
31
 
27
32
  ## Installation
28
33
 
@@ -30,19 +35,21 @@ requires Node.js 24 or newer.
30
35
  npm install @blazingagents/sdk ai@^7.0.84 zod@^4.5.4
31
36
  ```
32
37
 
33
- `ai` (`^7.0.84`) and `zod` (`^4.5.4`) are peer dependencies. The SDK
34
- re-exports AI SDK message types and Zod schemas, so consumers share these
35
- dependencies with the SDK.
38
+ `ai` and `zod` are required peer dependencies. The SDK re-exports AI SDK
39
+ message types and Zod schemas, so your app and the SDK share one copy of each.
36
40
 
37
41
  ## Quick start
38
42
 
39
- Create a Tenant API key in the Blazing Agents dashboard, then pass it to the
40
- client or read it from your server environment.
43
+ Create a Full API key in the Blazing Agents dashboard and set
44
+ `BLAZING_AGENTS_API_KEY` in your server environment. The key acts for your
45
+ whole Tenant, so keep it on your backend and never send it to a browser.
41
46
 
42
47
  ```ts
43
48
  import { BlazingAgents } from "@blazingagents/sdk";
44
49
 
45
- const client = new BlazingAgents({ apiKey: "ba_..." });
50
+ const client = new BlazingAgents({
51
+ apiKey: process.env.BLAZING_AGENTS_API_KEY!,
52
+ });
46
53
 
47
54
  const result = await client.completion({
48
55
  agentId: "ag_...",
@@ -52,31 +59,59 @@ const result = await client.completion({
52
59
  console.log(await result.text);
53
60
  ```
54
61
 
55
- For stateful chat, pass one user message or an ordered batch.
62
+ Replace `ag_...` with an Agent ID from the dashboard.
56
63
 
57
- ```ts
58
- const chat = await client.chat({
59
- agentId: "ag_...",
60
- messages: [
61
- { id: "first", role: "user", parts: [{ type: "text", text: "Compare the plans." }] },
62
- { id: "second", role: "user", parts: [{ type: "text", text: "Include annual pricing." }] },
63
- ],
64
- });
64
+ For requests from your users, scope the client to the user ID that your
65
+ backend verified at sign-in, never to an ID from the request body. A scoped
66
+ client reaches only that End-user's Agents, Sessions, and Workspace. An
67
+ unscoped Agent shares one Workspace across all your users, so give each user
68
+ an Agent of their own:
65
69
 
66
- const sessionId = await chat.sessionId;
67
- return chat.toResponse();
70
+ ```ts
71
+ export async function createAgentForUser(userId: string): Promise<string> {
72
+ const agent = await client.forUser(userId).agents.create({
73
+ name: "Assistant",
74
+ providerId: "prv_...",
75
+ model: "openai/gpt-6-luna",
76
+ });
77
+ return agent.id;
78
+ }
79
+
80
+ export async function chatAsUser(
81
+ userId: string,
82
+ agentId: string,
83
+ text: string
84
+ ): Promise<Response> {
85
+ const chat = await client.forUser(userId).chat({
86
+ agentId,
87
+ message: {
88
+ id: crypto.randomUUID(),
89
+ role: "user",
90
+ parts: [{ type: "text", text }],
91
+ },
92
+ });
93
+ return chat.toResponse();
94
+ }
68
95
  ```
69
96
 
70
- Keep API keys on the server. For browser chat applications, relay `chat()`
71
- through your backend and use `BlazingAgentsChatTransport` with AI SDK
72
- `useChat`.
97
+ Call `createAgentForUser` once per user and store the Agent ID with the user.
98
+ A scoped chat with an Agent created without the scope fails with `404`.
99
+ `chatAsUser` returns the chat as a streaming `Response`. To chat from the
100
+ browser with `useChat`, serve `createChatRelay` from your backend and use
101
+ `BlazingAgentsChatTransport`. The relay scopes each request to the user that
102
+ your `resolveContext` returns.
103
+
104
+ ## Examples
105
+
106
+ The [examples repository](https://github.com/blazingagents/examples) has
107
+ complete TypeScript and Python apps built on the Blazing Agents SDKs.
73
108
 
74
109
  ## Documentation
75
110
 
76
111
  Read the
77
112
  [TypeScript SDK documentation](https://docs.blazingagents.com/sdk/typescript)
78
- for authentication, resource guides, generation and streaming, React
79
- integration, error handling, and the complete API reference.
113
+ for client setup, End-user scoping, chat and generation, a guide to each
114
+ resource, and error handling.
80
115
 
81
116
  ## Development
82
117
 
@@ -74,7 +74,7 @@ const mcpConnectionUrlSchema = z
74
74
  message: "URL must use http(s) without credentials, query, or fragment",
75
75
  })
76
76
  .transform((value) => new URL(value).toString());
77
- const mcpConnectionUrlInputSchema = mcpConnectionUrlSchema.describe("Streamable HTTP URL of the MCP server. Use `http` or `https`, with no credentials, query, or fragment.");
77
+ const mcpConnectionUrlInputSchema = mcpConnectionUrlSchema.describe("Streamable HTTP URL of the MCP server. Use `https`, with no credentials, query, or fragment.");
78
78
  const authTypeDescription = "How Blazing Agents authenticates to the MCP server: `none`, `bearer`, `oauth_client_credentials`, or `oauth_authorization_code`. The other fields you send depend on it.";
79
79
  export const mcpConnectionResponseSchema = z
80
80
  .object({
@@ -41,7 +41,7 @@ export const createMemoryBodySchema = z
41
41
  text: memoryTextSchema.describe("The note to remember, up to 10 KiB."),
42
42
  userId: userIdSchema
43
43
  .default("")
44
- .describe("The end user this memory belongs to. Only turns that pass the same `userId` see it. Leave it out or send an empty string for a general memory that every turn of the agent sees. It cannot change after creation."),
44
+ .describe("The end user this memory belongs to. Turns for that end user see it. Leave it out or send an empty string for a general memory, which unscoped turns see; a turn made through `forUser` sees only its end user's memories. It cannot change after creation."),
45
45
  })
46
46
  .strict();
47
47
  export const updateMemoryBodySchema = z
@@ -129,11 +129,6 @@ export declare const merchantUsageEventStatusSchema: z.ZodEnum<{
129
129
  pending: "pending";
130
130
  }>;
131
131
  export type MerchantUsageEventStatus = z.infer<typeof merchantUsageEventStatusSchema>;
132
- export declare const merchantWorkflowIssueSchema: z.ZodEnum<{
133
- cancelled: "cancelled";
134
- error: "error";
135
- recovery_exhausted: "recovery_exhausted";
136
- }>;
137
132
  export declare const merchantUsageEventNextActionSchema: z.ZodEnum<{
138
133
  discard: "discard";
139
134
  investigate: "investigate";
@@ -186,11 +181,6 @@ export declare const merchantUsageEventSchema: z.ZodObject<{
186
181
  lastAttemptAt: z.ZodNullable<z.ZodISODateTime>;
187
182
  lastErrorCode: z.ZodNullable<z.ZodString>;
188
183
  acceptedAt: z.ZodNullable<z.ZodISODateTime>;
189
- workflowIssue: z.ZodNullable<z.ZodEnum<{
190
- cancelled: "cancelled";
191
- error: "error";
192
- recovery_exhausted: "recovery_exhausted";
193
- }>>;
194
184
  nextAction: z.ZodEnum<{
195
185
  discard: "discard";
196
186
  investigate: "investigate";
@@ -246,11 +236,6 @@ export declare const merchantUsageEventResponseSchema: z.ZodObject<{
246
236
  lastAttemptAt: z.ZodNullable<z.ZodISODateTime>;
247
237
  lastErrorCode: z.ZodNullable<z.ZodString>;
248
238
  acceptedAt: z.ZodNullable<z.ZodISODateTime>;
249
- workflowIssue: z.ZodNullable<z.ZodEnum<{
250
- cancelled: "cancelled";
251
- error: "error";
252
- recovery_exhausted: "recovery_exhausted";
253
- }>>;
254
239
  nextAction: z.ZodEnum<{
255
240
  discard: "discard";
256
241
  investigate: "investigate";
@@ -307,11 +292,6 @@ export declare const merchantUsageEventsResponseSchema: z.ZodObject<{
307
292
  lastAttemptAt: z.ZodNullable<z.ZodISODateTime>;
308
293
  lastErrorCode: z.ZodNullable<z.ZodString>;
309
294
  acceptedAt: z.ZodNullable<z.ZodISODateTime>;
310
- workflowIssue: z.ZodNullable<z.ZodEnum<{
311
- cancelled: "cancelled";
312
- error: "error";
313
- recovery_exhausted: "recovery_exhausted";
314
- }>>;
315
295
  nextAction: z.ZodEnum<{
316
296
  discard: "discard";
317
297
  investigate: "investigate";
@@ -386,10 +366,10 @@ export declare const merchantUsageSummaryResponseSchema: z.ZodObject<{
386
366
  }, z.core.$strip>;
387
367
  export type MerchantUsageSummaryResponse = z.infer<typeof merchantUsageSummaryResponseSchema>;
388
368
  /**
389
- * The operator-facing action derived from event state — computed at the
390
- * service seam, never persisted.
369
+ * The action a Tenant takes on an event. `automaticDeliveryStopped` is true
370
+ * when automatic delivery has given up on a `pending` event.
391
371
  */
392
372
  export declare function merchantUsageEventNextAction(event: {
373
+ automaticDeliveryStopped: boolean;
393
374
  status: MerchantUsageEventStatus;
394
- workflowIssue: z.infer<typeof merchantWorkflowIssueSchema> | null;
395
375
  }): z.infer<typeof merchantUsageEventNextActionSchema>;
@@ -99,11 +99,6 @@ export const merchantUsageEventStatusSchema = z.enum([
99
99
  "discarded",
100
100
  "expired",
101
101
  ]);
102
- export const merchantWorkflowIssueSchema = z.enum([
103
- "error",
104
- "cancelled",
105
- "recovery_exhausted",
106
- ]);
107
102
  export const merchantUsageEventNextActionSchema = z.enum([
108
103
  "none",
109
104
  "wait",
@@ -136,7 +131,6 @@ export const merchantUsageEventSchema = z
136
131
  lastAttemptAt: z.iso.datetime({ offset: true }).nullable(),
137
132
  lastErrorCode: z.string().nullable(),
138
133
  acceptedAt: z.iso.datetime({ offset: true }).nullable(),
139
- workflowIssue: merchantWorkflowIssueSchema.nullable(),
140
134
  nextAction: merchantUsageEventNextActionSchema,
141
135
  })
142
136
  .strip();
@@ -195,8 +189,8 @@ export const merchantUsageSummaryResponseSchema = z
195
189
  .object({ summary: merchantUsageSummarySchema })
196
190
  .strip();
197
191
  /**
198
- * The operator-facing action derived from event state — computed at the
199
- * service seam, never persisted.
192
+ * The action a Tenant takes on an event. `automaticDeliveryStopped` is true
193
+ * when automatic delivery has given up on a `pending` event.
200
194
  */
201
195
  export function merchantUsageEventNextAction(event) {
202
196
  switch (event.status) {
@@ -204,7 +198,7 @@ export function merchantUsageEventNextAction(event) {
204
198
  case "discarded":
205
199
  return "none";
206
200
  case "pending":
207
- return event.workflowIssue === null ? "wait" : "retry";
201
+ return event.automaticDeliveryStopped ? "retry" : "wait";
208
202
  case "failed":
209
203
  return "retry";
210
204
  case "incomplete":
@@ -15,7 +15,7 @@ export type { McpConnectionLiveDetails, McpConnectionTestErrorCode, } from "./en
15
15
  export { createMcpConnectionBodySchema, forwardedMetadataKeysSchema, mcpAttachmentResponseSchema, mcpAttachmentsResponseSchema, mcpConnectionAuthTypeSchema, mcpConnectionLiveDetailsSchema, mcpConnectionReconnectResultSchema, mcpConnectionResponseSchema, mcpConnectionStatusSchema, mcpConnectionsResponseSchema, mcpConnectionTestErrorCodeSchema, mcpConnectionTestResponseSchema, mcpOauthAuthorizationLaunchResponseSchema, reconnectMcpConnectionBodySchema, updateMcpAttachmentBodySchema, updateMcpConnectionBodySchema, } from "./entities/mcp-connections.ts";
16
16
  export type { CreateMemoryBody, Memory, UpdateMemoryBody, } from "./entities/memories.ts";
17
17
  export { createMemoryBodySchema, memoriesListResponseSchema, memoryResponseSchema, memorySchema, memoryTextSchema, updateMemoryBodySchema, } from "./entities/memories.ts";
18
- export { createMerchantConnectionBodySchema, merchantBindingResponseSchema, merchantBindingsResponseSchema, merchantConnectionResponseSchema, merchantConnectionSchema, merchantCustomerBindingSchema, merchantEnvironmentSchema, merchantGuardSchema, merchantProviderSchema, merchantUsageEventNextAction, merchantUsageEventNextActionSchema, merchantUsageEventResponseSchema, merchantUsageEventSchema, merchantUsageEventStatusSchema, merchantUsageEventsResponseSchema, merchantUsageSummaryQuerySchema, merchantUsageSummaryResponseSchema, merchantUsageSummarySchema, merchantWorkflowIssueSchema, updateMerchantConnectionBodySchema, upsertMerchantBindingBodySchema, } from "./entities/merchant.ts";
18
+ export { createMerchantConnectionBodySchema, merchantBindingResponseSchema, merchantBindingsResponseSchema, merchantConnectionResponseSchema, merchantConnectionSchema, merchantCustomerBindingSchema, merchantEnvironmentSchema, merchantGuardSchema, merchantProviderSchema, merchantUsageEventNextAction, merchantUsageEventNextActionSchema, merchantUsageEventResponseSchema, merchantUsageEventSchema, merchantUsageEventStatusSchema, merchantUsageEventsResponseSchema, merchantUsageSummaryQuerySchema, merchantUsageSummaryResponseSchema, merchantUsageSummarySchema, updateMerchantConnectionBodySchema, upsertMerchantBindingBodySchema, } from "./entities/merchant.ts";
19
19
  export { createPromptBodySchema, parsePromptVariables, promptResponseSchema, promptsListQuerySchema, promptsResponseSchema, promptTemplateSchema, renderPromptTemplate, updatePromptBodySchema, } from "./entities/prompts.ts";
20
20
  export { createProviderBodySchema, providerListItemSchema, providerModelsResponseSchema, providerResponseSchema, providersResponseSchema, providerTypeSchema, thinkingLevelsResponseSchema, updateProviderBodySchema, } from "./entities/providers.ts";
21
21
  export type { ChatSteerConsumedEvent, SessionActivity, SessionInput, SessionInputResponse, SessionInputState, SessionInputsQuery, SessionInputsResponse, StopSessionBody, StopSessionResponse, SubmitSessionInputBody, } from "./entities/session-inputs.ts";
@@ -10,7 +10,7 @@ export { blazingAgentsChatMessageMetadataSchema, chatFunctionCallEventSchema, ch
10
10
  export { chatConfigurationSchema, chatConnectionSchema, chatConnectionsResponseSchema, chatCredentialsSchema, chatHealthCheckSchema, chatHealthSchema, chatIdentitySchema, createChatConnectionBodySchema, rotateChatConnectionBodySchema, updateChatConnectionBodySchema, } from "./entities/chat-connections.js";
11
11
  export { createMcpConnectionBodySchema, forwardedMetadataKeysSchema, mcpAttachmentResponseSchema, mcpAttachmentsResponseSchema, mcpConnectionAuthTypeSchema, mcpConnectionLiveDetailsSchema, mcpConnectionReconnectResultSchema, mcpConnectionResponseSchema, mcpConnectionStatusSchema, mcpConnectionsResponseSchema, mcpConnectionTestErrorCodeSchema, mcpConnectionTestResponseSchema, mcpOauthAuthorizationLaunchResponseSchema, reconnectMcpConnectionBodySchema, updateMcpAttachmentBodySchema, updateMcpConnectionBodySchema, } from "./entities/mcp-connections.js";
12
12
  export { createMemoryBodySchema, memoriesListResponseSchema, memoryResponseSchema, memorySchema, memoryTextSchema, updateMemoryBodySchema, } from "./entities/memories.js";
13
- export { createMerchantConnectionBodySchema, merchantBindingResponseSchema, merchantBindingsResponseSchema, merchantConnectionResponseSchema, merchantConnectionSchema, merchantCustomerBindingSchema, merchantEnvironmentSchema, merchantGuardSchema, merchantProviderSchema, merchantUsageEventNextAction, merchantUsageEventNextActionSchema, merchantUsageEventResponseSchema, merchantUsageEventSchema, merchantUsageEventStatusSchema, merchantUsageEventsResponseSchema, merchantUsageSummaryQuerySchema, merchantUsageSummaryResponseSchema, merchantUsageSummarySchema, merchantWorkflowIssueSchema, updateMerchantConnectionBodySchema, upsertMerchantBindingBodySchema, } from "./entities/merchant.js";
13
+ export { createMerchantConnectionBodySchema, merchantBindingResponseSchema, merchantBindingsResponseSchema, merchantConnectionResponseSchema, merchantConnectionSchema, merchantCustomerBindingSchema, merchantEnvironmentSchema, merchantGuardSchema, merchantProviderSchema, merchantUsageEventNextAction, merchantUsageEventNextActionSchema, merchantUsageEventResponseSchema, merchantUsageEventSchema, merchantUsageEventStatusSchema, merchantUsageEventsResponseSchema, merchantUsageSummaryQuerySchema, merchantUsageSummaryResponseSchema, merchantUsageSummarySchema, updateMerchantConnectionBodySchema, upsertMerchantBindingBodySchema, } from "./entities/merchant.js";
14
14
  export { createPromptBodySchema, parsePromptVariables, promptResponseSchema, promptsListQuerySchema, promptsResponseSchema, promptTemplateSchema, renderPromptTemplate, updatePromptBodySchema, } from "./entities/prompts.js";
15
15
  export { createProviderBodySchema, providerListItemSchema, providerModelsResponseSchema, providerResponseSchema, providersResponseSchema, providerTypeSchema, thinkingLevelsResponseSchema, updateProviderBodySchema, } from "./entities/providers.js";
16
16
  export { chatSteerConsumedEventSchema, sessionActivitySchema, sessionInputRequestIdSchema, sessionInputResponseSchema, sessionInputSchema, sessionInputStateSchema, sessionInputsQuerySchema, sessionInputsResponseSchema, stopSessionBodySchema, stopSessionResponseSchema, submitSessionInputBodySchema, } from "./entities/session-inputs.js";
package/dist/index.d.ts CHANGED
@@ -27,7 +27,7 @@ export type { CreateWorkspaceBody, UpdateWorkspaceBody, Workspace, WorkspaceNetw
27
27
  export { BlazingAgentsDirectChatTransport, type BlazingAgentsDirectChatTransportOptions, } from "./direct-chat-transport.ts";
28
28
  export { BlazingAgentsError } from "./errors.ts";
29
29
  export { type ChatFunction, type ChatFunctionContext, type ChatFunctions, defineFunction, } from "./functions.ts";
30
- export { createChatRelay, createCompletionRelay, type RelayContext, type SessionOwnershipStore, } from "./relay.ts";
30
+ export { createChatRelay, createCompletionRelay, type RelayContext, } from "./relay.ts";
31
31
  export type { AgentsListOptions, AgentsResource, UserAgentsResource, } from "./resources/agents.ts";
32
32
  export type { ArtifactsResource } from "./resources/artifacts.ts";
33
33
  export type { ChatConnectionsResource } from "./resources/chat-connections.ts";
package/dist/relay.d.ts CHANGED
@@ -1,29 +1,26 @@
1
- import type { BlazingAgents } from "./client.ts";
2
1
  import type { ChatFunctions } from "./functions.ts";
2
+ import type { UserClient } from "./types.ts";
3
3
  export interface RelayContext {
4
+ /**
5
+ * Agent that serves this request. It must be owned by `userId`, and its
6
+ * Workspace must be owned by the same End-user; otherwise the API answers 404.
7
+ */
4
8
  agentId: string;
5
9
  /** Handlers for this authenticated request and its approved continuation. */
6
10
  functions?: ChatFunctions;
7
11
  metadata?: Record<string, unknown>;
8
- userId: string;
9
- }
10
- export interface SessionOwnershipStore {
11
12
  /**
12
- * Looks up the end user who owns the Session.
13
- * @param sessionId - Session to look up or record.
14
- * @returns The owner ID, or undefined when no owner is recorded.
13
+ * The signed-in End-user. The relay scopes every API request to this
14
+ * End-user with `client.forUser(userId)`, so the API only reaches that
15
+ * End-user's Agents, Sessions, and Workspaces. Follows the `forUser` rules:
16
+ * printable ASCII, at most 256 characters, no surrounding spaces.
15
17
  */
16
- ownerOf(sessionId: string): Promise<string | undefined>;
17
- /**
18
- * Records ownership of a newly created Session.
19
- * @param sessionId - Session to look up or record.
20
- * @param userId - End-user ID for request scope.
21
- * @returns Resolves after ownership is stored.
22
- */
23
- recordOwner(sessionId: string, userId: string): Promise<void>;
18
+ userId: string;
24
19
  }
25
- interface RelayOptions<Method extends keyof BlazingAgents> {
26
- client: Pick<BlazingAgents, Method>;
20
+ interface RelayOptions<Method extends keyof UserClient> {
21
+ client: {
22
+ forUser(userId: string): Pick<UserClient, Method>;
23
+ };
27
24
  /**
28
25
  * Resolves authenticated Agent and end-user context, or null for an unauthenticated request.
29
26
  * @param request - Incoming HTTP request.
@@ -32,18 +29,17 @@ interface RelayOptions<Method extends keyof BlazingAgents> {
32
29
  resolveContext(request: Request): Promise<RelayContext | null>;
33
30
  }
34
31
  /**
35
- * Relays useChat submissions. An assistant message carrying approval
36
- * responses submits the complete round and streams the continuation.
32
+ * Relays useChat submissions as the signed-in End-user. An assistant message
33
+ * carrying approval responses submits the complete round and streams the
34
+ * continuation.
37
35
  * @param options - Configuration for this operation.
38
- * @returns An HTTP handler that checks Session ownership before resuming.
36
+ * @returns An HTTP handler that runs each request through `client.forUser(context.userId)`, so the API answers 404 for a Session outside that End-user's scope.
39
37
  */
40
- export declare function createChatRelay(options: RelayOptions<"chat" | "continueChat"> & {
41
- sessions: SessionOwnershipStore;
42
- }): (request: Request) => Promise<Response>;
38
+ export declare function createChatRelay(options: RelayOptions<"chat" | "continueChat">): (request: Request) => Promise<Response>;
43
39
  /**
44
- * Creates an authenticated HTTP handler that validates prompts and relays text generation.
40
+ * Creates an authenticated HTTP handler that validates prompts and relays text generation as the signed-in End-user.
45
41
  * @param options - Configuration for this operation.
46
- * @returns An HTTP handler that validates prompts and relays text generation.
42
+ * @returns An HTTP handler that runs each request through `client.forUser(context.userId)`.
47
43
  */
48
44
  export declare function createCompletionRelay(options: RelayOptions<"completion">): (request: Request) => Promise<Response>;
49
45
  export {};
package/dist/relay.js CHANGED
@@ -13,10 +13,11 @@ const chatBodySchema = z.object({
13
13
  });
14
14
  const completionBodySchema = z.object({ prompt: z.string().trim().min(1) });
15
15
  /**
16
- * Relays useChat submissions. An assistant message carrying approval
17
- * responses submits the complete round and streams the continuation.
16
+ * Relays useChat submissions as the signed-in End-user. An assistant message
17
+ * carrying approval responses submits the complete round and streams the
18
+ * continuation.
18
19
  * @param options - Configuration for this operation.
19
- * @returns An HTTP handler that checks Session ownership before resuming.
20
+ * @returns An HTTP handler that runs each request through `client.forUser(context.userId)`, so the API answers 404 for a Session outside that End-user's scope.
20
21
  */
21
22
  export function createChatRelay(options) {
22
23
  return async (request) => {
@@ -25,6 +26,7 @@ export function createChatRelay(options) {
25
26
  if (!context) {
26
27
  return errorResponse(401, "unauthorized", "Authentication required.");
27
28
  }
29
+ const client = scopeTo(options.client, context.userId);
28
30
  const body = chatBodySchema.parse(await request.json());
29
31
  const validated = await safeValidateUIMessages({
30
32
  messages: [body.message],
@@ -32,13 +34,9 @@ export function createChatRelay(options) {
32
34
  if (!validated.success) {
33
35
  return errorResponse(400, "invalid_request", "Invalid chat message.");
34
36
  }
35
- if (body.sessionId !== undefined &&
36
- (await options.sessions.ownerOf(body.sessionId)) !== context.userId) {
37
- return errorResponse(403, "forbidden", "Session is not available.");
38
- }
39
37
  const message = validated.data[0];
40
38
  if (message.role === "assistant") {
41
- return await relayApprovalResponses(options.client, {
39
+ return await relayApprovalResponses(client, {
42
40
  agentId: context.agentId,
43
41
  functions: context.functions,
44
42
  message,
@@ -56,9 +54,8 @@ export function createChatRelay(options) {
56
54
  messageId: body.messageId,
57
55
  metadata: context.metadata,
58
56
  abortSignal: request.signal,
59
- userId: context.userId,
60
57
  };
61
- const result = await options.client.chat(body.sessionId === undefined
58
+ const result = await client.chat(body.sessionId === undefined
62
59
  ? {
63
60
  ...chatInput,
64
61
  trigger: "submit-message",
@@ -68,19 +65,6 @@ export function createChatRelay(options) {
68
65
  sessionId: body.sessionId,
69
66
  trigger: body.trigger,
70
67
  });
71
- const sessionId = await result.sessionId;
72
- if (body.sessionId === undefined) {
73
- try {
74
- await options.sessions.recordOwner(sessionId, context.userId);
75
- }
76
- catch (error) {
77
- await result
78
- .toResponse()
79
- .body?.cancel(error)
80
- .catch(() => undefined);
81
- throw error;
82
- }
83
- }
84
68
  return result.toResponse();
85
69
  }
86
70
  catch (error) {
@@ -89,7 +73,7 @@ export function createChatRelay(options) {
89
73
  };
90
74
  }
91
75
  /**
92
- * Validates the Session and forwards the last assistant approval round.
76
+ * Forwards the last assistant approval round to its Session.
93
77
  */
94
78
  async function relayApprovalResponses(client, { functions, message, request, ...input }) {
95
79
  if (input.sessionId === undefined) {
@@ -112,9 +96,9 @@ async function relayApprovalResponses(client, { functions, message, request, ...
112
96
  return continuation.toResponse();
113
97
  }
114
98
  /**
115
- * Creates an authenticated HTTP handler that validates prompts and relays text generation.
99
+ * Creates an authenticated HTTP handler that validates prompts and relays text generation as the signed-in End-user.
116
100
  * @param options - Configuration for this operation.
117
- * @returns An HTTP handler that validates prompts and relays text generation.
101
+ * @returns An HTTP handler that runs each request through `client.forUser(context.userId)`.
118
102
  */
119
103
  export function createCompletionRelay(options) {
120
104
  return async (request) => {
@@ -123,13 +107,13 @@ export function createCompletionRelay(options) {
123
107
  if (!context) {
124
108
  return errorResponse(401, "unauthorized", "Authentication required.");
125
109
  }
110
+ const client = scopeTo(options.client, context.userId);
126
111
  const body = completionBodySchema.parse(await request.json());
127
- const result = await options.client.completion({
112
+ const result = await client.completion({
128
113
  agentId: context.agentId,
129
114
  metadata: context.metadata,
130
115
  prompt: body.prompt,
131
116
  abortSignal: request.signal,
132
- userId: context.userId,
133
117
  });
134
118
  return result.toResponse();
135
119
  }
@@ -138,6 +122,19 @@ export function createCompletionRelay(options) {
138
122
  }
139
123
  };
140
124
  }
125
+ /**
126
+ * Scopes the client to the resolved End-user. An ID that `forUser` rejects is a
127
+ * Tenant resolver bug, not a browser error, so it becomes a plain error that
128
+ * the generic 500 response answers without the validation message.
129
+ */
130
+ function scopeTo(client, userId) {
131
+ try {
132
+ return client.forUser(userId);
133
+ }
134
+ catch (cause) {
135
+ throw new Error("The relay context has an invalid userId.", { cause });
136
+ }
137
+ }
141
138
  /**
142
139
  * Maps validation and SDK failures to safe public error responses.
143
140
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blazingagents/sdk",
3
- "version": "0.42.1",
3
+ "version": "0.43.1",
4
4
  "description": "TypeScript SDK for the Blazing Agents API",
5
5
  "homepage": "https://docs.blazingagents.com",
6
6
  "bugs": {