@usestratus/sdk 1.6.0 → 1.9.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 (59) hide show
  1. package/README.md +109 -2
  2. package/dist/ai-sdk/index.d.ts +294 -0
  3. package/dist/ai-sdk/index.d.ts.map +1 -0
  4. package/dist/ai-sdk/index.js +741 -0
  5. package/dist/ai-sdk/index.js.map +1 -0
  6. package/dist/azure/index.d.ts +4 -4
  7. package/dist/azure/index.d.ts.map +1 -1
  8. package/dist/azure/index.js +1 -1
  9. package/dist/azure/index.js.map +1 -1
  10. package/dist/azure/responses-model.js +15 -5
  11. package/dist/azure/responses-model.js.map +1 -1
  12. package/dist/core/codemode/index.d.ts +1 -2
  13. package/dist/core/codemode/index.d.ts.map +1 -1
  14. package/dist/core/codemode/index.js.map +1 -1
  15. package/dist/core/index.d.ts +41 -34
  16. package/dist/core/index.d.ts.map +1 -1
  17. package/dist/core/index.js +18 -15
  18. package/dist/core/index.js.map +1 -1
  19. package/dist/core/run.d.ts.map +1 -1
  20. package/dist/core/run.js +1 -1
  21. package/dist/core/run.js.map +1 -1
  22. package/dist/core/session.d.ts.map +1 -1
  23. package/dist/core/session.js.map +1 -1
  24. package/dist/core/subagent.js +1 -1
  25. package/dist/core/subagent.js.map +1 -1
  26. package/dist/core/types.d.ts +4 -1
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/core/utils/zod.d.ts.map +1 -1
  29. package/dist/core/utils/zod.js.map +1 -1
  30. package/dist/core/validate-agent.d.ts.map +1 -1
  31. package/dist/core/validate-agent.js.map +1 -1
  32. package/dist/core/workflow-draft.d.ts +32 -0
  33. package/dist/core/workflow-draft.d.ts.map +1 -0
  34. package/dist/core/workflow-draft.js +84 -0
  35. package/dist/core/workflow-draft.js.map +1 -0
  36. package/dist/core/workflow-manager.d.ts +25 -0
  37. package/dist/core/workflow-manager.d.ts.map +1 -0
  38. package/dist/core/workflow-manager.js +178 -0
  39. package/dist/core/workflow-manager.js.map +1 -0
  40. package/dist/core/workflow-saved.d.ts +21 -0
  41. package/dist/core/workflow-saved.d.ts.map +1 -0
  42. package/dist/core/workflow-saved.js +79 -0
  43. package/dist/core/workflow-saved.js.map +1 -0
  44. package/dist/core/workflow.d.ts +262 -0
  45. package/dist/core/workflow.d.ts.map +1 -0
  46. package/dist/core/workflow.js +560 -0
  47. package/dist/core/workflow.js.map +1 -0
  48. package/dist/effect/index.d.ts +39 -0
  49. package/dist/effect/index.d.ts.map +1 -0
  50. package/dist/effect/index.js +90 -0
  51. package/dist/effect/index.js.map +1 -0
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +1 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/testing/index.d.ts +1 -1
  57. package/dist/testing/index.d.ts.map +1 -1
  58. package/dist/testing/index.js.map +1 -1
  59. package/package.json +19 -5
