@mastra/claude 0.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,1024 @@
1
+ import { randomUUID } from 'crypto';
2
+ import { ReadableStream, TransformStream } from 'stream/web';
3
+ import { query } from '@anthropic-ai/claude-agent-sdk';
4
+ import { Agent } from '@mastra/core/agent';
5
+ import { RequestContext } from '@mastra/core/request-context';
6
+ import { ChunkFrom, MastraModelOutput } from '@mastra/core/stream';
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
+ 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
+ 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
+ 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
+ raw: usage
566
+ };
567
+ }
568
+ function createProviderMetadata(provider, metadata) {
569
+ return {
570
+ [provider]: toJsonRecord(metadata)
571
+ };
572
+ }
573
+ function toJsonRecord(record) {
574
+ return Object.fromEntries(
575
+ Object.entries(record).filter((entry) => entry[1] !== void 0).map(([key, value]) => [key, toJsonValue(value)])
576
+ );
577
+ }
578
+ function toJsonValue(value) {
579
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
580
+ return value;
581
+ }
582
+ if (Array.isArray(value)) {
583
+ return value.filter((item) => item !== void 0).map(toJsonValue);
584
+ }
585
+ if (value instanceof Date) {
586
+ return value.toISOString();
587
+ }
588
+ if (typeof value === "object") {
589
+ return toJsonRecord(value);
590
+ }
591
+ return String(value);
592
+ }
593
+ function promptToText(prompt) {
594
+ if (typeof prompt === "string") {
595
+ return prompt;
596
+ }
597
+ if (Array.isArray(prompt)) {
598
+ return prompt.map(promptToText).filter(Boolean).join("\n");
599
+ }
600
+ if (!prompt || typeof prompt !== "object") {
601
+ return "";
602
+ }
603
+ const record = prompt;
604
+ if (typeof record.text === "string") {
605
+ return record.text;
606
+ }
607
+ if (typeof record.content === "string") {
608
+ return record.content;
609
+ }
610
+ if (record.content) {
611
+ return promptToText(record.content);
612
+ }
613
+ return "";
614
+ }
615
+ function sumDefined(...values) {
616
+ const defined = values.filter((value) => typeof value === "number");
617
+ if (defined.length === 0) {
618
+ return void 0;
619
+ }
620
+ return defined.reduce((sum, value) => sum + value, 0);
621
+ }
622
+
623
+ // src/index.ts
624
+ var PROVIDER = "@anthropic-ai/claude-agent-sdk";
625
+ var MODEL_ID = "claude-agent-sdk";
626
+ var ClaudeSDKAgent = class extends Agent {
627
+ options;
628
+ #mastra;
629
+ constructor(options) {
630
+ super({
631
+ id: options.id,
632
+ name: options.name ?? options.id,
633
+ description: options.description,
634
+ instructions: "",
635
+ model: createNoopModel({
636
+ modelId: getModelId(options),
637
+ provider: PROVIDER
638
+ })
639
+ });
640
+ this.options = options;
641
+ }
642
+ __registerMastra(mastra) {
643
+ super.__registerMastra(mastra);
644
+ this.#mastra = mastra;
645
+ }
646
+ supportsMemory() {
647
+ return false;
648
+ }
649
+ async generate(messages, options) {
650
+ const prompt = promptToText(messages);
651
+ const runId = options?.runId ?? randomUUID();
652
+ const requestContext = options?.requestContext ?? new RequestContext();
653
+ const instructions = options?.instructions ? promptToText(options.instructions) : void 0;
654
+ const telemetry = createSDKAgentTelemetry({
655
+ agentId: this.id,
656
+ agentName: this.name,
657
+ provider: PROVIDER,
658
+ modelId: getModelId(this.options),
659
+ messages,
660
+ prompt,
661
+ runId,
662
+ streaming: false,
663
+ method: "generate",
664
+ requestContext,
665
+ instructions,
666
+ maxSteps: options?.maxSteps,
667
+ tracingOptions: options?.tracingOptions,
668
+ tracingContext: options?.tracingContext,
669
+ onFinish: options?.onFinish,
670
+ onStepFinish: options?.onStepFinish,
671
+ mastra: this.#mastra
672
+ });
673
+ let result;
674
+ try {
675
+ result = await telemetry.execute(
676
+ () => runClaudeGenerate(prompt, this.options, telemetry, options?.abortSignal ?? options?.signal)
677
+ );
678
+ telemetry.endGenerate(result);
679
+ } catch (error) {
680
+ telemetry.fail(error);
681
+ throw error;
682
+ }
683
+ return toFullOutput({
684
+ messages,
685
+ runId,
686
+ provider: PROVIDER,
687
+ result,
688
+ options: telemetry.outputOptions()
689
+ });
690
+ }
691
+ async stream(messages, options) {
692
+ const runId = options?.runId ?? randomUUID();
693
+ const prompt = promptToText(messages);
694
+ const modelId = getModelId(this.options);
695
+ const requestContext = options?.requestContext ?? new RequestContext();
696
+ const instructions = options?.instructions ? promptToText(options.instructions) : void 0;
697
+ const telemetry = createSDKAgentTelemetry({
698
+ agentId: this.id,
699
+ agentName: this.name,
700
+ provider: PROVIDER,
701
+ modelId,
702
+ messages,
703
+ prompt,
704
+ runId,
705
+ streaming: true,
706
+ method: "stream",
707
+ requestContext,
708
+ instructions,
709
+ maxSteps: options?.maxSteps,
710
+ tracingOptions: options?.tracingOptions,
711
+ tracingContext: options?.tracingContext,
712
+ onFinish: options?.onFinish,
713
+ onStepFinish: options?.onStepFinish,
714
+ mastra: this.#mastra
715
+ });
716
+ return createMastraOutput({
717
+ messages,
718
+ runId,
719
+ modelId,
720
+ provider: PROVIDER,
721
+ stream: telemetry.wrapStream(
722
+ runClaudeAsMastraStream(prompt, this.options, runId, telemetry, options?.abortSignal ?? options?.signal)
723
+ ),
724
+ options: telemetry.outputOptions()
725
+ });
726
+ }
727
+ };
728
+ async function runClaudeGenerate(prompt, options, telemetry, signal) {
729
+ let text = "";
730
+ const usage = createClaudeUsageCollector();
731
+ for await (const message of observeClaudeMessages(runClaude(prompt, options, signal), telemetry)) {
732
+ usage.record(message);
733
+ if (message.type === "result") {
734
+ if (message.subtype !== "success") {
735
+ throw new Error(message.errors.join("\n") || `Claude Agent SDK failed with ${message.subtype}`);
736
+ }
737
+ text = message.result;
738
+ }
739
+ }
740
+ const totals = usage.totals();
741
+ return {
742
+ content: [{ type: "text", text }],
743
+ finishReason: { unified: "stop", raw: "stop" },
744
+ usage: usage.toV3Usage(),
745
+ response: {
746
+ id: randomUUID(),
747
+ modelId: getModelId(options),
748
+ timestamp: /* @__PURE__ */ new Date()
749
+ },
750
+ providerMetadata: getClaudeProviderMetadata(options, totals),
751
+ costContext: getClaudeCostContext(options, totals)
752
+ };
753
+ }
754
+ function runClaudeAsMastraStream(prompt, options, runId, telemetry, signal) {
755
+ return new ReadableStream({
756
+ start: async (controller) => {
757
+ const textId = randomUUID();
758
+ const responseId = randomUUID();
759
+ const modelId = getModelId(options);
760
+ const usage = createClaudeUsageCollector();
761
+ let text = "";
762
+ let sawDelta = false;
763
+ try {
764
+ enqueueStartChunks(controller, {
765
+ runId,
766
+ prompt,
767
+ textId,
768
+ responseId,
769
+ modelId,
770
+ providerMetadata: getClaudeProviderMetadata(options, usage.totals())
771
+ });
772
+ for await (const message of observeClaudeMessages(runClaude(prompt, options, signal), telemetry)) {
773
+ usage.record(message);
774
+ const delta = getTextDelta(message);
775
+ if (delta) {
776
+ sawDelta = true;
777
+ text += delta;
778
+ enqueueTextDelta(controller, runId, textId, delta);
779
+ }
780
+ if (message.type === "result") {
781
+ if (message.subtype !== "success") {
782
+ throw new Error(message.errors.join("\n") || `Claude Agent SDK failed with ${message.subtype}`);
783
+ }
784
+ if (!sawDelta && message.result) {
785
+ text += message.result;
786
+ enqueueTextDelta(controller, runId, textId, message.result);
787
+ }
788
+ }
789
+ }
790
+ const totals = usage.totals();
791
+ const providerMetadata = getClaudeProviderMetadata(options, totals);
792
+ enqueueFinishChunks(controller, {
793
+ runId,
794
+ prompt,
795
+ textId,
796
+ text,
797
+ responseId,
798
+ modelId,
799
+ usage: usage.toLanguageModelUsage(),
800
+ providerMetadata,
801
+ costContext: getClaudeCostContext(options, totals)
802
+ });
803
+ controller.close();
804
+ } catch (error) {
805
+ controller.enqueue({
806
+ type: "error",
807
+ runId,
808
+ from: ChunkFrom.AGENT,
809
+ payload: { error }
810
+ });
811
+ controller.close();
812
+ }
813
+ }
814
+ });
815
+ }
816
+ function runClaude(prompt, options, signal) {
817
+ const abortController = createAbortController(signal);
818
+ const queryOptions = {
819
+ ...options.sdkOptions
820
+ };
821
+ if (abortController) {
822
+ queryOptions.abortController = abortController;
823
+ }
824
+ return query({
825
+ prompt,
826
+ options: queryOptions
827
+ });
828
+ }
829
+ async function* observeClaudeMessages(messages, telemetry) {
830
+ for await (const message of messages) {
831
+ recordClaudeToolTelemetry(message, telemetry);
832
+ yield message;
833
+ }
834
+ }
835
+ function recordClaudeToolTelemetry(message, telemetry) {
836
+ for (const toolCall of getClaudeToolCalls(message)) {
837
+ telemetry.startToolCall(toolCall);
838
+ }
839
+ for (const toolResult of getClaudeToolResults(message)) {
840
+ telemetry.endToolCall(toolResult);
841
+ }
842
+ }
843
+ function getClaudeToolCalls(message) {
844
+ if (message.type !== "assistant") {
845
+ return [];
846
+ }
847
+ return getContentBlocks(message.message).filter(isRecord).filter((block) => block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string").map((block) => ({
848
+ toolCallId: block.id,
849
+ toolName: block.name,
850
+ input: block.input
851
+ }));
852
+ }
853
+ function getClaudeToolResults(message) {
854
+ if (message.type !== "user") {
855
+ return [];
856
+ }
857
+ return getContentBlocks(message.message).filter(isRecord).filter((block) => block.type === "tool_result" && typeof block.tool_use_id === "string").map((block) => ({
858
+ toolCallId: block.tool_use_id,
859
+ output: block.content,
860
+ isError: block.is_error === true
861
+ }));
862
+ }
863
+ function getContentBlocks(message) {
864
+ if (!isRecord(message)) {
865
+ return [];
866
+ }
867
+ return Array.isArray(message.content) ? message.content : [];
868
+ }
869
+ function isRecord(value) {
870
+ return value !== null && typeof value === "object";
871
+ }
872
+ function createAbortController(signal) {
873
+ if (!signal) {
874
+ return void 0;
875
+ }
876
+ const controller = new AbortController();
877
+ if (signal.aborted) {
878
+ controller.abort(signal.reason);
879
+ return controller;
880
+ }
881
+ signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
882
+ return controller;
883
+ }
884
+ function getModelId(options) {
885
+ return options.sdkOptions?.model ?? MODEL_ID;
886
+ }
887
+ function createClaudeUsageCollector() {
888
+ const assistantUsageById = /* @__PURE__ */ new Map();
889
+ let resultUsage = {};
890
+ return {
891
+ record(message) {
892
+ if (message.type === "assistant") {
893
+ assistantUsageById.set(message.message.id, usageFromClaudeMessage(message.message.usage));
894
+ return;
895
+ }
896
+ if (message.type === "result") {
897
+ resultUsage = {
898
+ ...usageFromClaudeMessage(message.usage),
899
+ totalCostUsd: message.total_cost_usd,
900
+ modelUsage: message.modelUsage
901
+ };
902
+ }
903
+ },
904
+ totals() {
905
+ const assistantUsage = getAssistantUsageTotals(assistantUsageById);
906
+ if (hasAnyUsage(resultUsage)) {
907
+ return {
908
+ ...resultUsage,
909
+ inputTokens: resultUsage.inputTokens ?? assistantUsage.inputTokens,
910
+ outputTokens: resultUsage.outputTokens ?? assistantUsage.outputTokens,
911
+ cacheReadInputTokens: resultUsage.cacheReadInputTokens ?? assistantUsage.cacheReadInputTokens,
912
+ cacheCreationInputTokens: resultUsage.cacheCreationInputTokens ?? assistantUsage.cacheCreationInputTokens
913
+ };
914
+ }
915
+ return assistantUsage;
916
+ },
917
+ toV3Usage() {
918
+ return toV3Usage(this.totals());
919
+ },
920
+ toLanguageModelUsage() {
921
+ return toLanguageModelUsage(toV3Usage(this.totals()));
922
+ }
923
+ };
924
+ }
925
+ function getAssistantUsageTotals(assistantUsageById) {
926
+ return [...assistantUsageById.values()].reduce((totals, item) => {
927
+ totals.inputTokens = addOptional(totals.inputTokens, item.inputTokens);
928
+ totals.outputTokens = addOptional(totals.outputTokens, item.outputTokens);
929
+ totals.cacheReadInputTokens = addOptional(totals.cacheReadInputTokens, item.cacheReadInputTokens);
930
+ totals.cacheCreationInputTokens = addOptional(totals.cacheCreationInputTokens, item.cacheCreationInputTokens);
931
+ return totals;
932
+ }, {});
933
+ }
934
+ function usageFromClaudeMessage(usage) {
935
+ if (!usage || typeof usage !== "object") {
936
+ return {};
937
+ }
938
+ const record = usage;
939
+ return {
940
+ inputTokens: getTokenTotal(record.input_tokens),
941
+ outputTokens: getTokenTotal(record.output_tokens),
942
+ cacheReadInputTokens: getTokenTotal(record.cache_read_input_tokens),
943
+ cacheCreationInputTokens: getTokenTotal(record.cache_creation_input_tokens)
944
+ };
945
+ }
946
+ function hasAnyUsage(usage) {
947
+ return usage.inputTokens !== void 0 || usage.outputTokens !== void 0 || usage.cacheReadInputTokens !== void 0 || usage.cacheCreationInputTokens !== void 0 || usage.totalCostUsd !== void 0;
948
+ }
949
+ function addOptional(left, right) {
950
+ if (left === void 0) {
951
+ return right;
952
+ }
953
+ if (right === void 0) {
954
+ return left;
955
+ }
956
+ return left + right;
957
+ }
958
+ function toV3Usage(usage) {
959
+ const noCache = usage.inputTokens;
960
+ const cacheRead = usage.cacheReadInputTokens;
961
+ const cacheWrite = usage.cacheCreationInputTokens;
962
+ const totalInputTokens = sumDefined(noCache, cacheRead, cacheWrite);
963
+ const outputTokens = usage.outputTokens;
964
+ return {
965
+ inputTokens: {
966
+ total: totalInputTokens,
967
+ noCache,
968
+ cacheRead,
969
+ cacheWrite
970
+ },
971
+ outputTokens: {
972
+ total: outputTokens,
973
+ text: outputTokens
974
+ }
975
+ };
976
+ }
977
+ function getClaudeProviderMetadata(options, usage) {
978
+ const queryOptions = options.sdkOptions;
979
+ return createProviderMetadata("claude", {
980
+ totalCostUsd: usage?.totalCostUsd,
981
+ model: getModelId(options),
982
+ cwd: queryOptions?.cwd,
983
+ permissionMode: queryOptions?.permissionMode,
984
+ maxTurns: queryOptions?.maxTurns,
985
+ allowedTools: queryOptions?.allowedTools,
986
+ disallowedTools: queryOptions?.disallowedTools,
987
+ usage
988
+ });
989
+ }
990
+ function getClaudeCostContext(options, usage) {
991
+ if (typeof usage?.totalCostUsd !== "number") {
992
+ return void 0;
993
+ }
994
+ return {
995
+ provider: "anthropic",
996
+ model: getModelId(options),
997
+ estimatedCost: usage.totalCostUsd,
998
+ costUnit: "USD",
999
+ costMetadata: {
1000
+ source: "sdk_estimate",
1001
+ sdkProvider: PROVIDER,
1002
+ sdkCostField: "total_cost_usd",
1003
+ scope: "query_total",
1004
+ modelUsage: usage.modelUsage
1005
+ }
1006
+ };
1007
+ }
1008
+ function getTextDelta(message) {
1009
+ if (message.type !== "stream_event") {
1010
+ return "";
1011
+ }
1012
+ const event = message.event;
1013
+ if (event.type === "content_block_delta" && event.delta?.type === "text_delta") {
1014
+ return event.delta.text ?? "";
1015
+ }
1016
+ return "";
1017
+ }
1018
+ function getTokenTotal(value) {
1019
+ return typeof value === "number" ? value : void 0;
1020
+ }
1021
+
1022
+ export { ClaudeSDKAgent };
1023
+ //# sourceMappingURL=index.js.map
1024
+ //# sourceMappingURL=index.js.map