@mastra/claude 0.1.1-alpha.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # @mastra/claude
2
2
 
3
+ ## 0.2.0-alpha.1
4
+
5
+ ### Minor Changes
6
+
7
+ - Added structured output support for Claude and OpenAI SDK agents using their provider-native structured output APIs. Cursor SDK agent calls now fail clearly when structuredOutput is requested because the Cursor TypeScript SDK does not expose a schema-constrained output API. SDK agents now implement provider-native resume through Mastra's existing resumeGenerate/resumeStream methods by accepting provider-specific resumeData with a message payload. Cursor SDK agent options now use the same clear source split as OpenAI: pass either a pre-created agent or SDK options for wrapper-created agents. ([#17580](https://github.com/mastra-ai/mastra/pull/17580))
8
+
9
+ Example:
10
+
11
+ ```ts
12
+ await claudeAgent.resumeGenerate({
13
+ message: 'Continue the task.',
14
+ sessionId: 'claude-session-id',
15
+ });
16
+
17
+ await openAIAgent.resumeStream({
18
+ message: 'Continue the task.',
19
+ previousResponseId: 'resp_123',
20
+ });
21
+
22
+ const result = await openAIAgent.generate('Return the answer as JSON.', {
23
+ structuredOutput: {
24
+ schema: z.object({ answer: z.string() }),
25
+ },
26
+ });
27
+ // result.object has shape { answer: string }
28
+ ```
29
+
30
+ Claude and OpenAI SDK agents support `structuredOutput` through their native SDK APIs. `CursorSDKAgent` throws a clear error when `structuredOutput` is requested because the Cursor TypeScript SDK does not expose schema-constrained output.
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies [[`575f815`](https://github.com/mastra-ai/mastra/commit/575f815c5c3567b71c0b83cbb7fa98c8253a9d9c), [`306909a`](https://github.com/mastra-ai/mastra/commit/306909a693de77d709b38706e2673c9547d24a28), [`5191af8`](https://github.com/mastra-ai/mastra/commit/5191af80c799eea25357c545fc05d91b3883531d), [`43bd3d4`](https://github.com/mastra-ai/mastra/commit/43bd3d421987463fdf35386a45199c49499ed069), [`e6fa79e`](https://github.com/mastra-ai/mastra/commit/e6fa79ec72a2ddffdd25e85270398951e9d552a4), [`904bcdf`](https://github.com/mastra-ai/mastra/commit/904bcdf7b8004aa7be823f9f70ca63580e47e470), [`7f5ee1d`](https://github.com/mastra-ai/mastra/commit/7f5ee1dca46daee8d2817f2ebe49e6335da81956), [`1e9aab5`](https://github.com/mastra-ai/mastra/commit/1e9aab50ff11e6e88fde4d7cbf512c44a9fe8d61), [`bf8eb6d`](https://github.com/mastra-ai/mastra/commit/bf8eb6d0ec213a403eb9265a594ad283c44ab3dc), [`493a328`](https://github.com/mastra-ai/mastra/commit/493a328f4346a1deeb9f1e2e44c8f2a3a4d7591b), [`029a414`](https://github.com/mastra-ai/mastra/commit/029a4141719793bd3e898a39eb5a0466a55f5f3a), [`b147b29`](https://github.com/mastra-ai/mastra/commit/b147b2907f0cd1aa812efe6d6e3f58d22e66fc88), [`d371ac1`](https://github.com/mastra-ai/mastra/commit/d371ac1d9820afaaf7cfdbc380a475946a994d8f), [`cf182b7`](https://github.com/mastra-ai/mastra/commit/cf182b7fb495767946d9840ef29f19cfa906f31f), [`a049c2a`](https://github.com/mastra-ai/mastra/commit/a049c2a9dfb41d0ee2e7a28874a88cd64fd5669f), [`b147b29`](https://github.com/mastra-ai/mastra/commit/b147b2907f0cd1aa812efe6d6e3f58d22e66fc88), [`2a96528`](https://github.com/mastra-ai/mastra/commit/2a9652848dfa3c5a2426f952e9d93554c26fd90f), [`2656d9c`](https://github.com/mastra-ai/mastra/commit/2656d9c2976d4f3354253bfbbbf9b88a1b2bbf34), [`63e3fe1`](https://github.com/mastra-ai/mastra/commit/63e3fe13cc1ea96f91d7c68aea92f400faf9e4da), [`1d4ce8d`](https://github.com/mastra-ai/mastra/commit/1d4ce8daaa54511f325c1b609d31b8e54009d677), [`8c68372`](https://github.com/mastra-ai/mastra/commit/8c68372e85fe0b066ec12c58bd29ffb93e54c552)]:
35
+ - @mastra/core@1.42.0-alpha.4
36
+
3
37
  ## 0.1.1-alpha.0
4
38
 
5
39
  ### Patch Changes
@@ -3,7 +3,7 @@ name: mastra-claude
3
3
  description: Documentation for @mastra/claude. Use when working with @mastra/claude APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/claude"
6
- version: "0.1.1-alpha.0"
6
+ version: "0.2.0-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -16,7 +16,7 @@ Read the individual reference documents for detailed explanations and code examp
16
16
 
17
17
  ### Docs
18
18
 
19
- - [SDK agents](references/docs-agents-sdk-agents.md) - Use Claude Agent SDK and Cursor Agent SDK agents from Mastra.
19
+ - [SDK agents](references/docs-agents-sdk-agents.md) - Use Claude Agent SDK, Cursor Agent SDK, and OpenAI Agents SDK agents from Mastra.
20
20
 
21
21
 
22
22
  Read [assets/SOURCE_MAP.json](assets/SOURCE_MAP.json) for source code references.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.1-alpha.0",
2
+ "version": "0.2.0-alpha.1",
3
3
  "package": "@mastra/claude",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -13,6 +13,7 @@ SDK agents let you use other agent SDK frameworks inside Mastra. Use them to reg
13
13
 
14
14
  - [Claude Agent SDK](#claude-agent-sdk): Use `@mastra/claude` to register a Claude SDK agent and call it with Mastra `generate()` and `stream()`.
15
15
  - [Cursor Agent SDK](#cursor-agent-sdk): Use `@mastra/cursor` to register a Cursor SDK agent and call it with Mastra `generate()` and `stream()`.
16
+ - [OpenAI Agents SDK](#openai-agents-sdk): Use `@mastra/openai` to register an OpenAI SDK agent and call it with Mastra `generate()` and `stream()`.
16
17
 
17
18
  ## Claude Agent SDK
18
19
 
@@ -216,6 +217,117 @@ export const cursorSDKAgent = new CursorSDKAgent({
216
217
  })
217
218
  ```
218
219
 
220
+ ## OpenAI Agents SDK
221
+
222
+ Use `@mastra/openai` to register an OpenAI Agents SDK agent in Mastra while keeping OpenAI-specific agent settings in OpenAI SDK options.
223
+
224
+ ### Install OpenAI packages
225
+
226
+ Install the Mastra package and the OpenAI Agents SDK peer dependency:
227
+
228
+ **npm**:
229
+
230
+ ```bash
231
+ npm install @mastra/openai @openai/agents zod
232
+ ```
233
+
234
+ **pnpm**:
235
+
236
+ ```bash
237
+ pnpm add @mastra/openai @openai/agents zod
238
+ ```
239
+
240
+ **Yarn**:
241
+
242
+ ```bash
243
+ yarn add @mastra/openai @openai/agents zod
244
+ ```
245
+
246
+ **Bun**:
247
+
248
+ ```bash
249
+ bun add @mastra/openai @openai/agents zod
250
+ ```
251
+
252
+ Set the OpenAI SDK credential:
253
+
254
+ ```bash
255
+ export OPENAI_API_KEY="..."
256
+ ```
257
+
258
+ ### Create an OpenAI SDK agent
259
+
260
+ Configure OpenAI Agents SDK through `sdkOptions`. `OpenAISDKAgent` creates the OpenAI SDK agent on first use.
261
+
262
+ ```typescript
263
+ import { OpenAISDKAgent } from '@mastra/openai'
264
+
265
+ export const openaiSDKAgent = new OpenAISDKAgent({
266
+ id: 'openai-sdk-agent',
267
+ name: 'OpenAI SDK Agent',
268
+ description: 'Use OpenAI Agents SDK through Mastra.',
269
+ sdkOptions: {
270
+ name: 'Repository assistant',
271
+ instructions: 'Answer clearly and cite the relevant files.',
272
+ model: 'gpt-5',
273
+ },
274
+ })
275
+ ```
276
+
277
+ ### Use an existing OpenAI SDK agent
278
+
279
+ If your app already creates an OpenAI SDK agent, pass that agent to `OpenAISDKAgent` instead:
280
+
281
+ ```typescript
282
+ import { Agent as OpenAIAgent } from '@openai/agents'
283
+ import { OpenAISDKAgent } from '@mastra/openai'
284
+
285
+ const sdkAgent = new OpenAIAgent({
286
+ name: 'Repository assistant',
287
+ instructions: 'Answer clearly and cite the relevant files.',
288
+ model: 'gpt-5',
289
+ })
290
+
291
+ export const openaiSDKAgent = new OpenAISDKAgent({
292
+ id: 'openai-sdk-agent',
293
+ name: 'OpenAI SDK Agent',
294
+ description: 'Use OpenAI Agents SDK through Mastra.',
295
+ agent: sdkAgent,
296
+ })
297
+ ```
298
+
299
+ ### Add OpenAI SDK tools
300
+
301
+ OpenAI Agents SDK tools are configured with OpenAI SDK options. Create tools with the OpenAI SDK, then pass them through `sdkOptions.tools`.
302
+
303
+ ```typescript
304
+ import { tool } from '@openai/agents'
305
+ import { OpenAISDKAgent } from '@mastra/openai'
306
+ import { z } from 'zod'
307
+
308
+ const getTemperature = tool({
309
+ name: 'get_temperature',
310
+ description: 'Get the current temperature for a city.',
311
+ parameters: z.object({
312
+ city: z.string(),
313
+ }),
314
+ execute: async ({ city }) => {
315
+ return `${city}: 27 C`
316
+ },
317
+ })
318
+
319
+ export const openaiSDKAgent = new OpenAISDKAgent({
320
+ id: 'openai-sdk-agent',
321
+ name: 'OpenAI SDK Agent',
322
+ description: 'Use OpenAI Agents SDK through Mastra.',
323
+ sdkOptions: {
324
+ name: 'Weather assistant',
325
+ model: 'gpt-5',
326
+ tools: [getTemperature],
327
+ },
328
+ })
329
+ ```
330
+
219
331
  ## Register SDK agents
220
332
 
221
333
  Register SDK agents in the Mastra instance like other agents:
@@ -224,11 +336,13 @@ Register SDK agents in the Mastra instance like other agents:
224
336
  import { Mastra } from '@mastra/core'
225
337
  import { claudeSDKAgent } from './agents/claude-sdk-agent'
226
338
  import { cursorSDKAgent } from './agents/cursor-sdk-agent'
339
+ import { openaiSDKAgent } from './agents/openai-sdk-agent'
227
340
 
228
341
  export const mastra = new Mastra({
229
342
  agents: {
230
343
  claudeSDKAgent,
231
344
  cursorSDKAgent,
345
+ openaiSDKAgent,
232
346
  },
233
347
  })
234
348
  ```
@@ -246,11 +360,61 @@ for await (const chunk of stream.textStream) {
246
360
  }
247
361
  ```
248
362
 
363
+ ## Resume SDK runs
364
+
365
+ SDK agents support Mastra `resumeGenerate()` and `resumeStream()` with provider-native resume data. Pass the message to continue with and the resume identifier used by the underlying SDK.
366
+
367
+ Claude SDK agents can resume a known session with `sessionId`:
368
+
369
+ ```typescript
370
+ const result = await claudeSDKAgent.resumeGenerate({
371
+ message: 'Continue the previous task.',
372
+ sessionId: 'claude-session-id',
373
+ })
374
+
375
+ console.log(result.text)
376
+ ```
377
+
378
+ OpenAI SDK agents can resume with a previous response, conversation, or session:
379
+
380
+ ```typescript
381
+ const stream = await openaiSDKAgent.resumeStream({
382
+ message: 'Continue the previous task.',
383
+ previousResponseId: 'resp_123',
384
+ })
385
+
386
+ for await (const chunk of stream.textStream) {
387
+ process.stdout.write(chunk)
388
+ }
389
+ ```
390
+
391
+ Cursor SDK agents can continue with the wrapped SDK agent. If you need to resume a stored Cursor SDK agent by ID, pass `agentId` in `resumeData`.
392
+
393
+ ## Structured output
394
+
395
+ Claude and OpenAI SDK agents support Mastra `structuredOutput` through their provider-native structured output APIs. The validated value is available on `result.object`.
396
+
397
+ ```typescript
398
+ import { z } from 'zod'
399
+
400
+ const result = await openaiSDKAgent.generate<{ summary: string }>('Summarize this project.', {
401
+ structuredOutput: {
402
+ schema: z.object({
403
+ summary: z.string(),
404
+ }),
405
+ },
406
+ })
407
+
408
+ console.log(result.object.summary)
409
+ ```
410
+
411
+ Cursor SDK agents throw a clear error when `structuredOutput` is requested because the Cursor TypeScript SDK doesn't expose a schema-constrained output API.
412
+
249
413
  ## Observability
250
414
 
251
415
  SDK agents create Mastra agent and model spans for `generate()` and `stream()` calls. Mastra records SDK-provided usage, tool activity, and provider metadata when the vendor SDK exposes those events.
252
416
 
253
- Claude SDK runs can include SDK-estimated cost from the Claude result message. Cursor SDK runs include token usage from Cursor interaction updates.
417
+ Claude SDK runs can include SDK-estimated cost from the Claude result message. Cursor SDK runs include token usage from Cursor interaction updates. OpenAI SDK runs include token usage from OpenAI run state.
254
418
 
255
419
  For storage and dashboard setup, see [Observability](https://mastra.ai/docs/observability/overview).
256
420
 
package/dist/index.cjs CHANGED
@@ -8,6 +8,7 @@ var requestContext = require('@mastra/core/request-context');
8
8
  var stream = require('@mastra/core/stream');
9
9
  var messageList = require('@mastra/core/agent/message-list');
10
10
  var observability = require('@mastra/core/observability');
11
+ var schema = require('@mastra/core/schema');
11
12
 
12
13
  // src/index.ts
13
14
  function createNoopModel({ modelId, provider }) {
@@ -35,7 +36,8 @@ function createCompletedMastraStream({
35
36
  modelId,
36
37
  usage,
37
38
  providerMetadata,
38
- costContext
39
+ costContext,
40
+ object
39
41
  }) {
40
42
  return new web.ReadableStream({
41
43
  start(controller) {
@@ -60,7 +62,8 @@ function createCompletedMastraStream({
60
62
  modelId,
61
63
  usage,
62
64
  providerMetadata,
63
- costContext
65
+ costContext,
66
+ object
64
67
  });
65
68
  controller.close();
66
69
  }
@@ -109,7 +112,8 @@ function toFullOutput({
109
112
  modelId: result.response.modelId,
110
113
  usage: toLanguageModelUsage(result.usage),
111
114
  providerMetadata: result.providerMetadata,
112
- costContext: result.costContext
115
+ costContext: result.costContext,
116
+ object: result.object
113
117
  });
114
118
  return createMastraOutput({
115
119
  messages,
@@ -488,7 +492,8 @@ function enqueueFinishChunks(controller, {
488
492
  modelId,
489
493
  usage,
490
494
  providerMetadata,
491
- costContext
495
+ costContext,
496
+ object
492
497
  }) {
493
498
  const timestamp = /* @__PURE__ */ new Date();
494
499
  const response = {
@@ -512,6 +517,14 @@ function enqueueFinishChunks(controller, {
512
517
  providerMetadata
513
518
  }
514
519
  });
520
+ if (object !== void 0) {
521
+ controller.enqueue({
522
+ type: "object-result",
523
+ runId,
524
+ from: stream.ChunkFrom.AGENT,
525
+ object
526
+ });
527
+ }
515
528
  controller.enqueue({
516
529
  type: "step-finish",
517
530
  runId,
@@ -616,6 +629,48 @@ function promptToText(prompt) {
616
629
  }
617
630
  return "";
618
631
  }
632
+ function getStructuredOutputSchema(structuredOutput) {
633
+ if (!structuredOutput?.schema) {
634
+ return void 0;
635
+ }
636
+ return schema.standardSchemaToJSONSchema(schema.toStandardSchema(structuredOutput.schema));
637
+ }
638
+ async function getStructuredOutputFromValue(value, structuredOutput) {
639
+ if (!structuredOutput?.schema) {
640
+ return void 0;
641
+ }
642
+ let parsed;
643
+ if (typeof value === "string") {
644
+ try {
645
+ parsed = JSON.parse(value);
646
+ } catch (error) {
647
+ return handleStructuredOutputError(
648
+ new Error("Structured output must be valid JSON.", { cause: error }),
649
+ structuredOutput
650
+ );
651
+ }
652
+ } else {
653
+ parsed = value;
654
+ }
655
+ const schema$1 = schema.toStandardSchema(structuredOutput.schema);
656
+ const result = await schema$1["~standard"].validate(parsed);
657
+ if (!result.issues) {
658
+ return result.value;
659
+ }
660
+ const message = result.issues.map((issue) => `- ${issue.path?.join(".") || "root"}: ${issue.message}`).join("\n");
661
+ return handleStructuredOutputError(new Error(`Structured output validation failed:
662
+ ${message}`), structuredOutput);
663
+ }
664
+ function handleStructuredOutputError(error, structuredOutput) {
665
+ if (structuredOutput.errorStrategy === "fallback") {
666
+ return structuredOutput.fallbackValue;
667
+ }
668
+ if (structuredOutput.errorStrategy === "warn") {
669
+ structuredOutput.logger?.warn(error.message);
670
+ return void 0;
671
+ }
672
+ throw error;
673
+ }
619
674
  function sumDefined(...values) {
620
675
  const defined = values.filter((value) => typeof value === "number");
621
676
  if (defined.length === 0) {
@@ -676,9 +731,7 @@ var ClaudeSDKAgent = class extends agent.Agent {
676
731
  });
677
732
  let result;
678
733
  try {
679
- result = await telemetry.execute(
680
- () => runClaudeGenerate(prompt, this.options, telemetry, options?.abortSignal ?? options?.signal)
681
- );
734
+ result = await telemetry.execute(() => runClaudeGenerate(prompt, this.options, telemetry, options));
682
735
  telemetry.endGenerate(result);
683
736
  } catch (error) {
684
737
  telemetry.fail(error);
@@ -689,7 +742,7 @@ var ClaudeSDKAgent = class extends agent.Agent {
689
742
  runId,
690
743
  provider: PROVIDER,
691
744
  result,
692
- options: telemetry.outputOptions()
745
+ options: { ...telemetry.outputOptions(), structuredOutput: options?.structuredOutput }
693
746
  });
694
747
  }
695
748
  async stream(messages, options) {
@@ -722,26 +775,82 @@ var ClaudeSDKAgent = class extends agent.Agent {
722
775
  runId,
723
776
  modelId,
724
777
  provider: PROVIDER,
725
- stream: telemetry.wrapStream(
726
- runClaudeAsMastraStream(prompt, this.options, runId, telemetry, options?.abortSignal ?? options?.signal)
727
- ),
728
- options: telemetry.outputOptions()
778
+ stream: telemetry.wrapStream(runClaudeAsMastraStream(prompt, this.options, runId, telemetry, options)),
779
+ options: { ...telemetry.outputOptions(), structuredOutput: options?.structuredOutput }
729
780
  });
730
781
  }
782
+ async resumeGenerate(resumeData, options) {
783
+ const data = validateClaudeResumeData(resumeData);
784
+ return this.generate(data.message, createClaudeResumeRunOptions(data, options));
785
+ }
786
+ async resumeStream(resumeData, options) {
787
+ const data = validateClaudeResumeData(resumeData);
788
+ return this.stream(data.message, createClaudeResumeRunOptions(data, options));
789
+ }
731
790
  };
732
- async function runClaudeGenerate(prompt, options, telemetry, signal) {
791
+ function validateClaudeResumeData(resumeData) {
792
+ if (!isRecord(resumeData) || !("message" in resumeData)) {
793
+ throw new Error("ClaudeSDKAgent resumeData must include a message.");
794
+ }
795
+ const hasSessionId = "sessionId" in resumeData;
796
+ const hasContinue = "continue" in resumeData;
797
+ if (hasSessionId && hasContinue) {
798
+ throw new Error("ClaudeSDKAgent resumeData must include either sessionId or continue: true, not both.");
799
+ }
800
+ if (hasSessionId) {
801
+ if (typeof resumeData.sessionId !== "string") {
802
+ throw new Error("ClaudeSDKAgent resumeData.sessionId must be a string.");
803
+ }
804
+ return resumeData;
805
+ }
806
+ if (hasContinue) {
807
+ if (resumeData.continue !== true) {
808
+ throw new Error("ClaudeSDKAgent resumeData.continue must be true when provided.");
809
+ }
810
+ return resumeData;
811
+ }
812
+ throw new Error("ClaudeSDKAgent resumeData must include sessionId or continue: true.");
813
+ }
814
+ function createClaudeResumeRunOptions(resumeData, options) {
815
+ const sdkOptions = { ...options?.sdkOptions };
816
+ if ("sessionId" in resumeData && typeof resumeData.sessionId === "string") {
817
+ sdkOptions.resume = resumeData.sessionId;
818
+ if (resumeData.forkSession !== void 0) {
819
+ sdkOptions.forkSession = resumeData.forkSession;
820
+ }
821
+ if (resumeData.resumeSessionAt !== void 0) {
822
+ sdkOptions.resumeSessionAt = resumeData.resumeSessionAt;
823
+ }
824
+ } else {
825
+ sdkOptions.continue = true;
826
+ }
827
+ return {
828
+ ...options,
829
+ sdkOptions
830
+ };
831
+ }
832
+ async function runClaudeGenerate(prompt, options, telemetry, runOptions) {
733
833
  let text = "";
834
+ let structuredOutputValue;
734
835
  const usage = createClaudeUsageCollector();
735
- for await (const message of observeClaudeMessages(runClaude(prompt, options, signal), telemetry)) {
836
+ for await (const message of observeClaudeMessages(
837
+ runClaude(prompt, options, runOptions?.abortSignal ?? runOptions?.signal, runOptions),
838
+ telemetry
839
+ )) {
736
840
  usage.record(message);
737
841
  if (message.type === "result") {
738
842
  if (message.subtype !== "success") {
739
843
  throw new Error(message.errors.join("\n") || `Claude Agent SDK failed with ${message.subtype}`);
740
844
  }
741
845
  text = message.result;
846
+ structuredOutputValue = getClaudeStructuredOutput(message);
742
847
  }
743
848
  }
744
849
  const totals = usage.totals();
850
+ const object = await getStructuredOutputFromValue(
851
+ structuredOutputValue === void 0 ? text : structuredOutputValue,
852
+ runOptions?.structuredOutput
853
+ );
745
854
  return {
746
855
  content: [{ type: "text", text }],
747
856
  finishReason: { unified: "stop", raw: "stop" },
@@ -752,10 +861,11 @@ async function runClaudeGenerate(prompt, options, telemetry, signal) {
752
861
  timestamp: /* @__PURE__ */ new Date()
753
862
  },
754
863
  providerMetadata: getClaudeProviderMetadata(options, totals),
755
- costContext: getClaudeCostContext(options, totals)
864
+ costContext: getClaudeCostContext(options, totals),
865
+ object
756
866
  };
757
867
  }
758
- function runClaudeAsMastraStream(prompt, options, runId, telemetry, signal) {
868
+ function runClaudeAsMastraStream(prompt, options, runId, telemetry, runOptions) {
759
869
  return new web.ReadableStream({
760
870
  start: async (controller) => {
761
871
  const textId = crypto.randomUUID();
@@ -763,6 +873,7 @@ function runClaudeAsMastraStream(prompt, options, runId, telemetry, signal) {
763
873
  const modelId = getModelId(options);
764
874
  const usage = createClaudeUsageCollector();
765
875
  let text = "";
876
+ let structuredOutputValue;
766
877
  let sawDelta = false;
767
878
  try {
768
879
  enqueueStartChunks(controller, {
@@ -773,7 +884,10 @@ function runClaudeAsMastraStream(prompt, options, runId, telemetry, signal) {
773
884
  modelId,
774
885
  providerMetadata: getClaudeProviderMetadata(options, usage.totals())
775
886
  });
776
- for await (const message of observeClaudeMessages(runClaude(prompt, options, signal), telemetry)) {
887
+ for await (const message of observeClaudeMessages(
888
+ runClaude(prompt, options, runOptions?.abortSignal ?? runOptions?.signal, runOptions),
889
+ telemetry
890
+ )) {
777
891
  usage.record(message);
778
892
  const delta = getTextDelta(message);
779
893
  if (delta) {
@@ -789,6 +903,7 @@ function runClaudeAsMastraStream(prompt, options, runId, telemetry, signal) {
789
903
  text += message.result;
790
904
  enqueueTextDelta(controller, runId, textId, message.result);
791
905
  }
906
+ structuredOutputValue = getClaudeStructuredOutput(message);
792
907
  }
793
908
  }
794
909
  const totals = usage.totals();
@@ -802,7 +917,11 @@ function runClaudeAsMastraStream(prompt, options, runId, telemetry, signal) {
802
917
  modelId,
803
918
  usage: usage.toLanguageModelUsage(),
804
919
  providerMetadata,
805
- costContext: getClaudeCostContext(options, totals)
920
+ costContext: getClaudeCostContext(options, totals),
921
+ object: await getStructuredOutputFromValue(
922
+ structuredOutputValue === void 0 ? text : structuredOutputValue,
923
+ runOptions?.structuredOutput
924
+ )
806
925
  });
807
926
  controller.close();
808
927
  } catch (error) {
@@ -817,11 +936,19 @@ function runClaudeAsMastraStream(prompt, options, runId, telemetry, signal) {
817
936
  }
818
937
  });
819
938
  }
820
- function runClaude(prompt, options, signal) {
939
+ function runClaude(prompt, options, signal, runOptions) {
821
940
  const abortController = createAbortController(signal);
822
941
  const queryOptions = {
823
- ...options.sdkOptions
942
+ ...options.sdkOptions,
943
+ ...runOptions?.sdkOptions
824
944
  };
945
+ const outputSchema = getStructuredOutputSchema(runOptions?.structuredOutput);
946
+ if (outputSchema) {
947
+ queryOptions.outputFormat = {
948
+ type: "json_schema",
949
+ schema: outputSchema
950
+ };
951
+ }
825
952
  if (abortController) {
826
953
  queryOptions.abortController = abortController;
827
954
  }
@@ -830,6 +957,12 @@ function runClaude(prompt, options, signal) {
830
957
  options: queryOptions
831
958
  });
832
959
  }
960
+ function getClaudeStructuredOutput(message) {
961
+ if (message.type !== "result") {
962
+ return void 0;
963
+ }
964
+ return message.structured_output;
965
+ }
833
966
  async function* observeClaudeMessages(messages, telemetry) {
834
967
  for await (const message of messages) {
835
968
  recordClaudeToolTelemetry(message, telemetry);