@@ -0,0 +1,741 @@
1
+ import { resumeRun, stream } from "../core/run";
2
+ import { resumeSession } from "../core/session";
3
+ function isUIMessage(message) {
4
+ return "parts" in message && Array.isArray(message.parts);
5
+ }
6
+ function stringifyOutput(value) {
7
+ if (typeof value === "string")
8
+ return value;
9
+ if (value && typeof value === "object" && "type" in value) {
10
+ const typed = value;
11
+ if (typed.type === "text" || typed.type === "error-text")
12
+ return String(typed.value ?? "");
13
+ if (typed.type === "execution-denied")
14
+ return typed.reason ?? "Tool execution denied";
15
+ }
16
+ return JSON.stringify(value);
17
+ }
18
+ function parseJsonish(value) {
19
+ try {
20
+ return JSON.parse(value);
21
+ }
22
+ catch {
23
+ return value;
24
+ }
25
+ }
26
+ function toolNameFromUIPart(part) {
27
+ if (part.type === "dynamic-tool" && typeof part.toolName === "string")
28
+ return part.toolName;
29
+ if (part.type.startsWith("tool-"))
30
+ return part.type.slice("tool-".length);
31
+ return undefined;
32
+ }
33
+ function isRecord(value) {
34
+ return typeof value === "object" && value !== null;
35
+ }
36
+ function isTextUIPart(part) {
37
+ return part.type === "text" && typeof part.text === "string";
38
+ }
39
+ function isFileUIPart(part) {
40
+ return (part.type === "file" &&
41
+ typeof part.url === "string" &&
42
+ typeof part.mediaType === "string");
43
+ }
44
+ function isModelTextPart(part) {
45
+ return part.type === "text" && typeof part.text === "string";
46
+ }
47
+ function isModelToolCallPart(part) {
48
+ return (part.type === "tool-call" &&
49
+ typeof part.toolCallId === "string" &&
50
+ typeof part.toolName === "string");
51
+ }
52
+ function isModelToolResultPart(part) {
53
+ return (part.type === "tool-result" && typeof part.toolCallId === "string");
54
+ }
55
+ function imagePartFromUrl(url) {
56
+ return { type: "image_url", image_url: { url } };
57
+ }
58
+ function filePartFromUrl(url, filename) {
59
+ return { type: "file", file: { url }, filename };
60
+ }
61
+ function contentPartFromModelPart(part) {
62
+ if (isModelTextPart(part))
63
+ return { type: "text", text: part.text };
64
+ if (part.type === "image") {
65
+ const image = part.image;
66
+ if (typeof image === "string")
67
+ return imagePartFromUrl(image);
68
+ if (image instanceof URL)
69
+ return imagePartFromUrl(image.toString());
70
+ if (isRecord(image) && image.type === "reference" && typeof image.reference === "string") {
71
+ return { type: "image_url", image_url: { file_id: image.reference } };
72
+ }
73
+ }
74
+ if (part.type === "file") {
75
+ const file = part;
76
+ const filename = typeof file.filename === "string" ? file.filename : undefined;
77
+ if (typeof file.data === "string")
78
+ return filePartFromUrl(file.data, filename);
79
+ if (file.data instanceof URL)
80
+ return filePartFromUrl(file.data.toString(), filename);
81
+ if (isRecord(file.data) && file.data.type === "url" && typeof file.data.url === "string") {
82
+ return filePartFromUrl(file.data.url, filename);
83
+ }
84
+ if (isRecord(file.data) &&
85
+ file.data.type === "reference" &&
86
+ typeof file.data.reference === "string") {
87
+ return { type: "file", file: { file_id: file.data.reference }, filename };
88
+ }
89
+ }
90
+ return undefined;
91
+ }
92
+ function contentPartFromUIPart(part, options) {
93
+ if (isTextUIPart(part))
94
+ return { type: "text", text: part.text };
95
+ if (isFileUIPart(part)) {
96
+ if (part.mediaType.startsWith("image/"))
97
+ return imagePartFromUrl(part.url);
98
+ return filePartFromUrl(part.url, part.filename);
99
+ }
100
+ if (part.type.startsWith("data-"))
101
+ return options?.convertDataPart?.(part);
102
+ return undefined;
103
+ }
104
+ function normalizeContent(parts) {
105
+ if (parts.length === 0)
106
+ return "";
107
+ if (parts.every((part) => part.type === "text")) {
108
+ return parts.map((part) => part.text).join("");
109
+ }
110
+ return parts;
111
+ }
112
+ function fromUIMessage(message, options) {
113
+ if (message.role === "system") {
114
+ return [
115
+ {
116
+ role: "system",
117
+ content: message.parts.map((p) => (isTextUIPart(p) ? p.text : "")).join(""),
118
+ },
119
+ ];
120
+ }
121
+ if (message.role === "user") {
122
+ const parts = message.parts
123
+ .map((part) => contentPartFromUIPart(part, options))
124
+ .filter((part) => part !== undefined);
125
+ return [{ role: "user", content: normalizeContent(parts) }];
126
+ }
127
+ const text = message.parts
128
+ .filter(isTextUIPart)
129
+ .map((part) => part.text)
130
+ .join("");
131
+ const toolCalls = [];
132
+ const toolMessages = [];
133
+ for (const part of message.parts) {
134
+ const toolName = toolNameFromUIPart(part);
135
+ if (!toolName || !("toolCallId" in part))
136
+ continue;
137
+ const toolPart = part;
138
+ const input = "input" in part ? part.input : undefined;
139
+ if (toolPart.state === "input-available" ||
140
+ toolPart.state === "approval-requested" ||
141
+ toolPart.state === "approval-responded" ||
142
+ toolPart.state === "output-available" ||
143
+ toolPart.state === "output-error" ||
144
+ toolPart.state === "output-denied") {
145
+ toolCalls.push({
146
+ id: toolPart.toolCallId,
147
+ type: "function",
148
+ function: { name: toolName, arguments: JSON.stringify(input ?? {}) },
149
+ });
150
+ }
151
+ if (toolPart.state === "output-available") {
152
+ toolMessages.push({
153
+ role: "tool",
154
+ tool_call_id: toolPart.toolCallId,
155
+ content: stringifyOutput(toolPart.output),
156
+ });
157
+ }
158
+ if (toolPart.state === "output-error") {
159
+ toolMessages.push({
160
+ role: "tool",
161
+ tool_call_id: toolPart.toolCallId,
162
+ content: toolPart.errorText ?? "Tool execution failed",
163
+ });
164
+ }
165
+ if (toolPart.state === "output-denied") {
166
+ toolMessages.push({
167
+ role: "tool",
168
+ tool_call_id: toolPart.toolCallId,
169
+ content: toolPart.approval?.reason ?? "Tool execution denied",
170
+ });
171
+ }
172
+ }
173
+ const assistant = {
174
+ role: "assistant",
175
+ content: text || null,
176
+ ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
177
+ };
178
+ return [assistant, ...toolMessages];
179
+ }
180
+ function fromModelMessage(message) {
181
+ if (message.role === "system")
182
+ return [{ role: "system", content: message.content }];
183
+ if (message.role === "user") {
184
+ if (typeof message.content === "string")
185
+ return [{ role: "user", content: message.content }];
186
+ const parts = message.content
187
+ .map(contentPartFromModelPart)
188
+ .filter((part) => part !== undefined);
189
+ return [{ role: "user", content: normalizeContent(parts) }];
190
+ }
191
+ if (message.role === "tool") {
192
+ return message.content.filter(isModelToolResultPart).map((part) => ({
193
+ role: "tool",
194
+ tool_call_id: String(part.toolCallId),
195
+ content: stringifyOutput(part.output),
196
+ }));
197
+ }
198
+ if (typeof message.content === "string") {
199
+ return [{ role: "assistant", content: message.content }];
200
+ }
201
+ const text = message.content
202
+ .filter(isModelTextPart)
203
+ .map((part) => part.text)
204
+ .join("");
205
+ const toolCalls = message.content.filter(isModelToolCallPart).map((part) => ({
206
+ id: part.toolCallId,
207
+ type: "function",
208
+ function: { name: part.toolName, arguments: JSON.stringify(part.input ?? {}) },
209
+ }));
210
+ return [
211
+ {
212
+ role: "assistant",
213
+ content: text || null,
214
+ ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
215
+ },
216
+ ];
217
+ }
218
+ export function fromAISDKMessages(messages, options) {
219
+ return messages.flatMap((message) => isUIMessage(message) ? fromUIMessage(message, options) : fromModelMessage(message));
220
+ }
221
+ export function toAISDKUIMessages(messagesOrSnapshot) {
222
+ const messages = Array.isArray(messagesOrSnapshot)
223
+ ? messagesOrSnapshot
224
+ : "messages" in messagesOrSnapshot
225
+ ? messagesOrSnapshot.messages
226
+ : [];
227
+ const toolResults = new Map();
228
+ const uiMessages = [];
229
+ for (const message of messages) {
230
+ if (message.role === "tool") {
231
+ toolResults.set(message.tool_call_id, message.content);
232
+ }
233
+ }
234
+ for (const message of messages) {
235
+ if (message.role === "tool") {
236
+ continue;
237
+ }
238
+ if (message.role === "developer")
239
+ continue;
240
+ if (message.role === "assistant") {
241
+ const parts = contentToUIParts(message.content);
242
+ for (const toolCall of message.tool_calls ?? []) {
243
+ const toolName = toolCall.function.name;
244
+ const output = toolResults.get(toolCall.id);
245
+ parts.push({
246
+ type: `tool-${toolName}`,
247
+ toolCallId: toolCall.id,
248
+ state: output === undefined ? "input-available" : "output-available",
249
+ input: parseJsonish(toolCall.function.arguments),
250
+ ...(output === undefined ? {} : { output }),
251
+ });
252
+ }
253
+ uiMessages.push({
254
+ id: crypto.randomUUID(),
255
+ role: "assistant",
256
+ parts,
257
+ });
258
+ continue;
259
+ }
260
+ uiMessages.push({
261
+ id: crypto.randomUUID(),
262
+ role: message.role,
263
+ parts: userOrSystemContentToUIParts(message.content),
264
+ });
265
+ }
266
+ return uiMessages;
267
+ }
268
+ export function toSessionSnapshotFromAISDKMessages(messages, options) {
269
+ return {
270
+ id: options?.id ?? crypto.randomUUID(),
271
+ messages: fromAISDKMessages(messages, options).filter((message) => message.role !== "system"),
272
+ };
273
+ }
274
+ export function resumeSessionFromAISDKMessages(messages, config, options) {
275
+ return resumeSession(toSessionSnapshotFromAISDKMessages(messages, options), config);
276
+ }
277
+ function contentToUIParts(content) {
278
+ if (typeof content === "string")
279
+ return [{ type: "text", text: content }];
280
+ return [];
281
+ }
282
+ function userOrSystemContentToUIParts(content) {
283
+ if (typeof content === "string")
284
+ return [{ type: "text", text: content }];
285
+ return content.flatMap((part) => {
286
+ if (part.type === "text")
287
+ return [{ type: "text", text: part.text }];
288
+ if (part.type === "image_url" && "url" in part.image_url) {
289
+ return [{ type: "file", url: part.image_url.url, mediaType: "image" }];
290
+ }
291
+ if (part.type === "file" && "url" in part.file) {
292
+ return [
293
+ {
294
+ type: "file",
295
+ url: part.file.url,
296
+ mediaType: "application/octet-stream",
297
+ filename: part.filename,
298
+ },
299
+ ];
300
+ }
301
+ return [];
302
+ });
303
+ }
304
+ export function toAISDKUIMessage(result, options) {
305
+ const messages = Array.isArray(result) ? result : result.messages;
306
+ const lastAssistant = [...messages].reverse().find((message) => message.role === "assistant");
307
+ return {
308
+ id: options?.id ?? crypto.randomUUID(),
309
+ role: "assistant",
310
+ metadata: options?.metadata,
311
+ parts: lastAssistant ? contentToUIParts(lastAssistant.content) : [],
312
+ };
313
+ }
314
+ function finishReasonFromEvent(event) {
315
+ switch (event.response.finishReason) {
316
+ case "stop":
317
+ case "length":
318
+ case "content_filter":
319
+ return event.response.finishReason;
320
+ case "tool_calls":
321
+ return "tool-calls";
322
+ default:
323
+ return event.response.finishReason;
324
+ }
325
+ }
326
+ export function toAISDKToolApprovalRequests(interrupted) {
327
+ return interrupted.pendingToolCalls.map((call) => ({
328
+ type: "tool-approval-request",
329
+ approvalId: call.toolCallId,
330
+ toolCallId: call.toolCallId,
331
+ isAutomatic: false,
332
+ }));
333
+ }
334
+ export function approvalsFromAISDKMessages(messages, pendingToolCalls) {
335
+ const pending = new Set(pendingToolCalls.map((call) => call.toolCallId));
336
+ const approvals = new Map();
337
+ for (const message of messages) {
338
+ if (!isUIMessage(message))
339
+ continue;
340
+ for (const part of message.parts) {
341
+ const toolName = toolNameFromUIPart(part);
342
+ if (!toolName || !("toolCallId" in part))
343
+ continue;
344
+ const toolPart = part;
345
+ if (!pending.has(toolPart.toolCallId))
346
+ continue;
347
+ if (toolPart.state === "approval-responded" || toolPart.state === "output-denied") {
348
+ const approved = toolPart.approval?.approved === true;
349
+ approvals.set(toolPart.toolCallId, {
350
+ toolCallId: toolPart.toolCallId,
351
+ decision: approved ? "approve" : "deny",
352
+ denyMessage: approved
353
+ ? undefined
354
+ : (toolPart.approval?.reason ?? "Tool call denied by user"),
355
+ });
356
+ }
357
+ }
358
+ }
359
+ return [...approvals.values()];
360
+ }
361
+ export async function* toAISDKUIMessageChunks(events, options) {
362
+ const textId = options?.textId ?? "stratus-text";
363
+ const toolInputs = new Map();
364
+ let startedText = false;
365
+ let endedText = false;
366
+ if (options?.sendStart !== false) {
367
+ yield {
368
+ type: "start",
369
+ messageId: options?.messageId,
370
+ messageMetadata: options?.messageMetadata,
371
+ };
372
+ }
373
+ for await (const event of events) {
374
+ switch (event.type) {
375
+ case "content_delta":
376
+ if (!startedText) {
377
+ startedText = true;
378
+ yield { type: "text-start", id: textId };
379
+ }
380
+ yield { type: "text-delta", id: textId, delta: event.content };
381
+ break;
382
+ case "tool_call_start":
383
+ toolInputs.set(event.toolCall.id, {
384
+ toolName: event.toolCall.name,
385
+ text: "",
386
+ available: false,
387
+ });
388
+ yield {
389
+ type: "tool-input-start",
390
+ toolCallId: event.toolCall.id,
391
+ toolName: event.toolCall.name,
392
+ };
393
+ break;
394
+ case "tool_call_delta": {
395
+ const input = toolInputs.get(event.toolCallId);
396
+ if (input)
397
+ input.text += event.arguments;
398
+ yield {
399
+ type: "tool-input-delta",
400
+ toolCallId: event.toolCallId,
401
+ inputTextDelta: event.arguments,
402
+ };
403
+ break;
404
+ }
405
+ case "tool_call_done": {
406
+ const input = toolInputs.get(event.toolCallId);
407
+ if (input && !input.available) {
408
+ input.available = true;
409
+ yield {
410
+ type: "tool-input-available",
411
+ toolCallId: event.toolCallId,
412
+ toolName: input.toolName,
413
+ input: parseJsonish(input.text || "{}"),
414
+ };
415
+ }
416
+ break;
417
+ }
418
+ case "done":
419
+ if (startedText && !endedText) {
420
+ endedText = true;
421
+ yield { type: "text-end", id: textId };
422
+ }
423
+ for (const toolCall of event.response.toolCalls) {
424
+ if (toolInputs.has(toolCall.id))
425
+ continue;
426
+ yield {
427
+ type: "tool-input-available",
428
+ toolCallId: toolCall.id,
429
+ toolName: toolCall.function.name,
430
+ input: parseJsonish(toolCall.function.arguments),
431
+ };
432
+ }
433
+ if (options?.sendFinish !== false) {
434
+ yield {
435
+ type: "finish",
436
+ finishReason: finishReasonFromEvent(event),
437
+ messageMetadata: options?.messageMetadata,
438
+ };
439
+ }
440
+ break;
441
+ default:
442
+ yield { type: "data-stratus-event", data: event };
443
+ }
444
+ }
445
+ }
446
+ async function* appendApprovalRequests(events, result, options) {
447
+ yield* toAISDKUIMessageChunks(events, { ...options, sendFinish: false });
448
+ const finalResult = await result;
449
+ if (finalResult.interrupted) {
450
+ yield* toAISDKToolApprovalRequests(finalResult);
451
+ if (options?.sendFinish !== false) {
452
+ yield {
453
+ type: "finish",
454
+ finishReason: "tool-calls",
455
+ messageMetadata: options?.messageMetadata,
456
+ };
457
+ }
458
+ return;
459
+ }
460
+ if (options?.sendFinish !== false) {
461
+ yield {
462
+ type: "finish",
463
+ finishReason: mapFinishReason(finalResult.finishReason),
464
+ messageMetadata: options?.messageMetadata,
465
+ };
466
+ }
467
+ }
468
+ export function toAISDKUIMessageStream(events, options) {
469
+ const chunks = toAISDKUIMessageChunks(events, options);
470
+ return new ReadableStream({
471
+ async pull(controller) {
472
+ const next = await chunks.next();
473
+ if (next.done) {
474
+ controller.close();
475
+ return;
476
+ }
477
+ controller.enqueue(next.value);
478
+ },
479
+ async cancel() {
480
+ await chunks.return?.(undefined);
481
+ },
482
+ });
483
+ }
484
+ function asyncIterableToReadableStream(iterable) {
485
+ const iterator = iterable[Symbol.asyncIterator]();
486
+ return new ReadableStream({
487
+ async pull(controller) {
488
+ const next = await iterator.next();
489
+ if (next.done) {
490
+ controller.close();
491
+ return;
492
+ }
493
+ controller.enqueue(next.value);
494
+ },
495
+ async cancel() {
496
+ await iterator.return?.();
497
+ },
498
+ });
499
+ }
500
+ function jsonToSseStream(stream) {
501
+ return stream.pipeThrough(new TransformStream({
502
+ transform(chunk, controller) {
503
+ controller.enqueue(`data: ${JSON.stringify(chunk)}\n\n`);
504
+ },
505
+ }));
506
+ }
507
+ export function createAISDKUIMessageStreamResponse(options) {
508
+ let sseStream = jsonToSseStream(options.stream);
509
+ if (options.consumeSseStream) {
510
+ const [primary, secondary] = sseStream.tee();
511
+ sseStream = primary;
512
+ options.consumeSseStream({ stream: secondary });
513
+ }
514
+ const headers = new Headers(options.headers);
515
+ headers.set("content-type", "text/event-stream; charset=utf-8");
516
+ headers.set("x-vercel-ai-ui-message-stream", "v1");
517
+ return new Response(sseStream.pipeThrough(new TextEncoderStream()), {
518
+ status: options.status,
519
+ statusText: options.statusText,
520
+ headers,
521
+ });
522
+ }
523
+ export function createStratusChatResponse(options) {
524
+ const input = fromAISDKMessages(options.messages, {
525
+ convertDataPart: options.convertDataPart,
526
+ });
527
+ const streamed = stream(options.agent, input, options.runOptions);
528
+ const uiStream = asyncIterableToReadableStream(appendApprovalRequests(streamed.stream, streamed.result, {
529
+ messageId: options.messageId,
530
+ messageMetadata: options.messageMetadata,
531
+ }));
532
+ return createAISDKUIMessageStreamResponse({ ...options, stream: uiStream });
533
+ }
534
+ export function resumeStratusChatResponse(options) {
535
+ const approvals = approvalsFromAISDKMessages(options.messages, options.interrupted.pendingToolCalls);
536
+ const result = resumeRun(options.interrupted, approvals, options.runOptions);
537
+ const uiStream = asyncIterableToReadableStream((async function* () {
538
+ yield {
539
+ type: "start",
540
+ messageId: options.messageId,
541
+ messageMetadata: options.messageMetadata,
542
+ };
543
+ try {
544
+ const resumed = await result;
545
+ if (resumed.interrupted) {
546
+ yield* toAISDKToolApprovalRequests(resumed);
547
+ yield {
548
+ type: "finish",
549
+ finishReason: "tool-calls",
550
+ messageMetadata: options.messageMetadata,
551
+ };
552
+ return;
553
+ }
554
+ const message = toAISDKUIMessage(resumed, {
555
+ id: options.messageId,
556
+ metadata: options.messageMetadata,
557
+ });
558
+ const textPart = message.parts.find(isTextUIPart);
559
+ if (textPart) {
560
+ const textId = "stratus-text";
561
+ yield { type: "text-start", id: textId };
562
+ yield { type: "text-delta", id: textId, delta: textPart.text };
563
+ yield { type: "text-end", id: textId };
564
+ }
565
+ yield {
566
+ type: "finish",
567
+ finishReason: mapFinishReason(resumed.finishReason),
568
+ messageMetadata: options.messageMetadata,
569
+ };
570
+ }
571
+ catch (error) {
572
+ yield {
573
+ type: "error",
574
+ errorText: error instanceof Error ? error.message : String(error),
575
+ };
576
+ }
577
+ })());
578
+ return createAISDKUIMessageStreamResponse({ ...options, stream: uiStream });
579
+ }
580
+ export function toAISDKToolSet(tools, context) {
581
+ return Object.fromEntries(tools.map((tool) => [
582
+ tool.name,
583
+ {
584
+ description: tool.description,
585
+ inputSchema: tool.parameters,
586
+ execute: (input, options) => tool.execute(context, input, options),
587
+ },
588
+ ]));
589
+ }
590
+ function mapFinishReason(reason) {
591
+ switch (reason) {
592
+ case "stop":
593
+ return "stop";
594
+ case "length":
595
+ return "length";
596
+ case "content_filter":
597
+ return "content-filter";
598
+ case "tool_calls":
599
+ return "tool-calls";
600
+ default:
601
+ return "unknown";
602
+ }
603
+ }
604
+ function mapUsage(response) {
605
+ return {
606
+ inputTokens: response.usage?.promptTokens ?? 0,
607
+ outputTokens: response.usage?.completionTokens ?? 0,
608
+ totalTokens: response.usage?.totalTokens ?? 0,
609
+ };
610
+ }
611
+ function requestFromAISDKCall(options) {
612
+ const messages = fromAISDKMessages((options.messages ?? options.prompt ?? []));
613
+ const reasoningEffort = typeof options.reasoningEffort === "string"
614
+ ? options.reasoningEffort
615
+ : undefined;
616
+ return {
617
+ messages,
618
+ tools: options.tools?.map((tool) => ({
619
+ type: "function",
620
+ function: {
621
+ name: tool.name,
622
+ description: tool.description ?? tool.name,
623
+ parameters: tool.inputSchema ?? tool.parameters ?? { type: "object", properties: {} },
624
+ },
625
+ })),
626
+ modelSettings: {
627
+ temperature: typeof options.temperature === "number" ? options.temperature : undefined,
628
+ topP: typeof options.topP === "number" ? options.topP : undefined,
629
+ maxTokens: typeof options.maxOutputTokens === "number" ? options.maxOutputTokens : undefined,
630
+ reasoningEffort,
631
+ },
632
+ };
633
+ }
634
+ export function toAISDKLanguageModel(model, options) {
635
+ return {
636
+ specificationVersion: "v2",
637
+ provider: options?.provider ?? "stratus",
638
+ modelId: options?.modelId ?? "stratus-model",
639
+ supportedUrls: {},
640
+ async doGenerate(callOptions) {
641
+ const response = await model.getResponse(requestFromAISDKCall(callOptions), {
642
+ signal: callOptions.abortSignal,
643
+ });
644
+ return {
645
+ content: [
646
+ ...(response.content ? [{ type: "text", text: response.content }] : []),
647
+ ...response.toolCalls.map((toolCall) => ({
648
+ type: "tool-call",
649
+ toolCallId: toolCall.id,
650
+ toolName: toolCall.function.name,
651
+ input: parseJsonish(toolCall.function.arguments),
652
+ })),
653
+ ],
654
+ finishReason: mapFinishReason(response.finishReason),
655
+ usage: mapUsage(response),
656
+ response: { id: response.responseId },
657
+ };
658
+ },
659
+ async doStream(callOptions) {
660
+ const request = requestFromAISDKCall(callOptions);
661
+ const events = model.getStreamedResponse(request, { signal: callOptions.abortSignal });
662
+ return {
663
+ stream: asyncIterableToReadableStream((async function* () {
664
+ for await (const event of events) {
665
+ if (event.type === "content_delta") {
666
+ yield { type: "text-delta", id: "stratus-text", delta: event.content };
667
+ }
668
+ else if (event.type === "done") {
669
+ for (const toolCall of event.response.toolCalls) {
670
+ yield {
671
+ type: "tool-call",
672
+ toolCallId: toolCall.id,
673
+ toolName: toolCall.function.name,
674
+ input: parseJsonish(toolCall.function.arguments),
675
+ };
676
+ }
677
+ yield {
678
+ type: "finish",
679
+ finishReason: mapFinishReason(event.response.finishReason),
680
+ usage: mapUsage(event.response),
681
+ };
682
+ }
683
+ }
684
+ })()),
685
+ };
686
+ },
687
+ };
688
+ }
689
+ export async function* toOpenAIAgentsStyleStreamEvents(events) {
690
+ const toolInputs = new Map();
691
+ for await (const event of events) {
692
+ yield { type: "raw_model_stream_event", data: event, source: "stratus" };
693
+ switch (event.type) {
694
+ case "content_delta":
695
+ yield {
696
+ type: "run_item_stream_event",
697
+ name: "message_output_created",
698
+ item: { content: event.content },
699
+ };
700
+ break;
701
+ case "tool_call_start":
702
+ toolInputs.set(event.toolCall.id, { toolName: event.toolCall.name, text: "" });
703
+ yield {
704
+ type: "run_item_stream_event",
705
+ name: "tool_called",
706
+ item: { toolCallId: event.toolCall.id, toolName: event.toolCall.name },
707
+ };
708
+ break;
709
+ case "tool_call_delta": {
710
+ const input = toolInputs.get(event.toolCallId);
711
+ if (input)
712
+ input.text += event.arguments;
713
+ break;
714
+ }
715
+ case "tool_call_done": {
716
+ const input = toolInputs.get(event.toolCallId);
717
+ yield {
718
+ type: "run_item_stream_event",
719
+ name: "tool_output",
720
+ item: {
721
+ toolCallId: event.toolCallId,
722
+ toolName: input?.toolName,
723
+ input: input ? parseJsonish(input.text || "{}") : undefined,
724
+ },
725
+ };
726
+ break;
727
+ }
728
+ case "subagent_start":
729
+ yield { type: "agent_updated_stream_event", agent: { name: event.agentName } };
730
+ break;
731
+ case "subagent_end":
732
+ yield {
733
+ type: "run_item_stream_event",
734
+ name: "handoff_occurred",
735
+ item: { agentName: event.agentName, result: event.result },
736
+ };
737
+ break;
738
+ }
739
+ }
740
+ }
741
+ //# sourceMappingURL=index.js.map