@osdk/aip-core 0.2.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 (131) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +211 -0
  3. package/ai-sdk.d.ts +17 -0
  4. package/build/browser/ai-sdk/convert-prompt.js +136 -0
  5. package/build/browser/ai-sdk/convert-prompt.js.map +1 -0
  6. package/build/browser/ai-sdk/foundry-chat-language-model.js +386 -0
  7. package/build/browser/ai-sdk/foundry-chat-language-model.js.map +1 -0
  8. package/build/browser/ai-sdk/map-finish-reason.js +42 -0
  9. package/build/browser/ai-sdk/map-finish-reason.js.map +1 -0
  10. package/build/browser/ai-sdk/provider.js +62 -0
  11. package/build/browser/ai-sdk/provider.js.map +1 -0
  12. package/build/browser/ai-sdk/types.js +2 -0
  13. package/build/browser/ai-sdk/types.js.map +1 -0
  14. package/build/browser/generateText.js +76 -0
  15. package/build/browser/generateText.js.map +1 -0
  16. package/build/browser/index.js +23 -0
  17. package/build/browser/index.js.map +1 -0
  18. package/build/browser/internal/__test__/mockPlatformClient.js +36 -0
  19. package/build/browser/internal/__test__/mockPlatformClient.js.map +1 -0
  20. package/build/browser/internal/ids.js +23 -0
  21. package/build/browser/internal/ids.js.map +1 -0
  22. package/build/browser/internal/openAi.js +293 -0
  23. package/build/browser/internal/openAi.js.map +1 -0
  24. package/build/browser/internal/options.js +58 -0
  25. package/build/browser/internal/options.js.map +1 -0
  26. package/build/browser/internal/runStep.js +107 -0
  27. package/build/browser/internal/runStep.js.map +1 -0
  28. package/build/browser/internal/streamStep.js +223 -0
  29. package/build/browser/internal/streamStep.js.map +1 -0
  30. package/build/browser/internal/uiMessageBridge.js +55 -0
  31. package/build/browser/internal/uiMessageBridge.js.map +1 -0
  32. package/build/browser/lmsChatTransport.js +185 -0
  33. package/build/browser/lmsChatTransport.js.map +1 -0
  34. package/build/browser/model.js +74 -0
  35. package/build/browser/model.js.map +1 -0
  36. package/build/browser/public/ai-sdk.js +18 -0
  37. package/build/browser/public/ai-sdk.js.map +1 -0
  38. package/build/browser/streamText.js +210 -0
  39. package/build/browser/streamText.js.map +1 -0
  40. package/build/browser/types.js +2 -0
  41. package/build/browser/types.js.map +1 -0
  42. package/build/browser/uiMessage.js +34 -0
  43. package/build/browser/uiMessage.js.map +1 -0
  44. package/build/cjs/index.cjs +1012 -0
  45. package/build/cjs/index.cjs.map +1 -0
  46. package/build/cjs/index.d.cts +467 -0
  47. package/build/cjs/model-B5uS56VB.d.cts +45 -0
  48. package/build/cjs/public/ai-sdk.cjs +534 -0
  49. package/build/cjs/public/ai-sdk.cjs.map +1 -0
  50. package/build/cjs/public/ai-sdk.d.cts +49 -0
  51. package/build/esm/ai-sdk/convert-prompt.js +136 -0
  52. package/build/esm/ai-sdk/convert-prompt.js.map +1 -0
  53. package/build/esm/ai-sdk/foundry-chat-language-model.js +386 -0
  54. package/build/esm/ai-sdk/foundry-chat-language-model.js.map +1 -0
  55. package/build/esm/ai-sdk/map-finish-reason.js +42 -0
  56. package/build/esm/ai-sdk/map-finish-reason.js.map +1 -0
  57. package/build/esm/ai-sdk/provider.js +62 -0
  58. package/build/esm/ai-sdk/provider.js.map +1 -0
  59. package/build/esm/ai-sdk/types.js +2 -0
  60. package/build/esm/ai-sdk/types.js.map +1 -0
  61. package/build/esm/generateText.js +76 -0
  62. package/build/esm/generateText.js.map +1 -0
  63. package/build/esm/index.js +23 -0
  64. package/build/esm/index.js.map +1 -0
  65. package/build/esm/internal/__test__/mockPlatformClient.js +36 -0
  66. package/build/esm/internal/__test__/mockPlatformClient.js.map +1 -0
  67. package/build/esm/internal/ids.js +23 -0
  68. package/build/esm/internal/ids.js.map +1 -0
  69. package/build/esm/internal/openAi.js +293 -0
  70. package/build/esm/internal/openAi.js.map +1 -0
  71. package/build/esm/internal/options.js +58 -0
  72. package/build/esm/internal/options.js.map +1 -0
  73. package/build/esm/internal/runStep.js +107 -0
  74. package/build/esm/internal/runStep.js.map +1 -0
  75. package/build/esm/internal/streamStep.js +223 -0
  76. package/build/esm/internal/streamStep.js.map +1 -0
  77. package/build/esm/internal/uiMessageBridge.js +55 -0
  78. package/build/esm/internal/uiMessageBridge.js.map +1 -0
  79. package/build/esm/lmsChatTransport.js +185 -0
  80. package/build/esm/lmsChatTransport.js.map +1 -0
  81. package/build/esm/model.js +74 -0
  82. package/build/esm/model.js.map +1 -0
  83. package/build/esm/public/ai-sdk.js +18 -0
  84. package/build/esm/public/ai-sdk.js.map +1 -0
  85. package/build/esm/streamText.js +210 -0
  86. package/build/esm/streamText.js.map +1 -0
  87. package/build/esm/types.js +2 -0
  88. package/build/esm/types.js.map +1 -0
  89. package/build/esm/uiMessage.js +34 -0
  90. package/build/esm/uiMessage.js.map +1 -0
  91. package/build/types/ai-sdk/convert-prompt.d.ts +19 -0
  92. package/build/types/ai-sdk/convert-prompt.d.ts.map +1 -0
  93. package/build/types/ai-sdk/foundry-chat-language-model.d.ts +20 -0
  94. package/build/types/ai-sdk/foundry-chat-language-model.d.ts.map +1 -0
  95. package/build/types/ai-sdk/map-finish-reason.d.ts +2 -0
  96. package/build/types/ai-sdk/map-finish-reason.d.ts.map +1 -0
  97. package/build/types/ai-sdk/provider.d.ts +46 -0
  98. package/build/types/ai-sdk/provider.d.ts.map +1 -0
  99. package/build/types/ai-sdk/types.d.ts +1 -0
  100. package/build/types/ai-sdk/types.d.ts.map +1 -0
  101. package/build/types/generateText.d.ts +56 -0
  102. package/build/types/generateText.d.ts.map +1 -0
  103. package/build/types/index.d.ts +12 -0
  104. package/build/types/index.d.ts.map +1 -0
  105. package/build/types/internal/__test__/mockPlatformClient.d.ts +13 -0
  106. package/build/types/internal/__test__/mockPlatformClient.d.ts.map +1 -0
  107. package/build/types/internal/ids.d.ts +1 -0
  108. package/build/types/internal/ids.d.ts.map +1 -0
  109. package/build/types/internal/openAi.d.ts +107 -0
  110. package/build/types/internal/openAi.d.ts.map +1 -0
  111. package/build/types/internal/options.d.ts +4 -0
  112. package/build/types/internal/options.d.ts.map +1 -0
  113. package/build/types/internal/runStep.d.ts +29 -0
  114. package/build/types/internal/runStep.d.ts.map +1 -0
  115. package/build/types/internal/streamStep.d.ts +52 -0
  116. package/build/types/internal/streamStep.d.ts.map +1 -0
  117. package/build/types/internal/uiMessageBridge.d.ts +15 -0
  118. package/build/types/internal/uiMessageBridge.d.ts.map +1 -0
  119. package/build/types/lmsChatTransport.d.ts +35 -0
  120. package/build/types/lmsChatTransport.d.ts.map +1 -0
  121. package/build/types/model.d.ts +42 -0
  122. package/build/types/model.d.ts.map +1 -0
  123. package/build/types/public/ai-sdk.d.ts +2 -0
  124. package/build/types/public/ai-sdk.d.ts.map +1 -0
  125. package/build/types/streamText.d.ts +82 -0
  126. package/build/types/streamText.d.ts.map +1 -0
  127. package/build/types/types.d.ts +189 -0
  128. package/build/types/types.d.ts.map +1 -0
  129. package/build/types/uiMessage.d.ts +85 -0
  130. package/build/types/uiMessage.d.ts.map +1 -0
  131. package/package.json +87 -0
