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