@blazingagents/sdk 0.1.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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +366 -0
  3. package/dist/chat-transport.d.ts +17 -0
  4. package/dist/chat-transport.js +58 -0
  5. package/dist/client.d.ts +38 -0
  6. package/dist/client.js +86 -0
  7. package/dist/contracts/api.d.ts +256 -0
  8. package/dist/contracts/api.js +189 -0
  9. package/dist/contracts/entities/agent-tools.d.ts +26 -0
  10. package/dist/contracts/entities/agent-tools.js +52 -0
  11. package/dist/contracts/entities/agents.d.ts +183 -0
  12. package/dist/contracts/entities/agents.js +153 -0
  13. package/dist/contracts/entities/artifacts.d.ts +71 -0
  14. package/dist/contracts/entities/artifacts.js +71 -0
  15. package/dist/contracts/entities/attribution.d.ts +27 -0
  16. package/dist/contracts/entities/attribution.js +27 -0
  17. package/dist/contracts/entities/chat.d.ts +269 -0
  18. package/dist/contracts/entities/chat.js +198 -0
  19. package/dist/contracts/entities/mcp-connections.d.ts +421 -0
  20. package/dist/contracts/entities/mcp-connections.js +473 -0
  21. package/dist/contracts/entities/memories.d.ts +56 -0
  22. package/dist/contracts/entities/memories.js +62 -0
  23. package/dist/contracts/entities/prompts.d.ts +61 -0
  24. package/dist/contracts/entities/prompts.js +96 -0
  25. package/dist/contracts/entities/providers.d.ts +123 -0
  26. package/dist/contracts/entities/providers.js +111 -0
  27. package/dist/contracts/entities/sessions.d.ts +156 -0
  28. package/dist/contracts/entities/sessions.js +120 -0
  29. package/dist/contracts/entities/skills.d.ts +167 -0
  30. package/dist/contracts/entities/skills.js +153 -0
  31. package/dist/contracts/entities/tasks.d.ts +457 -0
  32. package/dist/contracts/entities/tasks.js +252 -0
  33. package/dist/contracts/entities/tenants.d.ts +69 -0
  34. package/dist/contracts/entities/tenants.js +54 -0
  35. package/dist/contracts/entities/usage.d.ts +95 -0
  36. package/dist/contracts/entities/usage.js +117 -0
  37. package/dist/contracts/entities/workspaces.d.ts +89 -0
  38. package/dist/contracts/entities/workspaces.js +71 -0
  39. package/dist/contracts/ids.d.ts +57 -0
  40. package/dist/contracts/ids.js +79 -0
  41. package/dist/contracts/index.d.ts +15 -0
  42. package/dist/contracts/index.js +16 -0
  43. package/dist/contracts/limitations.d.ts +138 -0
  44. package/dist/contracts/limitations.js +140 -0
  45. package/dist/contracts/utils.d.ts +3 -0
  46. package/dist/contracts/utils.js +7 -0
  47. package/dist/errors.d.ts +33 -0
  48. package/dist/errors.js +48 -0
  49. package/dist/generation.d.ts +5 -0
  50. package/dist/generation.js +422 -0
  51. package/dist/http.d.ts +21 -0
  52. package/dist/http.js +307 -0
  53. package/dist/index.d.ts +20 -0
  54. package/dist/index.js +13 -0
  55. package/dist/relay.d.ts +20 -0
  56. package/dist/relay.js +113 -0
  57. package/dist/resources/agents.d.ts +8 -0
  58. package/dist/resources/agents.js +82 -0
  59. package/dist/resources/artifacts.d.ts +5 -0
  60. package/dist/resources/artifacts.js +29 -0
  61. package/dist/resources/mcp-connections.d.ts +2 -0
  62. package/dist/resources/mcp-connections.js +40 -0
  63. package/dist/resources/memories.d.ts +7 -0
  64. package/dist/resources/memories.js +33 -0
  65. package/dist/resources/prompts.d.ts +6 -0
  66. package/dist/resources/prompts.js +36 -0
  67. package/dist/resources/providers.d.ts +5 -0
  68. package/dist/resources/providers.js +38 -0
  69. package/dist/resources/sessions.d.ts +8 -0
  70. package/dist/resources/sessions.js +49 -0
  71. package/dist/resources/skills.d.ts +2 -0
  72. package/dist/resources/skills.js +49 -0
  73. package/dist/resources/tasks.d.ts +7 -0
  74. package/dist/resources/tasks.js +63 -0
  75. package/dist/resources/tenant.d.ts +6 -0
  76. package/dist/resources/tenant.js +19 -0
  77. package/dist/resources/usage.d.ts +7 -0
  78. package/dist/resources/usage.js +19 -0
  79. package/dist/resources/workspaces.d.ts +2 -0
  80. package/dist/resources/workspaces.js +31 -0
  81. package/dist/types.d.ts +381 -0
  82. package/dist/types.js +1 -0
  83. package/package.json +65 -0