@@ -0,0 +1,1012 @@
1
+ 'use strict';
2
+
3
+ var languageModels = require('@osdk/language-models');
4
+
5
+ // src/internal/options.ts
6
+ function resolveMessages(callerLabel, system, prompt, messages) {
7
+ if (prompt != null && messages != null) {
8
+ throw new Error(`${callerLabel}: cannot specify both \`prompt\` and \`messages\`: choose one.`);
9
+ }
10
+ const sys = resolveSystem(system);
11
+ const body = resolveBody(prompt, messages);
12
+ if (sys.length === 0 && body.length === 0) {
13
+ throw new Error(`${callerLabel}: must provide at least one of \`system\`, \`prompt\`, or \`messages\`.`);
14
+ }
15
+ return [...sys, ...body];
16
+ }
17
+ function resolveSystem(system) {
18
+ if (system == null) {
19
+ return [];
20
+ }
21
+ if (typeof system === "string") {
22
+ return system === "" ? [] : [{
23
+ role: "system",
24
+ content: system
25
+ }];
26
+ }
27
+ if (Array.isArray(system)) {
28
+ return system;
29
+ }
30
+ return [system];
31
+ }
32
+ function resolveBody(prompt, messages) {
33
+ if (messages != null) {
34
+ return messages;
35
+ }
36
+ if (prompt == null) {
37
+ return [];
38
+ }
39
+ if (typeof prompt === "string") {
40
+ return [{
41
+ role: "user",
42
+ content: prompt
43
+ }];
44
+ }
45
+ return prompt;
46
+ }
47
+
48
+ // src/model.ts
49
+ var internals = /* @__PURE__ */ new WeakMap();
50
+ function foundryModel(options) {
51
+ const identifier = typeof options.model === "string" ? {
52
+ type: "lmsModel",
53
+ apiName: options.model
54
+ } : options.model;
55
+ const id = identifier.type === "lmsModel" ? identifier.apiName : identifier.registeredModelRid;
56
+ const handle = Object.freeze({
57
+ modelId: `foundry/${id}`,
58
+ provider: "foundry-lms"
59
+ });
60
+ internals.set(handle, {
61
+ client: options.client,
62
+ identifier
63
+ });
64
+ return handle;
65
+ }
66
+ function _getFoundryInternal(model) {
67
+ const handle = internals.get(model);
68
+ if (handle == null) {
69
+ throw new Error(`LanguageModel(modelId=${model.modelId}, provider=${model.provider}) was not constructed via foundryModel(). Only foundry-lms models are supported in v0.`);
70
+ }
71
+ return handle;
72
+ }
73
+ function getModelApiName(identifier) {
74
+ return identifier.type === "lmsModel" ? identifier.apiName : identifier.registeredModelRid;
75
+ }
76
+ function mapUsage(raw) {
77
+ return {
78
+ inputTokens: raw.prompt_tokens,
79
+ outputTokens: raw.completion_tokens,
80
+ totalTokens: raw.total_tokens,
81
+ reasoningTokens: raw.completion_tokens_details?.reasoning_tokens,
82
+ cachedInputTokens: raw.prompt_tokens_details?.cached_tokens
83
+ };
84
+ }
85
+ var EMPTY_USAGE = {
86
+ inputTokens: void 0,
87
+ outputTokens: void 0,
88
+ totalTokens: void 0
89
+ };
90
+ function mapFinishReason(reason) {
91
+ switch (reason) {
92
+ case "stop":
93
+ return "stop";
94
+ case "length":
95
+ return "length";
96
+ case "tool_calls":
97
+ case "function_call":
98
+ return "tool-calls";
99
+ case "content_filter":
100
+ return "content-filter";
101
+ default:
102
+ return "other";
103
+ }
104
+ }
105
+ function convertMessage(m, warnings) {
106
+ switch (m.role) {
107
+ case "system":
108
+ return [{
109
+ role: "system",
110
+ content: m.content
111
+ }];
112
+ case "user": {
113
+ if (typeof m.content === "string") {
114
+ return [{
115
+ role: "user",
116
+ content: m.content
117
+ }];
118
+ }
119
+ const parts = [];
120
+ for (const p of m.content) {
121
+ if (p.type === "text") {
122
+ parts.push({
123
+ type: "text",
124
+ text: p.text
125
+ });
126
+ } else {
127
+ warnings.push({
128
+ type: "other",
129
+ message: `Unsupported user content part "${p.type}": ignored in v0`
130
+ });
131
+ }
132
+ }
133
+ return [{
134
+ role: "user",
135
+ content: parts
136
+ }];
137
+ }
138
+ case "assistant": {
139
+ if (typeof m.content === "string") {
140
+ return [{
141
+ role: "assistant",
142
+ content: m.content
143
+ }];
144
+ }
145
+ let text = "";
146
+ const toolCalls = [];
147
+ for (const p of m.content) {
148
+ switch (p.type) {
149
+ case "text":
150
+ text += p.text;
151
+ break;
152
+ case "tool-call":
153
+ toolCalls.push({
154
+ id: p.toolCallId,
155
+ type: "function",
156
+ function: {
157
+ name: p.toolName,
158
+ arguments: JSON.stringify(p.input ?? {})
159
+ }
160
+ });
161
+ break;
162
+ case "reasoning":
163
+ case "file":
164
+ warnings.push({
165
+ type: "other",
166
+ message: `Unsupported assistant content part "${p.type}": ignored in v0`
167
+ });
168
+ break;
169
+ }
170
+ }
171
+ return [{
172
+ role: "assistant",
173
+ content: text.length > 0 ? text : null,
174
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
175
+ }];
176
+ }
177
+ case "tool":
178
+ return m.content.map((part) => ({
179
+ role: "tool",
180
+ content: stringifyToolResult(part, warnings),
181
+ tool_call_id: part.toolCallId
182
+ }));
183
+ }
184
+ }
185
+ function stringifyToolResult(part, warnings) {
186
+ switch (part.output.type) {
187
+ case "text":
188
+ case "error-text":
189
+ return part.output.value;
190
+ case "json":
191
+ case "error-json":
192
+ return JSON.stringify(part.output.value);
193
+ case "content":
194
+ return part.output.value.map((c) => {
195
+ if (c.type === "text") {
196
+ return c.text;
197
+ }
198
+ warnings.push({
199
+ type: "other",
200
+ message: `Unsupported tool result media: ignored in v0`
201
+ });
202
+ return "";
203
+ }).filter((s) => s.length > 0).join("\n");
204
+ }
205
+ }
206
+ function convertTools(tools, warnings) {
207
+ return Object.entries(tools).map(([name, tool]) => {
208
+ const parameters = isJsonSchemaLike(tool.inputSchema) ? tool.inputSchema : (warnings.push({
209
+ type: "unsupported-tool",
210
+ details: `Tool "${name}" inputSchema is not a JSON Schema; v0 only supports plain JSON Schema objects. Defaulting to {} parameters.`
211
+ }), {
212
+ type: "object",
213
+ properties: {}
214
+ });
215
+ return {
216
+ type: "function",
217
+ function: {
218
+ name,
219
+ description: tool.description,
220
+ parameters
221
+ }
222
+ };
223
+ });
224
+ }
225
+ function convertToolChoice(choice) {
226
+ if (choice == null) {
227
+ return void 0;
228
+ }
229
+ if (choice === "auto" || choice === "none" || choice === "required") {
230
+ return choice;
231
+ }
232
+ return {
233
+ type: "function",
234
+ function: {
235
+ name: choice.toolName
236
+ }
237
+ };
238
+ }
239
+ function isJsonSchemaLike(value) {
240
+ return typeof value === "object" && value != null && ("type" in value || "properties" in value || "$ref" in value || "oneOf" in value || "anyOf" in value || "allOf" in value);
241
+ }
242
+ function parseToolArguments(args, warnings) {
243
+ if (args === "") {
244
+ return {};
245
+ }
246
+ try {
247
+ return JSON.parse(args);
248
+ } catch {
249
+ warnings.push({
250
+ type: "other",
251
+ message: `Tool call arguments were not valid JSON; passing through as a raw string`
252
+ });
253
+ return args;
254
+ }
255
+ }
256
+ function buildOpenAiRequestBody(args, streaming) {
257
+ const common = {
258
+ model: args.apiName,
259
+ messages: args.messages.map((m) => convertMessage(m, args.warnings)).flat(),
260
+ max_tokens: args.maxOutputTokens,
261
+ temperature: args.temperature,
262
+ top_p: args.topP,
263
+ stop: args.stopSequences,
264
+ seed: args.seed,
265
+ presence_penalty: args.presencePenalty,
266
+ frequency_penalty: args.frequencyPenalty,
267
+ tools: args.tools != null ? convertTools(args.tools, args.warnings) : void 0,
268
+ tool_choice: convertToolChoice(args.toolChoice)
269
+ };
270
+ if (streaming) {
271
+ return {
272
+ ...common,
273
+ stream: true,
274
+ stream_options: {
275
+ include_usage: true
276
+ }
277
+ };
278
+ }
279
+ return {
280
+ ...common,
281
+ stream: false
282
+ };
283
+ }
284
+ function buildAssistantContent(text, toolCalls) {
285
+ if (toolCalls.length === 0) {
286
+ return text;
287
+ }
288
+ const parts = [];
289
+ if (text.length > 0) {
290
+ parts.push({
291
+ type: "text",
292
+ text
293
+ });
294
+ }
295
+ for (const tc of toolCalls) {
296
+ parts.push({
297
+ type: "tool-call",
298
+ toolCallId: tc.toolCallId,
299
+ toolName: tc.toolName,
300
+ input: tc.input
301
+ });
302
+ }
303
+ return parts;
304
+ }
305
+ function filterHeaders(input) {
306
+ const out = {};
307
+ for (const [k, v] of Object.entries(input)) {
308
+ if (v != null) {
309
+ out[k] = v;
310
+ }
311
+ }
312
+ return out;
313
+ }
314
+ async function safeReadText(res) {
315
+ try {
316
+ return await res.text();
317
+ } catch {
318
+ return void 0;
319
+ }
320
+ }
321
+ async function postChatCompletions(args) {
322
+ const handle = _getFoundryInternal(args.model);
323
+ const baseUrl = languageModels.getOpenAiBaseUrl(handle.client);
324
+ const url = new URL("chat/completions", `${baseUrl}/`).toString();
325
+ const res = await handle.client.fetch(url, {
326
+ method: "POST",
327
+ headers: filterHeaders({
328
+ "Content-Type": "application/json",
329
+ Accept: args.accept,
330
+ ...args.headers ?? {}
331
+ }),
332
+ body: JSON.stringify(args.body),
333
+ signal: args.abortSignal
334
+ });
335
+ if (!res.ok) {
336
+ const errBody = await safeReadText(res);
337
+ throw new Error(`LMS chat/completions request failed: ${res.status} ${res.statusText}` + (errBody ? `: ${errBody}` : ""));
338
+ }
339
+ return res;
340
+ }
341
+
342
+ // src/internal/runStep.ts
343
+ async function runStep(input) {
344
+ const apiName = getModelApiName(_getFoundryInternal(input.model).identifier);
345
+ const body = buildOpenAiRequestBody({
346
+ apiName,
347
+ ...input
348
+ }, false);
349
+ const res = await postChatCompletions({
350
+ model: input.model,
351
+ body,
352
+ accept: "application/json",
353
+ headers: input.headers,
354
+ abortSignal: input.abortSignal
355
+ });
356
+ const data = await res.json();
357
+ return parseResponse(data, body, input.warnings);
358
+ }
359
+ function parseResponse(res, request, warnings) {
360
+ const choice = res.choices[0];
361
+ if (choice == null) {
362
+ throw new Error("LMS chat/completions response did not include any choices");
363
+ }
364
+ const message = choice.message;
365
+ const text = message.content ?? "";
366
+ const reasoningText = message.reasoning ?? message.reasoning_content;
367
+ const toolCalls = (message.tool_calls ?? []).map((c) => ({
368
+ type: "tool-call",
369
+ toolCallId: c.id,
370
+ toolName: c.function.name,
371
+ input: parseToolArguments(c.function.arguments, warnings)
372
+ }));
373
+ const reasoning = reasoningText != null ? [{
374
+ type: "reasoning",
375
+ text: reasoningText
376
+ }] : [];
377
+ const content = [];
378
+ if (text.length > 0) {
379
+ content.push({
380
+ type: "text",
381
+ text
382
+ });
383
+ }
384
+ for (const r of reasoning) {
385
+ content.push({
386
+ type: "reasoning",
387
+ text: r.text
388
+ });
389
+ }
390
+ for (const tc of toolCalls) {
391
+ content.push({
392
+ ...tc,
393
+ type: "tool-call"
394
+ });
395
+ }
396
+ const usage = res.usage != null ? mapUsage(res.usage) : EMPTY_USAGE;
397
+ const finishReason = mapFinishReason(choice.finish_reason);
398
+ const responseMessages = [{
399
+ role: "assistant",
400
+ content: buildAssistantContent(text, toolCalls)
401
+ }];
402
+ return {
403
+ content,
404
+ text,
405
+ reasoning,
406
+ reasoningText,
407
+ toolCalls,
408
+ toolResults: [],
409
+ finishReason,
410
+ rawFinishReason: choice.finish_reason,
411
+ usage,
412
+ warnings: warnings.length > 0 ? warnings : void 0,
413
+ request: {
414
+ body: request
415
+ },
416
+ response: {
417
+ id: res.id,
418
+ modelId: res.model,
419
+ timestamp: new Date(res.created * 1e3),
420
+ body: res,
421
+ messages: responseMessages
422
+ },
423
+ providerMetadata: void 0
424
+ };
425
+ }
426
+
427
+ // src/generateText.ts
428
+ async function generateText(options) {
429
+ const messages = resolveMessages("generateText", options.system, options.prompt, options.messages);
430
+ const step = await runStep({
431
+ model: options.model,
432
+ messages,
433
+ tools: options.tools,
434
+ toolChoice: options.toolChoice,
435
+ maxOutputTokens: options.maxOutputTokens,
436
+ temperature: options.temperature,
437
+ topP: options.topP,
438
+ stopSequences: options.stopSequences,
439
+ seed: options.seed,
440
+ presencePenalty: options.presencePenalty,
441
+ frequencyPenalty: options.frequencyPenalty,
442
+ abortSignal: options.abortSignal,
443
+ headers: options.headers,
444
+ warnings: []
445
+ });
446
+ await options.onStepFinish?.(step);
447
+ const totalUsage = step.usage;
448
+ await options.onFinish?.({
449
+ ...step,
450
+ steps: [step],
451
+ totalUsage
452
+ });
453
+ return {
454
+ ...step,
455
+ totalUsage,
456
+ steps: [step]
457
+ };
458
+ }
459
+
460
+ // src/internal/streamStep.ts
461
+ async function streamStep(input) {
462
+ const apiName = getModelApiName(_getFoundryInternal(input.model).identifier);
463
+ const body = buildOpenAiRequestBody({
464
+ apiName,
465
+ ...input
466
+ }, true);
467
+ const res = await postChatCompletions({
468
+ model: input.model,
469
+ body,
470
+ accept: "text/event-stream",
471
+ headers: input.headers,
472
+ abortSignal: input.abortSignal
473
+ });
474
+ if (res.body == null) {
475
+ throw new Error("LMS chat/completions response had no streaming body");
476
+ }
477
+ return parseSseStream({
478
+ body: res.body,
479
+ onChunk: input.onChunk,
480
+ warnings: input.warnings,
481
+ request: {
482
+ body
483
+ }
484
+ });
485
+ }
486
+ var TEXT_PART_ID = "text-0";
487
+ var REASONING_PART_ID = "reasoning-0";
488
+ async function parseSseStream(args) {
489
+ const reader = args.body.pipeThrough(new TextDecoderStream()).getReader();
490
+ let buffer = "";
491
+ let textBuf = "";
492
+ let reasoningStarted = false;
493
+ let reasoningBuf = "";
494
+ let finishReason = "other";
495
+ let rawFinishReason;
496
+ let usage;
497
+ const toolCallAcc = /* @__PURE__ */ new Map();
498
+ let responseInitialized = false;
499
+ let responseId;
500
+ let responseModel;
501
+ let responseCreated;
502
+ try {
503
+ while (true) {
504
+ const {
505
+ value,
506
+ done
507
+ } = await reader.read();
508
+ if (done) {
509
+ break;
510
+ }
511
+ buffer += value.replace(/\r\n/g, "\n");
512
+ let frameEnd = buffer.indexOf("\n\n");
513
+ while (frameEnd !== -1) {
514
+ const frame = buffer.slice(0, frameEnd);
515
+ buffer = buffer.slice(frameEnd + 2);
516
+ for (const line of frame.split("\n")) {
517
+ if (!line.startsWith("data:")) {
518
+ continue;
519
+ }
520
+ const payload = line.slice(5).trim();
521
+ if (payload === "") {
522
+ continue;
523
+ }
524
+ if (payload === "[DONE]") {
525
+ continue;
526
+ }
527
+ let parsed;
528
+ try {
529
+ parsed = JSON.parse(payload);
530
+ } catch {
531
+ args.warnings.push({
532
+ type: "other",
533
+ message: `Skipped malformed SSE frame: ${payload.slice(0, 80)}`
534
+ });
535
+ continue;
536
+ }
537
+ if (isErrorFrame(parsed)) {
538
+ throw new Error(extractErrorMessage(parsed));
539
+ }
540
+ const chunk = parsed;
541
+ if (!responseInitialized) {
542
+ responseId = chunk.id;
543
+ responseModel = chunk.model;
544
+ responseCreated = chunk.created;
545
+ responseInitialized = true;
546
+ }
547
+ if (chunk.usage != null) {
548
+ usage = mapUsage(chunk.usage);
549
+ }
550
+ for (const choice of chunk.choices ?? []) {
551
+ const delta = choice.delta;
552
+ const contentDelta = delta.content;
553
+ if (typeof contentDelta === "string" && contentDelta.length > 0) {
554
+ textBuf += contentDelta;
555
+ await args.onChunk({
556
+ type: "text-delta",
557
+ id: TEXT_PART_ID,
558
+ delta: contentDelta
559
+ });
560
+ }
561
+ const reasoningDelta = delta.reasoning ?? delta.reasoning_content;
562
+ if (typeof reasoningDelta === "string" && reasoningDelta.length > 0) {
563
+ reasoningStarted = true;
564
+ reasoningBuf += reasoningDelta;
565
+ await args.onChunk({
566
+ type: "reasoning-delta",
567
+ id: REASONING_PART_ID,
568
+ delta: reasoningDelta
569
+ });
570
+ }
571
+ if (delta.tool_calls != null) {
572
+ for (const tc of delta.tool_calls) {
573
+ if (typeof tc.index !== "number") {
574
+ continue;
575
+ }
576
+ const acc = toolCallAcc.get(tc.index) ?? {
577
+ id: "",
578
+ name: "",
579
+ args: ""
580
+ };
581
+ if (tc.id != null) {
582
+ acc.id = tc.id;
583
+ }
584
+ if (tc.function?.name != null) {
585
+ acc.name = tc.function.name;
586
+ }
587
+ if (tc.function?.arguments != null) {
588
+ acc.args += tc.function.arguments;
589
+ }
590
+ toolCallAcc.set(tc.index, acc);
591
+ }
592
+ }
593
+ if (choice.finish_reason != null) {
594
+ rawFinishReason = choice.finish_reason;
595
+ finishReason = mapFinishReason(choice.finish_reason);
596
+ }
597
+ }
598
+ }
599
+ frameEnd = buffer.indexOf("\n\n");
600
+ }
601
+ }
602
+ } finally {
603
+ reader.releaseLock();
604
+ }
605
+ const finalUsage = usage ?? EMPTY_USAGE;
606
+ const toolCalls = Array.from(toolCallAcc.entries()).map(([index, acc]) => ({
607
+ type: "tool-call",
608
+ toolCallId: acc.id !== "" ? acc.id : `tool_call_${index}`,
609
+ toolName: acc.name,
610
+ input: parseToolArguments(acc.args, args.warnings)
611
+ }));
612
+ for (const tc of toolCalls) {
613
+ await args.onChunk({
614
+ type: "tool-call",
615
+ toolCallId: tc.toolCallId,
616
+ toolName: tc.toolName,
617
+ input: tc.input
618
+ });
619
+ }
620
+ await args.onChunk({
621
+ type: "finish",
622
+ finishReason,
623
+ rawFinishReason,
624
+ usage: finalUsage
625
+ });
626
+ const response = {
627
+ id: responseId,
628
+ modelId: responseModel,
629
+ timestamp: responseCreated != null ? new Date(responseCreated * 1e3) : void 0,
630
+ messages: [{
631
+ role: "assistant",
632
+ content: buildAssistantContent(textBuf, toolCalls)
633
+ }]
634
+ };
635
+ return {
636
+ text: textBuf,
637
+ reasoningText: reasoningStarted ? reasoningBuf : void 0,
638
+ toolCalls,
639
+ finishReason,
640
+ rawFinishReason,
641
+ usage: finalUsage,
642
+ request: args.request,
643
+ response
644
+ };
645
+ }
646
+ function isErrorFrame(payload) {
647
+ return typeof payload === "object" && payload != null && "error" in payload && payload.error != null;
648
+ }
649
+ function extractErrorMessage(payload) {
650
+ const err = payload.error;
651
+ if (typeof err === "string") {
652
+ return err;
653
+ }
654
+ if (typeof err === "object" && err != null) {
655
+ const message = err.message;
656
+ if (typeof message === "string") {
657
+ return message;
658
+ }
659
+ }
660
+ return "LMS chat/completions stream emitted an error frame";
661
+ }
662
+
663
+ // src/streamText.ts
664
+ function streamText(options) {
665
+ const warnings = [];
666
+ const messages = resolveMessages("streamText", options.system, options.prompt, options.messages);
667
+ const final = createDeferred();
668
+ const internalAbort = new AbortController();
669
+ const abortHandler = () => internalAbort.abort();
670
+ if (options.abortSignal != null) {
671
+ if (options.abortSignal.aborted) {
672
+ internalAbort.abort();
673
+ } else {
674
+ options.abortSignal.addEventListener("abort", abortHandler);
675
+ }
676
+ }
677
+ const detachAbortHandler = () => {
678
+ options.abortSignal?.removeEventListener("abort", abortHandler);
679
+ };
680
+ let streamController;
681
+ let streamClosed = false;
682
+ const run = async () => {
683
+ try {
684
+ const result = await streamStep({
685
+ model: options.model,
686
+ messages,
687
+ tools: options.tools,
688
+ toolChoice: options.toolChoice,
689
+ maxOutputTokens: options.maxOutputTokens,
690
+ temperature: options.temperature,
691
+ topP: options.topP,
692
+ stopSequences: options.stopSequences,
693
+ seed: options.seed,
694
+ presencePenalty: options.presencePenalty,
695
+ frequencyPenalty: options.frequencyPenalty,
696
+ abortSignal: internalAbort.signal,
697
+ headers: options.headers,
698
+ warnings,
699
+ onChunk: async (chunk) => {
700
+ if (!streamClosed) {
701
+ streamController?.enqueue(chunk);
702
+ }
703
+ if (options.onChunk != null) {
704
+ await options.onChunk(chunk);
705
+ }
706
+ }
707
+ });
708
+ streamController?.close();
709
+ streamClosed = true;
710
+ const finalWarnings = warnings.length > 0 ? warnings : void 0;
711
+ final.resolve({
712
+ text: result.text,
713
+ reasoningText: result.reasoningText,
714
+ usage: result.usage,
715
+ finishReason: result.finishReason,
716
+ toolCalls: result.toolCalls,
717
+ warnings: finalWarnings,
718
+ response: result.response,
719
+ request: result.request
720
+ });
721
+ if (options.onFinish != null) {
722
+ await options.onFinish({
723
+ finishReason: result.finishReason,
724
+ text: result.text,
725
+ reasoningText: result.reasoningText,
726
+ toolCalls: result.toolCalls,
727
+ usage: result.usage,
728
+ totalUsage: result.usage,
729
+ warnings: finalWarnings,
730
+ response: result.response,
731
+ request: result.request
732
+ });
733
+ }
734
+ } catch (err) {
735
+ const error = err instanceof Error ? err : new Error(String(err));
736
+ if (!streamClosed) {
737
+ streamController?.enqueue({
738
+ type: "error",
739
+ error
740
+ });
741
+ streamController?.error(error);
742
+ streamClosed = true;
743
+ }
744
+ final.reject(error);
745
+ if (options.onError != null) {
746
+ await options.onError(error);
747
+ }
748
+ } finally {
749
+ detachAbortHandler();
750
+ }
751
+ };
752
+ const sourceStream = new ReadableStream({
753
+ start(controller) {
754
+ streamController = controller;
755
+ void run();
756
+ },
757
+ cancel() {
758
+ internalAbort.abort();
759
+ detachAbortHandler();
760
+ }
761
+ });
762
+ const [fullStreamBranch, textStreamBranch] = sourceStream.tee();
763
+ const textStream = textStreamBranch.pipeThrough(new TransformStream({
764
+ transform(chunk, controller) {
765
+ if (chunk.type === "text-delta") {
766
+ controller.enqueue(chunk.delta);
767
+ }
768
+ }
769
+ }));
770
+ const warningsPromise = final.promise.then((s) => s.warnings, () => warnings.length > 0 ? warnings : void 0);
771
+ return {
772
+ fullStream: fullStreamBranch,
773
+ textStream,
774
+ text: silence(final.promise.then((s) => s.text)),
775
+ reasoningText: silence(final.promise.then((s) => s.reasoningText)),
776
+ usage: silence(final.promise.then((s) => s.usage)),
777
+ totalUsage: silence(final.promise.then((s) => s.usage)),
778
+ finishReason: silence(final.promise.then((s) => s.finishReason)),
779
+ toolCalls: silence(final.promise.then((s) => s.toolCalls)),
780
+ warnings: warningsPromise,
781
+ response: silence(final.promise.then((s) => s.response)),
782
+ request: silence(final.promise.then((s) => s.request))
783
+ };
784
+ }
785
+ function silence(p) {
786
+ p.catch(() => {
787
+ });
788
+ return p;
789
+ }
790
+ function createDeferred() {
791
+ let resolveFn = () => {
792
+ };
793
+ let rejectFn = () => {
794
+ };
795
+ const promise = new Promise((res, rej) => {
796
+ resolveFn = res;
797
+ rejectFn = rej;
798
+ });
799
+ promise.catch(() => {
800
+ });
801
+ return {
802
+ promise,
803
+ resolve: resolveFn,
804
+ reject: rejectFn
805
+ };
806
+ }
807
+
808
+ // src/uiMessage.ts
809
+ function getUIMessageText(message) {
810
+ let buf = "";
811
+ for (const p of message.parts) {
812
+ if (p.type === "text") {
813
+ buf += p.text;
814
+ }
815
+ }
816
+ return buf;
817
+ }
818
+
819
+ // src/internal/uiMessageBridge.ts
820
+ function uiMessagesToModelMessages(ui, system) {
821
+ const out = [];
822
+ const transportSystemSet = system != null && system.length > 0;
823
+ if (transportSystemSet) {
824
+ out.push({
825
+ role: "system",
826
+ content: system
827
+ });
828
+ }
829
+ for (const m of ui) {
830
+ const text = getUIMessageText(m);
831
+ if (text.length === 0) {
832
+ continue;
833
+ }
834
+ if (m.role === "system" && transportSystemSet) {
835
+ continue;
836
+ }
837
+ out.push({
838
+ role: m.role,
839
+ content: text
840
+ });
841
+ }
842
+ return out;
843
+ }
844
+
845
+ // src/lmsChatTransport.ts
846
+ var LmsChatTransport = class {
847
+ constructor(opts) {
848
+ this.opts = opts;
849
+ }
850
+ sendMessages = async (args) => {
851
+ const result = streamText({
852
+ model: this.opts.model,
853
+ // System prompt is folded into the model-message list by the bridge so
854
+ // it isn't double-prepended (transport.system + system messages from
855
+ // args.messages would both land otherwise).
856
+ messages: uiMessagesToModelMessages(args.messages, this.opts.system),
857
+ temperature: this.opts.temperature,
858
+ maxOutputTokens: this.opts.maxOutputTokens,
859
+ topP: this.opts.topP,
860
+ presencePenalty: this.opts.presencePenalty,
861
+ frequencyPenalty: this.opts.frequencyPenalty,
862
+ stopSequences: this.opts.stopSequences,
863
+ seed: this.opts.seed,
864
+ headers: mergeHeaders(this.opts.headers, args.headers),
865
+ abortSignal: args.abortSignal
866
+ });
867
+ const assistantId = args.messageId;
868
+ const textPartId = `${assistantId}-text-0`;
869
+ const reasoningPartId = `${assistantId}-reasoning-0`;
870
+ let textOpen = false;
871
+ let reasoningOpen = false;
872
+ let startEmitted = false;
873
+ return result.fullStream.pipeThrough(new TransformStream({
874
+ transform(chunk, controller) {
875
+ if (!startEmitted) {
876
+ startEmitted = true;
877
+ controller.enqueue({
878
+ type: "start",
879
+ messageId: assistantId
880
+ });
881
+ controller.enqueue({
882
+ type: "start-step"
883
+ });
884
+ }
885
+ const closeText = () => {
886
+ if (textOpen) {
887
+ textOpen = false;
888
+ controller.enqueue({
889
+ type: "text-end",
890
+ id: textPartId
891
+ });
892
+ }
893
+ };
894
+ const closeReasoning = () => {
895
+ if (reasoningOpen) {
896
+ reasoningOpen = false;
897
+ controller.enqueue({
898
+ type: "reasoning-end",
899
+ id: reasoningPartId
900
+ });
901
+ }
902
+ };
903
+ switch (chunk.type) {
904
+ case "text-delta": {
905
+ if (!textOpen) {
906
+ textOpen = true;
907
+ controller.enqueue({
908
+ type: "text-start",
909
+ id: textPartId
910
+ });
911
+ }
912
+ controller.enqueue({
913
+ type: "text-delta",
914
+ id: textPartId,
915
+ delta: chunk.delta
916
+ });
917
+ return;
918
+ }
919
+ case "reasoning-delta": {
920
+ if (!reasoningOpen) {
921
+ reasoningOpen = true;
922
+ controller.enqueue({
923
+ type: "reasoning-start",
924
+ id: reasoningPartId
925
+ });
926
+ }
927
+ controller.enqueue({
928
+ type: "reasoning-delta",
929
+ id: reasoningPartId,
930
+ delta: chunk.delta
931
+ });
932
+ return;
933
+ }
934
+ case "tool-call": {
935
+ controller.enqueue({
936
+ type: "tool-input-available",
937
+ toolCallId: chunk.toolCallId,
938
+ toolName: chunk.toolName,
939
+ input: chunk.input
940
+ });
941
+ return;
942
+ }
943
+ case "finish": {
944
+ closeText();
945
+ closeReasoning();
946
+ controller.enqueue({
947
+ type: "finish-step"
948
+ });
949
+ controller.enqueue({
950
+ type: "finish",
951
+ messageMetadata: {
952
+ finishReason: chunk.finishReason,
953
+ usage: chunk.usage
954
+ }
955
+ });
956
+ return;
957
+ }
958
+ case "error": {
959
+ closeText();
960
+ closeReasoning();
961
+ controller.enqueue({
962
+ type: "error",
963
+ errorText: chunk.error.message
964
+ });
965
+ return;
966
+ }
967
+ default: {
968
+ const unhandled = chunk;
969
+ controller.enqueue({
970
+ type: "error",
971
+ errorText: `Unhandled chunk type "${unhandled.type}"`
972
+ });
973
+ }
974
+ }
975
+ }
976
+ }));
977
+ };
978
+ reconnectToStream = async (_args) => {
979
+ return null;
980
+ };
981
+ };
982
+ function mergeHeaders(base, override) {
983
+ if (base == null && override == null) {
984
+ return void 0;
985
+ }
986
+ const out = {
987
+ ...base ?? {}
988
+ };
989
+ if (override != null) {
990
+ for (const [k, v] of Object.entries(override)) {
991
+ out[k] = v;
992
+ }
993
+ }
994
+ return out;
995
+ }
996
+
997
+ // src/internal/ids.ts
998
+ function generateMessageId() {
999
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1000
+ return crypto.randomUUID();
1001
+ }
1002
+ return `msg-${Math.random().toString(36).slice(2, 10)}-${Date.now()}`;
1003
+ }
1004
+
1005
+ exports.LmsChatTransport = LmsChatTransport;
1006
+ exports.foundryModel = foundryModel;
1007
+ exports.generateMessageId = generateMessageId;
1008
+ exports.generateText = generateText;
1009
+ exports.getUIMessageText = getUIMessageText;
1010
+ exports.streamText = streamText;
1011
+ //# sourceMappingURL=index.cjs.map
1012
+ //# sourceMappingURL=index.cjs.map