@mastra/openai 0.1.0-alpha.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/dist/index.js ADDED
@@ -0,0 +1,1074 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { ReadableStream, TransformStream } from 'stream/web';
3
+ import { Agent } from '@mastra/core/agent';
4
+ import { RequestContext } from '@mastra/core/request-context';
5
+ import { ChunkFrom, MastraModelOutput } from '@mastra/core/stream';
6
+ import { Agent as Agent$1, run } from '@openai/agents';
7
+ import { MessageList } from '@mastra/core/agent/message-list';
8
+ import { getOrCreateSpan, EntityType, SpanType, executeWithContext } from '@mastra/core/observability';
9
+
10
+ // src/index.ts
11
+ function createNoopModel({ modelId, provider }) {
12
+ return {
13
+ modelId,
14
+ provider,
15
+ specificationVersion: "v3",
16
+ supportedUrls: {},
17
+ doGenerate: async () => createNoopStreamResult(),
18
+ doStream: async () => createNoopStreamResult()
19
+ };
20
+ }
21
+ function createNoopStreamResult() {
22
+ return {
23
+ stream: new ReadableStream({
24
+ start: (controller) => controller.close()
25
+ })
26
+ };
27
+ }
28
+ function createCompletedMastraStream({
29
+ runId,
30
+ prompt,
31
+ text,
32
+ responseId,
33
+ modelId,
34
+ usage,
35
+ providerMetadata,
36
+ costContext
37
+ }) {
38
+ return new ReadableStream({
39
+ start(controller) {
40
+ const textId = randomUUID();
41
+ enqueueStartChunks(controller, {
42
+ runId,
43
+ prompt,
44
+ textId,
45
+ responseId,
46
+ modelId,
47
+ providerMetadata
48
+ });
49
+ if (text) {
50
+ enqueueTextDelta(controller, runId, textId, text);
51
+ }
52
+ enqueueFinishChunks(controller, {
53
+ runId,
54
+ prompt,
55
+ textId,
56
+ text,
57
+ responseId,
58
+ modelId,
59
+ usage,
60
+ providerMetadata,
61
+ costContext
62
+ });
63
+ controller.close();
64
+ }
65
+ });
66
+ }
67
+ function createMastraOutput({
68
+ messages,
69
+ runId,
70
+ modelId,
71
+ provider,
72
+ stream,
73
+ options
74
+ }) {
75
+ const messageList = new MessageList();
76
+ messageList.add(messages, "input");
77
+ messageList.add([{ role: "assistant", content: "" }], "response");
78
+ return new MastraModelOutput({
79
+ model: {
80
+ modelId,
81
+ provider,
82
+ version: "v3"
83
+ },
84
+ stream,
85
+ messageList,
86
+ messageId: randomUUID(),
87
+ options: {
88
+ ...options,
89
+ runId
90
+ }
91
+ });
92
+ }
93
+ function toFullOutput({
94
+ messages,
95
+ runId,
96
+ provider,
97
+ result,
98
+ options
99
+ }) {
100
+ const text = result.content.map((part) => part.text).join("");
101
+ const stream = createCompletedMastraStream({
102
+ runId,
103
+ prompt: promptToText(messages),
104
+ text,
105
+ responseId: result.response.id,
106
+ modelId: result.response.modelId,
107
+ usage: toLanguageModelUsage(result.usage),
108
+ providerMetadata: result.providerMetadata,
109
+ costContext: result.costContext
110
+ });
111
+ return createMastraOutput({
112
+ messages,
113
+ runId,
114
+ modelId: result.response.modelId,
115
+ provider,
116
+ stream,
117
+ options
118
+ }).getFullOutput();
119
+ }
120
+ function createSDKAgentTelemetry({
121
+ agentId,
122
+ agentName,
123
+ provider,
124
+ modelId,
125
+ messages,
126
+ prompt,
127
+ runId,
128
+ streaming,
129
+ method,
130
+ requestContext,
131
+ instructions,
132
+ maxSteps,
133
+ tracingOptions,
134
+ tracingContext,
135
+ onFinish,
136
+ onStepFinish,
137
+ mastra
138
+ }) {
139
+ const agentSpan = getOrCreateSpan({
140
+ type: SpanType.AGENT_RUN,
141
+ name: `agent run: '${agentId}'`,
142
+ entityType: EntityType.AGENT,
143
+ entityId: agentId,
144
+ entityName: agentName,
145
+ input: messages,
146
+ attributes: {
147
+ prompt,
148
+ instructions,
149
+ maxSteps
150
+ },
151
+ metadata: {
152
+ runId,
153
+ sdkAgent: true,
154
+ sdkProvider: provider,
155
+ sdkMethod: method
156
+ },
157
+ tracingOptions,
158
+ tracingContext,
159
+ requestContext,
160
+ mastra
161
+ });
162
+ const modelSpan = agentSpan?.createChildSpan({
163
+ type: SpanType.MODEL_GENERATION,
164
+ name: `llm: '${modelId}'`,
165
+ input: {
166
+ messages
167
+ },
168
+ attributes: {
169
+ model: modelId,
170
+ provider,
171
+ streaming
172
+ },
173
+ metadata: {
174
+ runId,
175
+ sdkAgent: true,
176
+ sdkProvider: provider,
177
+ sdkMethod: method
178
+ },
179
+ requestContext
180
+ });
181
+ const modelSpanTracker = getModelSpanTracker(modelSpan);
182
+ const toolSpans = /* @__PURE__ */ new Map();
183
+ let ended = false;
184
+ const startToolCall = ({ toolCallId, toolName, input }) => {
185
+ if (toolSpans.has(toolCallId)) {
186
+ return;
187
+ }
188
+ const parentSpan = agentSpan ?? modelSpan;
189
+ if (!parentSpan) {
190
+ return;
191
+ }
192
+ const mcp = parseMcpToolName(toolName);
193
+ const span = mcp ? parentSpan.createChildSpan({
194
+ type: SpanType.MCP_TOOL_CALL,
195
+ name: `mcp_tool: '${toolName}' on '${mcp.serverName}'`,
196
+ input,
197
+ entityType: EntityType.TOOL,
198
+ entityId: toolName,
199
+ entityName: toolName,
200
+ attributes: {
201
+ mcpServer: mcp.serverName
202
+ },
203
+ metadata: {
204
+ runId,
205
+ sdkAgent: true,
206
+ sdkProvider: provider,
207
+ sdkMethod: method,
208
+ toolCallId
209
+ },
210
+ requestContext
211
+ }) : parentSpan.createChildSpan({
212
+ type: SpanType.TOOL_CALL,
213
+ name: `tool: '${toolName}'`,
214
+ input,
215
+ entityType: EntityType.TOOL,
216
+ entityId: toolName,
217
+ entityName: toolName,
218
+ attributes: {
219
+ toolType: "tool"
220
+ },
221
+ metadata: {
222
+ runId,
223
+ sdkAgent: true,
224
+ sdkProvider: provider,
225
+ sdkMethod: method,
226
+ toolCallId
227
+ },
228
+ requestContext
229
+ });
230
+ toolSpans.set(toolCallId, span);
231
+ };
232
+ const endToolCall = ({ toolCallId, output, isError }) => {
233
+ const span = toolSpans.get(toolCallId);
234
+ if (!span) {
235
+ return;
236
+ }
237
+ toolSpans.delete(toolCallId);
238
+ if (isError) {
239
+ span.error({
240
+ error: output instanceof Error ? output : new Error(typeof output === "string" ? output : "SDK tool call failed"),
241
+ attributes: { success: false }
242
+ });
243
+ return;
244
+ }
245
+ span.end({
246
+ output,
247
+ attributes: { success: true }
248
+ });
249
+ };
250
+ const closeOpenToolSpans = (success, error) => {
251
+ for (const [toolCallId, span] of toolSpans) {
252
+ toolSpans.delete(toolCallId);
253
+ if (success) {
254
+ span.end({ attributes: { success: true } });
255
+ continue;
256
+ }
257
+ const normalized = error instanceof Error ? error : new Error(String(error ?? "SDK agent run failed"));
258
+ span.error({ error: normalized, attributes: { success: false } });
259
+ }
260
+ };
261
+ const endModel = ({
262
+ text,
263
+ usage,
264
+ providerMetadata,
265
+ finishReason = "stop",
266
+ responseId,
267
+ responseModel,
268
+ costContext
269
+ }) => {
270
+ if (modelSpanTracker) {
271
+ modelSpanTracker.endGeneration({
272
+ output: {
273
+ text
274
+ },
275
+ attributes: {
276
+ finishReason,
277
+ responseId,
278
+ responseModel,
279
+ costContext
280
+ },
281
+ usage,
282
+ providerMetadata
283
+ });
284
+ return;
285
+ }
286
+ modelSpan?.end({
287
+ output: {
288
+ text
289
+ },
290
+ attributes: {
291
+ finishReason,
292
+ responseId,
293
+ responseModel,
294
+ usage: usage ? toUsageStats(usage) : void 0,
295
+ costContext
296
+ }
297
+ });
298
+ };
299
+ const end = (result) => {
300
+ if (ended) {
301
+ return;
302
+ }
303
+ ended = true;
304
+ closeOpenToolSpans(true);
305
+ endModel(result);
306
+ agentSpan?.end({
307
+ output: {
308
+ text: result.text
309
+ }
310
+ });
311
+ };
312
+ const fail = (error) => {
313
+ if (ended) {
314
+ return;
315
+ }
316
+ ended = true;
317
+ const normalized = error instanceof Error ? error : new Error(String(error));
318
+ closeOpenToolSpans(false, normalized);
319
+ if (modelSpanTracker) {
320
+ modelSpanTracker.reportGenerationError({ error: normalized });
321
+ } else {
322
+ modelSpan?.error({ error: normalized });
323
+ }
324
+ agentSpan?.error({ error: normalized });
325
+ };
326
+ return {
327
+ execute: (fn) => executeWithContext({ span: modelSpan ?? agentSpan, fn }),
328
+ endGenerate(result) {
329
+ end({
330
+ text: result.content.map((part) => part.text).join(""),
331
+ usage: toLanguageModelUsage(result.usage),
332
+ providerMetadata: result.providerMetadata,
333
+ finishReason: result.finishReason.unified,
334
+ responseId: result.response.id,
335
+ responseModel: result.response.modelId,
336
+ costContext: result.costContext
337
+ });
338
+ },
339
+ fail,
340
+ startToolCall,
341
+ endToolCall,
342
+ wrapStream(stream) {
343
+ const trackedStream = modelSpanTracker?.wrapStream(stream) ?? stream;
344
+ return wrapStreamForAgentSpan(trackedStream, {
345
+ end,
346
+ fail
347
+ });
348
+ },
349
+ outputOptions() {
350
+ return {
351
+ onFinish,
352
+ onStepFinish,
353
+ requestContext,
354
+ tracingContext: agentSpan ? { currentSpan: agentSpan } : tracingContext
355
+ };
356
+ }
357
+ };
358
+ }
359
+ function parseMcpToolName(toolName) {
360
+ const match = /^mcp__([^_].*?)__(.+)$/.exec(toolName);
361
+ if (!match?.[1] || !match[2]) {
362
+ return void 0;
363
+ }
364
+ return {
365
+ serverName: match[1],
366
+ toolName: match[2]
367
+ };
368
+ }
369
+ function getModelSpanTracker(modelSpan) {
370
+ if (!modelSpan || !("createTracker" in modelSpan)) {
371
+ return void 0;
372
+ }
373
+ return modelSpan.createTracker();
374
+ }
375
+ function wrapStreamForAgentSpan(stream, telemetry) {
376
+ let text = "";
377
+ return stream.pipeThrough(
378
+ new TransformStream({
379
+ transform(chunk, controller) {
380
+ if (chunk.type === "text-delta") {
381
+ text += chunk.payload.text;
382
+ }
383
+ if (chunk.type === "finish") {
384
+ telemetry.end({
385
+ text,
386
+ usage: chunk.payload.output.usage,
387
+ providerMetadata: chunk.payload.providerMetadata,
388
+ finishReason: chunk.payload.stepResult.reason,
389
+ responseId: chunk.payload.response?.id,
390
+ responseModel: chunk.payload.response?.modelId,
391
+ costContext: getCostContext(chunk.payload.metadata?.costContext)
392
+ });
393
+ }
394
+ if (chunk.type === "error") {
395
+ telemetry.fail(chunk.payload.error);
396
+ }
397
+ controller.enqueue(chunk);
398
+ },
399
+ flush() {
400
+ telemetry.end({ text });
401
+ }
402
+ })
403
+ );
404
+ }
405
+ function toUsageStats(usage) {
406
+ return {
407
+ inputTokens: usage.inputTokens,
408
+ outputTokens: usage.outputTokens,
409
+ inputDetails: {
410
+ cacheRead: usage.cachedInputTokens,
411
+ cacheWrite: usage.cacheCreationInputTokens
412
+ },
413
+ outputDetails: {
414
+ text: usage.outputTokens,
415
+ reasoning: usage.reasoningTokens
416
+ }
417
+ };
418
+ }
419
+ function getCostContext(value) {
420
+ if (!value || typeof value !== "object") {
421
+ return void 0;
422
+ }
423
+ return value;
424
+ }
425
+ function enqueueStartChunks(controller, {
426
+ runId,
427
+ prompt,
428
+ textId,
429
+ responseId,
430
+ modelId,
431
+ providerMetadata
432
+ }) {
433
+ controller.enqueue({
434
+ type: "start",
435
+ runId,
436
+ from: ChunkFrom.AGENT,
437
+ payload: {}
438
+ });
439
+ controller.enqueue({
440
+ type: "step-start",
441
+ runId,
442
+ from: ChunkFrom.AGENT,
443
+ payload: {
444
+ request: { body: prompt }
445
+ }
446
+ });
447
+ controller.enqueue({
448
+ type: "response-metadata",
449
+ runId,
450
+ from: ChunkFrom.AGENT,
451
+ payload: {
452
+ ...responseId ? { id: responseId } : {},
453
+ modelId,
454
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
455
+ }
456
+ });
457
+ controller.enqueue({
458
+ type: "text-start",
459
+ runId,
460
+ from: ChunkFrom.AGENT,
461
+ payload: {
462
+ id: textId,
463
+ providerMetadata
464
+ }
465
+ });
466
+ }
467
+ function enqueueTextDelta(controller, runId, textId, text) {
468
+ controller.enqueue({
469
+ type: "text-delta",
470
+ runId,
471
+ from: ChunkFrom.AGENT,
472
+ payload: {
473
+ id: textId,
474
+ text
475
+ }
476
+ });
477
+ }
478
+ function enqueueFinishChunks(controller, {
479
+ runId,
480
+ prompt,
481
+ textId,
482
+ text,
483
+ responseId,
484
+ modelId,
485
+ usage,
486
+ providerMetadata,
487
+ costContext
488
+ }) {
489
+ const timestamp = /* @__PURE__ */ new Date();
490
+ const response = {
491
+ ...responseId ? { id: responseId } : {},
492
+ modelId,
493
+ timestamp
494
+ };
495
+ const metadata = {
496
+ providerMetadata,
497
+ costContext,
498
+ request: { body: prompt },
499
+ modelId,
500
+ timestamp
501
+ };
502
+ controller.enqueue({
503
+ type: "text-end",
504
+ runId,
505
+ from: ChunkFrom.AGENT,
506
+ payload: {
507
+ id: textId,
508
+ providerMetadata
509
+ }
510
+ });
511
+ controller.enqueue({
512
+ type: "step-finish",
513
+ runId,
514
+ from: ChunkFrom.AGENT,
515
+ payload: {
516
+ ...responseId ? { id: responseId } : {},
517
+ providerMetadata,
518
+ totalUsage: usage,
519
+ response,
520
+ stepResult: {
521
+ reason: "stop",
522
+ warnings: []
523
+ },
524
+ output: {
525
+ text,
526
+ usage,
527
+ steps: []
528
+ },
529
+ metadata
530
+ }
531
+ });
532
+ controller.enqueue({
533
+ type: "finish",
534
+ runId,
535
+ from: ChunkFrom.AGENT,
536
+ payload: {
537
+ stepResult: {
538
+ reason: "stop",
539
+ warnings: []
540
+ },
541
+ output: {
542
+ usage,
543
+ steps: []
544
+ },
545
+ metadata,
546
+ providerMetadata,
547
+ messages: {
548
+ all: [],
549
+ user: [],
550
+ nonUser: []
551
+ },
552
+ response
553
+ }
554
+ });
555
+ }
556
+ function toLanguageModelUsage(usage) {
557
+ const inputTokens = usage.inputTokens.total ?? 0;
558
+ const outputTokens = usage.outputTokens.total ?? 0;
559
+ return {
560
+ inputTokens,
561
+ outputTokens,
562
+ totalTokens: inputTokens + outputTokens,
563
+ cachedInputTokens: usage.inputTokens.cacheRead,
564
+ cacheCreationInputTokens: usage.inputTokens.cacheWrite,
565
+ reasoningTokens: usage.outputTokens.reasoning,
566
+ raw: usage
567
+ };
568
+ }
569
+ function createProviderMetadata(provider, metadata) {
570
+ return {
571
+ [provider]: toJsonRecord(metadata)
572
+ };
573
+ }
574
+ function toJsonRecord(record) {
575
+ return Object.fromEntries(
576
+ Object.entries(record).filter((entry) => entry[1] !== void 0).map(([key, value]) => [key, toJsonValue(value)])
577
+ );
578
+ }
579
+ function toJsonValue(value) {
580
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
581
+ return value;
582
+ }
583
+ if (Array.isArray(value)) {
584
+ return value.filter((item) => item !== void 0).map(toJsonValue);
585
+ }
586
+ if (value instanceof Date) {
587
+ return value.toISOString();
588
+ }
589
+ if (typeof value === "object") {
590
+ return toJsonRecord(value);
591
+ }
592
+ return String(value);
593
+ }
594
+ function promptToText(prompt) {
595
+ if (typeof prompt === "string") {
596
+ return prompt;
597
+ }
598
+ if (Array.isArray(prompt)) {
599
+ return prompt.map(promptToText).filter(Boolean).join("\n");
600
+ }
601
+ if (!prompt || typeof prompt !== "object") {
602
+ return "";
603
+ }
604
+ const record = prompt;
605
+ if (typeof record.text === "string") {
606
+ return record.text;
607
+ }
608
+ if (typeof record.content === "string") {
609
+ return record.content;
610
+ }
611
+ if (record.content) {
612
+ return promptToText(record.content);
613
+ }
614
+ return "";
615
+ }
616
+ function sumDefined(...values) {
617
+ const defined = values.filter((value) => typeof value === "number");
618
+ if (defined.length === 0) {
619
+ return void 0;
620
+ }
621
+ return defined.reduce((sum, value) => sum + value, 0);
622
+ }
623
+
624
+ // src/index.ts
625
+ var PROVIDER = "@openai/agents";
626
+ var MODEL_ID = "openai-agents-sdk";
627
+ var OpenAISDKAgent = class extends Agent {
628
+ options;
629
+ #mastra;
630
+ #createdAgent;
631
+ constructor(options) {
632
+ super({
633
+ id: options.id,
634
+ name: options.name ?? options.id,
635
+ description: options.description,
636
+ instructions: "",
637
+ model: createNoopModel({
638
+ modelId: getModelId(options),
639
+ provider: PROVIDER
640
+ })
641
+ });
642
+ this.options = options;
643
+ }
644
+ __registerMastra(mastra) {
645
+ super.__registerMastra(mastra);
646
+ this.#mastra = mastra;
647
+ }
648
+ supportsMemory() {
649
+ return false;
650
+ }
651
+ async generate(messages, options) {
652
+ const prompt = promptToText(messages);
653
+ const runId = options?.runId ?? randomUUID();
654
+ const sdkAgent = this.resolveOpenAIAgent();
655
+ const modelId = getModelId(this.options, sdkAgent);
656
+ const requestContext = options?.requestContext ?? new RequestContext();
657
+ const instructions = options?.instructions ? promptToText(options.instructions) : void 0;
658
+ const telemetry = createSDKAgentTelemetry({
659
+ agentId: this.id,
660
+ agentName: this.name,
661
+ provider: PROVIDER,
662
+ modelId,
663
+ messages,
664
+ prompt,
665
+ runId,
666
+ streaming: false,
667
+ method: "generate",
668
+ requestContext,
669
+ instructions,
670
+ maxSteps: options?.maxSteps,
671
+ tracingOptions: options?.tracingOptions,
672
+ tracingContext: options?.tracingContext,
673
+ onFinish: options?.onFinish,
674
+ onStepFinish: options?.onStepFinish,
675
+ mastra: this.#mastra
676
+ });
677
+ let result;
678
+ try {
679
+ result = await telemetry.execute(() => runOpenAIGenerate(prompt, sdkAgent, runId, telemetry, options));
680
+ telemetry.endGenerate(result);
681
+ } catch (error) {
682
+ telemetry.fail(error);
683
+ throw error;
684
+ }
685
+ return toFullOutput({
686
+ messages,
687
+ runId,
688
+ provider: PROVIDER,
689
+ result,
690
+ options: telemetry.outputOptions()
691
+ });
692
+ }
693
+ async stream(messages, options) {
694
+ const prompt = promptToText(messages);
695
+ const runId = options?.runId ?? randomUUID();
696
+ const sdkAgent = this.resolveOpenAIAgent();
697
+ const modelId = getModelId(this.options, sdkAgent);
698
+ const requestContext = options?.requestContext ?? new RequestContext();
699
+ const instructions = options?.instructions ? promptToText(options.instructions) : void 0;
700
+ const telemetry = createSDKAgentTelemetry({
701
+ agentId: this.id,
702
+ agentName: this.name,
703
+ provider: PROVIDER,
704
+ modelId,
705
+ messages,
706
+ prompt,
707
+ runId,
708
+ streaming: true,
709
+ method: "stream",
710
+ requestContext,
711
+ instructions,
712
+ maxSteps: options?.maxSteps,
713
+ tracingOptions: options?.tracingOptions,
714
+ tracingContext: options?.tracingContext,
715
+ onFinish: options?.onFinish,
716
+ onStepFinish: options?.onStepFinish,
717
+ mastra: this.#mastra
718
+ });
719
+ return createMastraOutput({
720
+ messages,
721
+ runId,
722
+ modelId,
723
+ provider: PROVIDER,
724
+ stream: telemetry.wrapStream(runOpenAIAsMastraStream(prompt, sdkAgent, runId, modelId, telemetry, options)),
725
+ options: telemetry.outputOptions()
726
+ });
727
+ }
728
+ resolveOpenAIAgent() {
729
+ this.#createdAgent ??= this.options.agent ?? new Agent$1(toOpenAIAgentOptions(this.options));
730
+ return this.#createdAgent;
731
+ }
732
+ };
733
+ async function runOpenAIGenerate(prompt, agent, runId, telemetry, options) {
734
+ const result = await run(agent, prompt, {
735
+ stream: false,
736
+ maxTurns: options?.maxSteps,
737
+ signal: getAbortSignal(options)
738
+ });
739
+ recordOpenAIToolTelemetry(result.newItems, telemetry);
740
+ const text = getTextFromFinalOutput(result.finalOutput);
741
+ const responseId = result.lastResponseId;
742
+ const modelId = getModelId(void 0, result.lastAgent ?? agent, result.rawResponses.at(-1));
743
+ const usage = createOpenAIUsageTotals(result.state.usage);
744
+ const providerMetadata = getOpenAIProviderMetadata({
745
+ modelId,
746
+ responseId,
747
+ lastResponseId: result.lastResponseId,
748
+ rawResponseCount: result.rawResponses.length,
749
+ itemCount: result.newItems.length,
750
+ usage
751
+ });
752
+ return {
753
+ content: [{ type: "text", text }],
754
+ finishReason: { unified: "stop", raw: "stop" },
755
+ usage: toV3Usage(usage),
756
+ response: {
757
+ id: responseId,
758
+ modelId,
759
+ timestamp: /* @__PURE__ */ new Date()
760
+ },
761
+ providerMetadata
762
+ };
763
+ }
764
+ function runOpenAIAsMastraStream(prompt, agent, runId, requestedModelId, telemetry, options) {
765
+ return new ReadableStream({
766
+ start: async (controller) => {
767
+ const textId = randomUUID();
768
+ let text = "";
769
+ let responseId;
770
+ let modelId = requestedModelId;
771
+ try {
772
+ const result = await run(agent, prompt, {
773
+ stream: true,
774
+ maxTurns: options?.maxSteps,
775
+ signal: getAbortSignal(options)
776
+ });
777
+ enqueueStartChunks(controller, {
778
+ runId,
779
+ prompt,
780
+ textId,
781
+ responseId,
782
+ modelId
783
+ });
784
+ for await (const event of result) {
785
+ const delta = getTextDelta(event);
786
+ if (delta) {
787
+ text += delta;
788
+ enqueueTextDelta(controller, runId, textId, delta);
789
+ }
790
+ recordOpenAIStreamToolTelemetry(event, telemetry);
791
+ }
792
+ await result.completed;
793
+ responseId = result.lastResponseId ?? responseId;
794
+ modelId = getModelId(void 0, result.lastAgent ?? agent, result.rawResponses.at(-1));
795
+ if (!text) {
796
+ text = getTextFromFinalOutput(result.finalOutput);
797
+ if (text) {
798
+ enqueueTextDelta(controller, runId, textId, text);
799
+ }
800
+ }
801
+ const usage = createOpenAIUsageTotals(result.state.usage);
802
+ const providerMetadata = getOpenAIProviderMetadata({
803
+ modelId,
804
+ responseId,
805
+ lastResponseId: result.lastResponseId,
806
+ rawResponseCount: result.rawResponses.length,
807
+ itemCount: result.newItems.length,
808
+ usage
809
+ });
810
+ enqueueFinishChunks(controller, {
811
+ runId,
812
+ prompt,
813
+ textId,
814
+ text,
815
+ responseId,
816
+ modelId,
817
+ usage: toLanguageModelUsage(toV3Usage(usage)),
818
+ providerMetadata
819
+ });
820
+ controller.close();
821
+ } catch (error) {
822
+ controller.enqueue({
823
+ type: "error",
824
+ runId,
825
+ from: ChunkFrom.AGENT,
826
+ payload: { error }
827
+ });
828
+ controller.close();
829
+ }
830
+ }
831
+ });
832
+ }
833
+ function toOpenAIAgentOptions(options) {
834
+ return {
835
+ name: options.name ?? options.id,
836
+ ...options.sdkOptions
837
+ };
838
+ }
839
+ function getAbortSignal(options) {
840
+ return options?.abortSignal ?? options?.signal;
841
+ }
842
+ function getModelId(options, agent, rawResponse) {
843
+ return getModelNameFromUnknown(rawResponse) ?? getModelNameFromUnknown(agent?.model) ?? getModelNameFromUnknown(options?.sdkOptions?.model) ?? MODEL_ID;
844
+ }
845
+ function getModelNameFromUnknown(value) {
846
+ if (typeof value === "string") {
847
+ return value;
848
+ }
849
+ const record = toRecord(value);
850
+ return getString(record, "model") ?? getString(record, "modelId") ?? getString(record, "modelName") ?? getString(toRecord(record?.providerData), "model");
851
+ }
852
+ function getTextFromFinalOutput(output) {
853
+ if (typeof output === "string") {
854
+ return output;
855
+ }
856
+ if (output === void 0 || output === null) {
857
+ return "";
858
+ }
859
+ return JSON.stringify(output);
860
+ }
861
+ function createOpenAIUsageTotals(usage) {
862
+ const record = toRecord(usage);
863
+ if (!record) {
864
+ return {};
865
+ }
866
+ const inputDetails = getDetailRecords(record.inputTokensDetails);
867
+ const outputDetails = getDetailRecords(record.outputTokensDetails);
868
+ const requestUsageEntries = Array.isArray(record.requestUsageEntries) ? record.requestUsageEntries : void 0;
869
+ return {
870
+ inputTokens: getNumber(record.inputTokens),
871
+ outputTokens: getNumber(record.outputTokens),
872
+ cacheReadInputTokens: sumDetails(inputDetails, "cachedTokens", "cached_tokens", "cacheReadInputTokens"),
873
+ cacheCreationInputTokens: sumDetails(inputDetails, "cacheCreationInputTokens", "cache_creation_input_tokens"),
874
+ reasoningTokens: sumDetails(outputDetails, "reasoningTokens", "reasoning_tokens"),
875
+ requests: getNumber(record.requests),
876
+ requestUsageEntries
877
+ };
878
+ }
879
+ function getDetailRecords(value) {
880
+ if (Array.isArray(value)) {
881
+ return value.filter(isRecord);
882
+ }
883
+ const record = toRecord(value);
884
+ return record ? [record] : [];
885
+ }
886
+ function sumDetails(records, ...keys) {
887
+ let total = 0;
888
+ let found = false;
889
+ for (const record of records) {
890
+ for (const key of keys) {
891
+ const value = getNumber(record[key]);
892
+ if (value !== void 0) {
893
+ total += value;
894
+ found = true;
895
+ }
896
+ }
897
+ }
898
+ return found ? total : void 0;
899
+ }
900
+ function toV3Usage(usage) {
901
+ const totalInputTokens = usage.inputTokens;
902
+ const cacheRead = usage.cacheReadInputTokens;
903
+ const cacheWrite = usage.cacheCreationInputTokens;
904
+ const noCache = totalInputTokens === void 0 ? void 0 : Math.max(totalInputTokens - (sumDefined(cacheRead, cacheWrite) ?? 0), 0);
905
+ const outputTokens = usage.outputTokens;
906
+ const reasoningTokens = usage.reasoningTokens;
907
+ return {
908
+ inputTokens: {
909
+ total: totalInputTokens,
910
+ noCache,
911
+ cacheRead,
912
+ cacheWrite
913
+ },
914
+ outputTokens: {
915
+ total: outputTokens,
916
+ text: outputTokens,
917
+ reasoning: reasoningTokens
918
+ }
919
+ };
920
+ }
921
+ function getOpenAIProviderMetadata({
922
+ modelId,
923
+ responseId,
924
+ lastResponseId,
925
+ rawResponseCount,
926
+ itemCount,
927
+ usage
928
+ }) {
929
+ return createProviderMetadata("openai", {
930
+ model: modelId,
931
+ responseId,
932
+ lastResponseId,
933
+ rawResponseCount,
934
+ itemCount,
935
+ usage
936
+ });
937
+ }
938
+ function recordOpenAIToolTelemetry(items, telemetry) {
939
+ for (const item of items) {
940
+ if (item.type === "tool_call_item") {
941
+ const toolCall = getOpenAIToolCall(item.rawItem);
942
+ if (toolCall) {
943
+ telemetry.startToolCall(toolCall);
944
+ }
945
+ continue;
946
+ }
947
+ if (item.type === "tool_call_output_item") {
948
+ const toolOutput = getOpenAIToolOutput(item.rawItem, item.output);
949
+ if (toolOutput) {
950
+ telemetry.endToolCall(toolOutput);
951
+ }
952
+ }
953
+ }
954
+ }
955
+ function recordOpenAIStreamToolTelemetry(event, telemetry) {
956
+ if (event.type !== "run_item_stream_event") {
957
+ return;
958
+ }
959
+ if (event.name === "tool_called") {
960
+ const toolCall = getOpenAIToolCall(event.item.rawItem);
961
+ if (toolCall) {
962
+ telemetry.startToolCall(toolCall);
963
+ }
964
+ return;
965
+ }
966
+ if (event.name === "tool_output") {
967
+ const toolOutput = getOpenAIToolOutput(event.item.rawItem, getObjectValue(event.item, "output"));
968
+ if (toolOutput) {
969
+ telemetry.endToolCall(toolOutput);
970
+ }
971
+ }
972
+ }
973
+ function getOpenAIToolCall(rawItem) {
974
+ const record = toRecord(rawItem);
975
+ if (!record) {
976
+ return void 0;
977
+ }
978
+ if (record.type === "function_call") {
979
+ const toolCallId = getString(record, "callId") ?? getString(record, "id");
980
+ const toolName = getNamespacedToolName(record);
981
+ if (!toolCallId || !toolName) {
982
+ return void 0;
983
+ }
984
+ return {
985
+ toolCallId,
986
+ toolName,
987
+ input: parseJsonString(record.arguments)
988
+ };
989
+ }
990
+ if (record.type === "hosted_tool_call") {
991
+ const toolCallId = getString(record, "id") ?? getString(record, "name");
992
+ const toolName = getString(record, "name");
993
+ if (!toolCallId || !toolName) {
994
+ return void 0;
995
+ }
996
+ return {
997
+ toolCallId,
998
+ toolName,
999
+ input: parseJsonString(record.arguments)
1000
+ };
1001
+ }
1002
+ if (record.type === "shell_call" || record.type === "apply_patch_call") {
1003
+ const toolCallId = getString(record, "callId");
1004
+ if (!toolCallId) {
1005
+ return void 0;
1006
+ }
1007
+ return {
1008
+ toolCallId,
1009
+ toolName: String(record.type),
1010
+ input: record.action ?? record.operation
1011
+ };
1012
+ }
1013
+ return void 0;
1014
+ }
1015
+ function getOpenAIToolOutput(rawItem, fallbackOutput) {
1016
+ const record = toRecord(rawItem);
1017
+ if (!record) {
1018
+ return void 0;
1019
+ }
1020
+ const toolCallId = getString(record, "callId") ?? getString(record, "id");
1021
+ if (!toolCallId) {
1022
+ return void 0;
1023
+ }
1024
+ return {
1025
+ toolCallId,
1026
+ output: record.output ?? fallbackOutput,
1027
+ isError: record.status === "failed" || record.status === "incomplete"
1028
+ };
1029
+ }
1030
+ function getNamespacedToolName(record) {
1031
+ const name = getString(record, "name");
1032
+ const namespace = getString(record, "namespace");
1033
+ if (!name) {
1034
+ return void 0;
1035
+ }
1036
+ return namespace ? `${namespace}.${name}` : name;
1037
+ }
1038
+ function getTextDelta(event) {
1039
+ if (event.type !== "raw_model_stream_event") {
1040
+ return "";
1041
+ }
1042
+ const data = toRecord(event.data);
1043
+ return data?.type === "output_text_delta" && typeof data.delta === "string" ? data.delta : "";
1044
+ }
1045
+ function parseJsonString(value) {
1046
+ if (typeof value !== "string") {
1047
+ return value;
1048
+ }
1049
+ try {
1050
+ return JSON.parse(value);
1051
+ } catch {
1052
+ return value;
1053
+ }
1054
+ }
1055
+ function getNumber(value) {
1056
+ return typeof value === "number" ? value : void 0;
1057
+ }
1058
+ function getString(record, key) {
1059
+ const value = record?.[key];
1060
+ return typeof value === "string" ? value : void 0;
1061
+ }
1062
+ function getObjectValue(value, key) {
1063
+ return toRecord(value)?.[key];
1064
+ }
1065
+ function toRecord(value) {
1066
+ return isRecord(value) ? value : void 0;
1067
+ }
1068
+ function isRecord(value) {
1069
+ return value !== null && typeof value === "object";
1070
+ }
1071
+
1072
+ export { OpenAISDKAgent };
1073
+ //# sourceMappingURL=index.js.map
1074
+ //# sourceMappingURL=index.js.map