@@ -0,0 +1,422 @@
1
+ import { createTextStreamResponse, parsePartialJson } from "ai";
2
+ import { sessionIdSchema } from "./contracts/ids.js";
3
+ import { BlazingAgentsError } from "./errors.js";
4
+ import { requestStream } from "./http.js";
5
+ // --- chat ---
6
+ export async function chat(config, input) {
7
+ const body = buildChatBody(input);
8
+ /**
9
+ * URL presence is the mode: no `sessionId` → create
10
+ * (`POST /v1/agents/:agentId/sessions`, server mints the `ss_` id,
11
+ * returned via `Location`); `sessionId` present → resume
12
+ * (`POST /v1/agents/:agentId/sessions/:sessionId`).
13
+ */
14
+ const path = input.sessionId === undefined
15
+ ? `/v1/agents/${input.agentId}/sessions`
16
+ : `/v1/agents/${input.agentId}/sessions/${input.sessionId}`;
17
+ const response = await requestStream(config, path, {
18
+ json: body,
19
+ method: "POST",
20
+ clientRequestId: input.clientRequestId,
21
+ ...(input.signal ? { signal: input.signal } : {}),
22
+ });
23
+ return buildChatResult(response, input.sessionId);
24
+ }
25
+ function buildChatBody(input) {
26
+ const base = {};
27
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits an undefined trigger.
28
+ if (input.trigger !== undefined) {
29
+ base.trigger = input.trigger;
30
+ }
31
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits an undefined message id.
32
+ if (input.messageId !== undefined) {
33
+ base.messageId = input.messageId;
34
+ }
35
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits an undefined Version Pin.
36
+ if (input.version !== undefined) {
37
+ base.version = input.version;
38
+ }
39
+ if ("message" in input) {
40
+ base.message = input.message;
41
+ }
42
+ else {
43
+ base.promptId = input.promptId;
44
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits undefined variables.
45
+ if (input.variables !== undefined) {
46
+ base.variables = input.variables;
47
+ }
48
+ }
49
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits an undefined user id.
50
+ if (input.userId !== undefined) {
51
+ base.userId = input.userId;
52
+ }
53
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits undefined metadata.
54
+ if (input.metadata !== undefined) {
55
+ base.metadata = input.metadata;
56
+ }
57
+ return base;
58
+ }
59
+ /**
60
+ * Extracts the server-minted `ss_` id from the `Location` header on the
61
+ * create path. The header is `/v1/agents/:agentId/sessions/:newId`; the
62
+ * id is the trailing path segment, validated against `sessionIdSchema`
63
+ * so a malformed or non-`ss_` value surfaces as a `stream_error` instead
64
+ * of flowing into resume calls as an untyped string.
65
+ */
66
+ function sessionIdFromLocation(response, requestId) {
67
+ const location = response.headers.get("location");
68
+ if (!location) {
69
+ const message = "The server did not return a session id (no Location header).";
70
+ throw new BlazingAgentsError({
71
+ code: "stream_error",
72
+ message,
73
+ requestId,
74
+ }, { cause: new Error(message) });
75
+ }
76
+ const id = location.split("/").pop();
77
+ const parsed = sessionIdSchema.safeParse(id);
78
+ if (!parsed.success) {
79
+ throw new BlazingAgentsError({
80
+ code: "stream_error",
81
+ message: "The server returned a malformed session Location header.",
82
+ requestId,
83
+ }, { cause: parsed.error });
84
+ }
85
+ return parsed.data;
86
+ }
87
+ function buildChatResult(response, resumeSessionId) {
88
+ const terminalResult = buildTerminalStreamResult(response, "chat");
89
+ /**
90
+ * `sessionId` resolves from the `Location` header on create, or to the
91
+ * passed id on resume. Read eagerly (the header is available before the
92
+ * body streams) so awaiting `result.sessionId` does not depend on
93
+ * draining the stream.
94
+ */
95
+ let sessionIdPromise;
96
+ if (resumeSessionId === undefined) {
97
+ try {
98
+ sessionIdPromise = Promise.resolve(sessionIdFromLocation(response, terminalResult.requestId));
99
+ }
100
+ catch (error) {
101
+ sessionIdPromise = Promise.reject(error);
102
+ }
103
+ }
104
+ else {
105
+ sessionIdPromise = Promise.resolve(resumeSessionId);
106
+ }
107
+ sessionIdPromise.catch(() => {
108
+ /* no-op — prevents unhandled rejection if the caller never awaits */
109
+ });
110
+ return {
111
+ sessionId: sessionIdPromise,
112
+ ...terminalResult,
113
+ };
114
+ }
115
+ export function buildTerminalStreamResult(response, resourceName) {
116
+ const requestId = response.headers.get("x-request-id") ?? undefined;
117
+ const location = response.headers.get("location");
118
+ let bodyClaimed = false;
119
+ const claimBody = () => {
120
+ if (bodyClaimed) {
121
+ const message = `The ${resourceName} response body has already been claimed.`;
122
+ const cause = new Error(message);
123
+ throw new BlazingAgentsError({
124
+ code: "stream_error",
125
+ message,
126
+ requestId,
127
+ }, { cause });
128
+ }
129
+ bodyClaimed = true;
130
+ return normalizeStreamErrors(responseBodyStream(response, requestId, resourceName), requestId, `The ${resourceName} response stream failed.`);
131
+ };
132
+ return {
133
+ requestId,
134
+ toResponse: () => {
135
+ const headers = replacementResponseHeaders(requestId, location);
136
+ headers.set("content-type", "text/event-stream");
137
+ headers.set("cache-control", "no-cache");
138
+ headers.set("connection", "keep-alive");
139
+ headers.set("x-vercel-ai-ui-message-stream", "v1");
140
+ headers.set("x-accel-buffering", "no");
141
+ try {
142
+ return new Response(claimBody(), {
143
+ status: response.status,
144
+ statusText: response.statusText,
145
+ headers,
146
+ });
147
+ }
148
+ catch (cause) {
149
+ throw toStreamError(cause, requestId, `The ${resourceName} response stream failed.`);
150
+ }
151
+ },
152
+ };
153
+ }
154
+ function toStreamError(cause, requestId, fallbackMessage) {
155
+ if (BlazingAgentsError.isInstance(cause) &&
156
+ cause.code === "stream_error" &&
157
+ cause.requestId === requestId) {
158
+ return cause;
159
+ }
160
+ let message;
161
+ if (cause instanceof Error) {
162
+ message = cause.message;
163
+ }
164
+ else if (typeof fallbackMessage === "function") {
165
+ message = fallbackMessage(cause);
166
+ }
167
+ else {
168
+ message = fallbackMessage;
169
+ }
170
+ return new BlazingAgentsError({
171
+ code: "stream_error",
172
+ message,
173
+ requestId,
174
+ }, { cause });
175
+ }
176
+ function normalizeStreamErrors(stream, requestId, fallbackMessage) {
177
+ let reader;
178
+ try {
179
+ reader = stream.getReader();
180
+ }
181
+ catch (cause) {
182
+ throw toStreamError(cause, requestId, fallbackMessage);
183
+ }
184
+ return new ReadableStream({
185
+ async pull(controller) {
186
+ try {
187
+ const { done, value } = await reader.read();
188
+ if (done) {
189
+ controller.close();
190
+ return;
191
+ }
192
+ controller.enqueue(value);
193
+ }
194
+ catch (cause) {
195
+ controller.error(toStreamError(cause, requestId, fallbackMessage));
196
+ }
197
+ },
198
+ async cancel(reason) {
199
+ try {
200
+ await reader.cancel(reason);
201
+ }
202
+ catch (cause) {
203
+ throw toStreamError(cause, requestId, fallbackMessage);
204
+ }
205
+ },
206
+ });
207
+ }
208
+ function responseBodyStream(response, requestId, resourceName) {
209
+ if (response.body) {
210
+ return response.body;
211
+ }
212
+ const message = `The ${resourceName} response did not include a body.`;
213
+ const cause = new Error(message);
214
+ const error = new BlazingAgentsError({
215
+ code: "stream_error",
216
+ message,
217
+ requestId,
218
+ }, { cause });
219
+ return new ReadableStream({
220
+ start(controller) {
221
+ controller.error(error);
222
+ },
223
+ });
224
+ }
225
+ function replacementResponseHeaders(requestId, location) {
226
+ const headers = new Headers();
227
+ if (requestId !== undefined) {
228
+ headers.set("x-request-id", requestId);
229
+ }
230
+ if (location !== null) {
231
+ headers.set("location", location);
232
+ }
233
+ return headers;
234
+ }
235
+ function buildStatelessGenerationBody(input, output) {
236
+ const body = { output };
237
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits an undefined Version Pin.
238
+ if (input.version !== undefined) {
239
+ body.version = input.version;
240
+ }
241
+ if ("prompt" in input) {
242
+ body.prompt = input.prompt;
243
+ }
244
+ else {
245
+ body.promptId = input.promptId;
246
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits undefined variables.
247
+ if (input.variables !== undefined) {
248
+ body.variables = input.variables;
249
+ }
250
+ }
251
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits an undefined user id.
252
+ if (input.userId !== undefined) {
253
+ body.userId = input.userId;
254
+ }
255
+ // Stryker disable next-line ConditionalExpression: JSON serialization omits undefined metadata.
256
+ if (input.metadata !== undefined) {
257
+ body.metadata = input.metadata;
258
+ }
259
+ return body;
260
+ }
261
+ // --- completion ---
262
+ export async function completion(config, input) {
263
+ const body = buildStatelessGenerationBody(input, { type: "text" });
264
+ const path = `/v1/agents/${input.agentId}/generation`;
265
+ const response = await requestStream(config, path, {
266
+ json: body,
267
+ method: "POST",
268
+ clientRequestId: input.clientRequestId,
269
+ ...(input.signal ? { signal: input.signal } : {}),
270
+ });
271
+ return buildCompletionResult(response);
272
+ }
273
+ function buildCompletionResult(response) {
274
+ const { finalStream, outputStream, requestId, toResponse } = buildStatelessGenerationStreams(response, "completion");
275
+ const textPromise = (async () => {
276
+ let text = "";
277
+ for await (const delta of finalStream) {
278
+ text += delta;
279
+ }
280
+ return text;
281
+ })();
282
+ /**
283
+ * Attach a no-op rejection handler so the promise doesn't trigger an
284
+ * unhandled-rejection warning if the caller only uses `textStream` or
285
+ * `toResponse()` without awaiting `text`.
286
+ */
287
+ textPromise.catch(() => {
288
+ /* no-op — prevents unhandled rejection if the caller never awaits */
289
+ });
290
+ return {
291
+ requestId,
292
+ textStream: outputStream,
293
+ text: textPromise,
294
+ toResponse,
295
+ };
296
+ }
297
+ // --- object ---
298
+ export async function objectGeneration(config, input) {
299
+ const body = buildStatelessGenerationBody(input, {
300
+ type: "object",
301
+ schema: input.schema,
302
+ });
303
+ const path = `/v1/agents/${input.agentId}/generation`;
304
+ const response = await requestStream(config, path, {
305
+ json: body,
306
+ method: "POST",
307
+ clientRequestId: input.clientRequestId,
308
+ ...(input.signal ? { signal: input.signal } : {}),
309
+ });
310
+ return buildObjectResult(response);
311
+ }
312
+ function buildObjectResult(response) {
313
+ const { finalStream, outputStream, requestId, toResponse } = buildStatelessGenerationStreams(response, "object");
314
+ let accumulatedText = "";
315
+ const partialObjectStream = outputStream.pipeThrough(new TransformStream({
316
+ async transform(chunk, controller) {
317
+ accumulatedText += chunk;
318
+ const { value } = await parsePartialJson(accumulatedText);
319
+ if (value !== undefined) {
320
+ controller.enqueue(value);
321
+ }
322
+ },
323
+ flush() {
324
+ try {
325
+ JSON.parse(accumulatedText);
326
+ }
327
+ catch (cause) {
328
+ throw new BlazingAgentsError({
329
+ code: "stream_error",
330
+ message: "The agent produced invalid JSON.",
331
+ requestId,
332
+ }, { cause });
333
+ }
334
+ },
335
+ }));
336
+ const objectPromise = (async () => {
337
+ let text = "";
338
+ for await (const delta of finalStream) {
339
+ text += delta;
340
+ }
341
+ try {
342
+ return JSON.parse(text);
343
+ }
344
+ catch (cause) {
345
+ throw new BlazingAgentsError({
346
+ code: "stream_error",
347
+ message: "The agent produced invalid JSON.",
348
+ requestId,
349
+ }, { cause });
350
+ }
351
+ })();
352
+ objectPromise.catch(() => {
353
+ /* no-op — prevents unhandled rejection if the caller never awaits */
354
+ });
355
+ return {
356
+ partialObjectStream,
357
+ object: objectPromise,
358
+ requestId,
359
+ toResponse,
360
+ };
361
+ }
362
+ // --- helpers ---
363
+ function buildStatelessGenerationStreams(response, resourceName) {
364
+ const requestId = response.headers.get("x-request-id") ?? undefined;
365
+ const location = response.headers.get("location");
366
+ const rawStream = responseBodyStream(response, requestId, resourceName);
367
+ const textStream = decodeTextStream(rawStream, requestId, resourceName);
368
+ /**
369
+ * The public output, awaited final value, and response relay each need a
370
+ * branch. `tee()` produces two branches, so tee twice.
371
+ */
372
+ const [outputStream, forRest] = textStream.tee();
373
+ const [finalStream, relayStream] = forRest.tee();
374
+ let responseBodyClaimed = false;
375
+ return {
376
+ finalStream,
377
+ outputStream,
378
+ requestId,
379
+ toResponse: () => {
380
+ if (responseBodyClaimed) {
381
+ const message = `The ${resourceName} response body has already been claimed.`;
382
+ throw new BlazingAgentsError({
383
+ code: "stream_error",
384
+ message,
385
+ requestId,
386
+ }, { cause: new Error(message) });
387
+ }
388
+ responseBodyClaimed = true;
389
+ const headers = replacementResponseHeaders(requestId, location);
390
+ headers.set("content-type", "text/plain; charset=utf-8");
391
+ try {
392
+ return createTextStreamResponse({
393
+ stream: relayStream,
394
+ status: response.status,
395
+ statusText: response.statusText,
396
+ headers,
397
+ });
398
+ }
399
+ catch (cause) {
400
+ throw toStreamError(cause, requestId, `The ${resourceName} response stream failed.`);
401
+ }
402
+ },
403
+ };
404
+ }
405
+ /**
406
+ * Wraps a `ReadableStream<Uint8Array>` as a `ReadableStream<string>` via
407
+ * `TextDecoderStream`. The cast works around a TS/Node-types mismatch
408
+ * where `TextDecoderStream`'s writable accepts `BufferSource` but the
409
+ * stream's chunks are typed as `Uint8Array<ArrayBufferLike>`.
410
+ */
411
+ function decodeTextStream(raw, requestId, resourceName) {
412
+ let decodedStream;
413
+ try {
414
+ decodedStream = raw.pipeThrough(new TextDecoderStream());
415
+ }
416
+ catch (cause) {
417
+ throw toStreamError(cause, requestId, `The ${resourceName} response stream failed.`);
418
+ }
419
+ return normalizeStreamErrors(decodedStream, requestId, (cause) => typeof cause === "string"
420
+ ? cause
421
+ : `The ${resourceName} response stream failed.`);
422
+ }
package/dist/http.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { BlazingAgentsError } from "./errors.ts";
2
+ import type { HttpConfig, RequestOptions } from "./types.ts";
3
+ /**
4
+ * Performs a request and returns the parsed JSON body for success (status
5
+ * 2xx). API errors preserve the tolerant wire envelope; malformed responses
6
+ * become `invalid_response`.
7
+ */
8
+ export declare function requestJson<T>(config: HttpConfig, path: string, options?: RequestOptions, schema?: {
9
+ parse(value: unknown): T;
10
+ }): Promise<T>;
11
+ /**
12
+ * Performs a request and returns the raw `Response` for streaming paths.
13
+ * Non-2xx bodies are decoded before a caller can observe a streaming body.
14
+ */
15
+ export declare function requestStream(config: HttpConfig, path: string, options?: RequestOptions): Promise<Response>;
16
+ /**
17
+ * Decodes a response body with the tolerant consumer schema. Unknown future
18
+ * codes and fields remain valid; malformed responses never infer a domain
19
+ * code from HTTP status.
20
+ */
21
+ export declare function parseErrorEnvelope(bodyText: string, status: number, headers?: Headers): BlazingAgentsError;