Skip to content

feat(memory): support inline json prompt injection#18652

Merged
TylerBarnes merged 3 commits into
mainfrom
feat/inline-json-injection
Jun 30, 2026
Merged

feat(memory): support inline json prompt injection#18652
TylerBarnes merged 3 commits into
mainfrom
feat/inline-json-injection

Conversation

@TylerBarnes

@TylerBarnes TylerBarnes commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

Adds a new structuredOutput.jsonPromptInjection: 'inline' mode.

Before this PR, JSON prompt injection put the structured-output schema instructions in the system prompt (true / 'system'). That works, but it changes the system prompt for each schema and can defeat provider prompt caching.

This PR adds an inline mode that appends the JSON instructions to the latest user message instead, keeping the leading system prompt stable and more cache-friendly.

await agent.generate('Extract the task details', {
  structuredOutput: {
    schema: taskSchema,
    jsonPromptInjection: 'inline',
  },
});

Behavior by mode:

jsonPromptInjection: true      // inject into system prompt
jsonPromptInjection: 'system'  // inject into system prompt
jsonPromptInjection: 'inline'  // inject into latest user message

If there is no user message, inline mode adds a user message containing the JSON instructions. Native responseFormat is still skipped whenever prompt injection is enabled.

The structured-output fallback helpers preserve explicit 'inline' / 'system' settings when retrying, instead of coercing every retry to true.

Test plan

Stack

ELI5

This change lets the app add JSON “instructions” in a new “inline” way, by attaching them to the user’s message instead of always putting them in the system message. That helps keep the system prompt stable, which can work better with providers that cache prompts.

Summary

  • Added support for structuredOutput.jsonPromptInjection: 'inline' alongside true and 'system'.
  • Updated structured output handling so:
    • true / 'system' inject JSON instructions into the system prompt
    • 'inline' appends them to the latest user message
    • if there is no user message, inline mode creates one
  • Kept native responseFormat disabled whenever prompt injection is enabled.
  • Preserved explicit 'inline' and 'system' settings during JSON fallback retries.
  • Added the new runtime feature flag json-prompt-injection:inline.
  • Expanded tests to cover inline injection, system injection, missing-user-message behavior, and feature flag exposure.

@changeset-bot

changeset-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 26a8be6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
@mastra/core Minor
mastracode Patch
@mastra/mcp-docs-server Patch
@internal/playground Patch
@mastra/client-js Patch
@mastra/opencode Patch
@mastra/longmemeval Patch
mastra Patch
@mastra/deployer-cloud Minor
@mastra/react Patch
@mastra/playground-ui Patch
@mastra/server Minor
@mastra/deployer Minor
create-mastra Patch
@mastra/express Patch
@mastra/fastify Patch
@mastra/hono Patch
@mastra/koa Patch
@mastra/nestjs Patch
@mastra/next Patch
@mastra/tanstack-start Patch
@mastra/temporal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ad8eed8f-4830-45f8-8a99-b952adaad847

📥 Commits

Reviewing files that changed from the base of the PR and between 927182f and 26a8be6.

📒 Files selected for processing (3)
  • .changeset/quick-dingos-eat.md
  • packages/core/src/agent/utils.test.ts
  • packages/core/src/stream/aisdk/v5/execute.test.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/quick-dingos-eat.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/agent/utils.test.ts
  • packages/core/src/stream/aisdk/v5/execute.test.ts

Walkthrough

Extends jsonPromptInjection from a boolean to boolean | 'system' | 'inline'. The 'inline' mode appends the JSON schema instruction to the latest user message instead of the system message. Retry fallbacks now preserve the existing mode. A 'json-prompt-injection:inline' feature flag is registered in coreFeatures.

Changes

Inline JSON Prompt Injection

Layer / File(s) Summary
Type and feature flag changes
packages/core/src/agent/types.ts, packages/core/src/agent/durable/types.ts, packages/core/src/processors/processors/structured-output.ts, packages/core/src/features/index.ts, .changeset/quick-dingos-eat.md
jsonPromptInjection type widened to boolean | 'system' | 'inline' across relevant interfaces; 'json-prompt-injection:inline' added to coreFeatures; release notes document inline injection.
Inline injection implementation
packages/core/src/stream/aisdk/v5/execute.ts
Adds buildJsonInstruction and injectJsonInstructionIntoLatestUserMessage; direct mode now derives injectionMode and branches between inline and system injection paths; strict JSON schema and responseFormat are gated on !injectionMode.
Retry fallback mode preservation
packages/core/src/agent/utils.ts
tryGenerateWithJsonFallback and tryStreamWithJsonFallback now preserve 'inline'/'system' on retry instead of always overwriting with true.
Tests
packages/core/src/stream/aisdk/v5/execute.test.ts, packages/core/src/agent/utils.test.ts
New tests cover feature flag presence, system/inline injection placement, responseFormat absence in inline mode, auto-added user message when none exists, and retry mode preservation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • mastra-ai/mastra#17046: Wires jsonPromptInjection into the tryGenerateWithJsonFallback path; this PR extends that same path to preserve 'inline'/'system' modes on retry.

Suggested reviewers

  • abhiaiyer91
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise, specific, and accurately describes the inline JSON prompt injection support added in this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/inline-json-injection

Comment @coderabbitai help to get the list of available commands.

@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mastra-docs-1.x Ready Ready Preview, Comment Jun 30, 2026 4:42pm
mastra-playground-ui Ready Ready Preview, Comment Jun 30, 2026 4:42pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
mastra-studio-preview Ignored Ignored Preview Jun 30, 2026 4:42pm

Request Review

@dane-ai-mastra

dane-ai-mastra Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

PR triage

Linked issue check skipped for core contributor @TylerBarnes.


PR complexity score

Factor Value Score impact
Files changed 9 +18
Lines changed 281 +15
Author merged PRs 566 -20
Test files changed Yes -10
Final score 3

Applied label: complexity: low


Changed test gate

Changed tests failed against the base branch as expected.

Label: tests: green ✅

@dane-ai-mastra dane-ai-mastra Bot added the tests: green ✅ Changed tests failed against base as expected label Jun 29, 2026
Base automatically changed from refactor/processor-agent-context to main June 30, 2026 07:27
TylerBarnes and others added 2 commits June 30, 2026 08:49
Widens the jsonPromptInjection type from boolean to boolean | 'system' | 'inline'. The 'inline' mode injects JSON schema instructions into the latest user message instead of the system prompt, preserving prompt cache for providers with prefix-based caching. Adds feature flag 'json-prompt-injection:inline' for runtime capability detection.

Co-Authored-By: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
Co-Authored-By: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/quick-dingos-eat.md:
- Around line 5-13: This changeset reads too much like internal implementation
detail and is missing a user-facing API example. Update the entry to highlight
the developer outcome of using structuredOutput.jsonPromptInjection: 'inline'
and add a short public example showing agent.generate with
structuredOutput.schema and jsonPromptInjection set to 'inline'. Keep the
wording focused on what changes for users rather than the runtime feature flag
or type widening, so the changeset clearly communicates the new API behavior.

In `@packages/core/src/agent/utils.test.ts`:
- Around line 59-72: Add a retry-preservation test for the explicit 'system'
jsonPromptInjection mode in tryGenerateWithJsonFallback(), since the current
case only verifies 'inline'. Mirror the existing test in utils.test.ts by
calling makeAgent(generate) with structuredOutput.jsonPromptInjection set to
'system', forcing the retry path, and asserting the second generate call still
receives 'system' on structuredOutput.jsonPromptInjection.

In `@packages/core/src/stream/aisdk/v5/execute.test.ts`:
- Around line 115-122: The inline injection test in execute.test.ts only
verifies that the schema text is added to the last user message, but it does not
confirm the original user prompt is preserved. Update the test around the
capturedPrompt assertions in the v5 execute flow to also assert that the final
user turn still contains the original text from the latest user message (for
example, the prompt that was being appended to), ensuring the
append-to-latest-user-message behavior is validated rather than overwrite
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 677fd6da-caed-4ccf-b9e3-518583dc7a5f

📥 Commits

Reviewing files that changed from the base of the PR and between af17a30 and 927182f.

📒 Files selected for processing (9)
  • .changeset/quick-dingos-eat.md
  • packages/core/src/agent/durable/types.ts
  • packages/core/src/agent/types.ts
  • packages/core/src/agent/utils.test.ts
  • packages/core/src/agent/utils.ts
  • packages/core/src/features/index.ts
  • packages/core/src/processors/processors/structured-output.ts
  • packages/core/src/stream/aisdk/v5/execute.test.ts
  • packages/core/src/stream/aisdk/v5/execute.ts

Comment thread .changeset/quick-dingos-eat.md Outdated
Comment thread packages/core/src/agent/utils.test.ts
Comment thread packages/core/src/stream/aisdk/v5/execute.test.ts
Co-Authored-By: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
@TylerBarnes TylerBarnes merged commit e84e791 into main Jun 30, 2026
108 checks passed
@TylerBarnes TylerBarnes deleted the feat/inline-json-injection branch June 30, 2026 17:17
TylerBarnes added a commit that referenced this pull request Jun 30, 2026
## Summary

Adds the observational memory extractor pipeline.

Extractors let OM capture structured values alongside observations,
persist selected values into thread metadata, and carry extraction
failures through the OM lifecycle. Extractor instructions and schemas
can be static or resolved from runtime context, so extraction can adapt
to the active agent and thread.

```ts
observationalMemory: {
  enabled: true,
  observation: {
    extract: [
      new Extractor({
        slug: 'priority',
        name: 'Priority',
        schema: z.enum(['low', 'medium', 'high']),
        instructions: 'Extract the user priority when it changes.',
      }),
    ],
  },
}
```

## Test plan

- `pnpm --filter ./packages/memory test:unit -- --run
src/processors/observational-memory/__tests__/extractor.test.ts
src/processors/observational-memory/__tests__/observational-memory-api.test.ts
--reporter=dot --bail 1`
- `pnpm --filter ./packages/memory check`
- Stack rebase verified linear against #18652

## Stack

- Previous: #18652
- Next: #18654


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
ELI5: This PR makes “observational memory” not only remember what
happened, but also automatically pull out specific structured facts
(like a user’s priority), save them on the thread, and reuse them later.
It also adds an `Extractor` API so you can define how those facts are
detected, validated, and what happens when extraction fails.

### Summary
- Added a public `Extractor` API for Observational Memory with:
- **inline (XML/tag-based)** and **structured (Zod/schema-based)**
extraction modes
- slug validation, runtime-resolved/dynamic `instructions` and optional
`schema`
- per-extractor `onExtracted` hooks to normalize/transform values and
record failures safely.
- Extended Observational Memory configuration with extraction pipelines:
- `observationalMemory.observation.extract` and
`observationalMemory.reflection.extract`
- built-in extractors (current task, suggested response, thread title)
composed with user extractors.
- Implemented extraction end-to-end across observer/reflector:
- prompt generation includes extractor output sections and optional
“prior extracted values”
- parsing supports extracting values from model output while stripping
extractor sections
- structured extraction retries/fallback behavior is handled, and
extracted values are validated/merged.
- Persisted extracted values into thread observational memory metadata
under `threadOMMetadata.extracted`, including carry-forward of prior
extracted values into subsequent observer/reflector runs.
- Propagated extraction failures through the OM lifecycle (without
blocking successful extractions):
- added `extractionFailures` alongside `extractedValues` in OM end
markers and marker/telemetry payloads.
- Updated exports/types and documentation:
- new/extended types for `extractedValues` and `extractionFailures`
across OM configs, runners, and storage
- added Observational Memory docs sections for “Extractors” plus an
“Extractor API” reference.
- Added tests covering extractor logic and Observational Memory
persistence across:
- extractor unit behavior (inline/structured parsing, retries, hooks,
prompt composition)
- observational-memory API behavior (observe/reflect/buffer) and thread
metadata persistence
- marker schema changes and additional observational-memory lifecycle
assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
wardpeet pushed a commit that referenced this pull request Jul 1, 2026
## Summary

Adds a new `structuredOutput.jsonPromptInjection: 'inline'` mode.

Before this PR, JSON prompt injection put the structured-output schema
instructions in the system prompt (`true` / `'system'`). That works, but
it changes the system prompt for each schema and can defeat provider
prompt caching.

This PR adds an inline mode that appends the JSON instructions to the
latest user message instead, keeping the leading system prompt stable
and more cache-friendly.

```ts
await agent.generate('Extract the task details', {
  structuredOutput: {
    schema: taskSchema,
    jsonPromptInjection: 'inline',
  },
});
```

Behavior by mode:

```ts
jsonPromptInjection: true      // inject into system prompt
jsonPromptInjection: 'system'  // inject into system prompt
jsonPromptInjection: 'inline'  // inject into latest user message
```

If there is no user message, inline mode adds a user message containing
the JSON instructions. Native `responseFormat` is still skipped whenever
prompt injection is enabled.

The structured-output fallback helpers preserve explicit `'inline'` /
`'system'` settings when retrying, instead of coercing every retry to
`true`.

## Test plan

- Stack rebase verified linear against #18651
- Covered by downstream memory/core checks in the stack

## Stack

- Previous: #18651
- Next: #18653


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This change lets the app add JSON “instructions” in a new “inline” way,
by attaching them to the user’s message instead of always putting them
in the system message. That helps keep the system prompt stable, which
can work better with providers that cache prompts.

## Summary
- Added support for `structuredOutput.jsonPromptInjection: 'inline'`
alongside `true` and `'system'`.
- Updated structured output handling so:
  - `true` / `'system'` inject JSON instructions into the system prompt
  - `'inline'` appends them to the latest user message
  - if there is no user message, inline mode creates one
- Kept native `responseFormat` disabled whenever prompt injection is
enabled.
- Preserved explicit `'inline'` and `'system'` settings during JSON
fallback retries.
- Added the new runtime feature flag `json-prompt-injection:inline`.
- Expanded tests to cover inline injection, system injection,
missing-user-message behavior, and feature flag exposure.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
wardpeet pushed a commit that referenced this pull request Jul 1, 2026
## Summary

Adds the observational memory extractor pipeline.

Extractors let OM capture structured values alongside observations,
persist selected values into thread metadata, and carry extraction
failures through the OM lifecycle. Extractor instructions and schemas
can be static or resolved from runtime context, so extraction can adapt
to the active agent and thread.

```ts
observationalMemory: {
  enabled: true,
  observation: {
    extract: [
      new Extractor({
        slug: 'priority',
        name: 'Priority',
        schema: z.enum(['low', 'medium', 'high']),
        instructions: 'Extract the user priority when it changes.',
      }),
    ],
  },
}
```

## Test plan

- `pnpm --filter ./packages/memory test:unit -- --run
src/processors/observational-memory/__tests__/extractor.test.ts
src/processors/observational-memory/__tests__/observational-memory-api.test.ts
--reporter=dot --bail 1`
- `pnpm --filter ./packages/memory check`
- Stack rebase verified linear against #18652

## Stack

- Previous: #18652
- Next: #18654


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
ELI5: This PR makes “observational memory” not only remember what
happened, but also automatically pull out specific structured facts
(like a user’s priority), save them on the thread, and reuse them later.
It also adds an `Extractor` API so you can define how those facts are
detected, validated, and what happens when extraction fails.

### Summary
- Added a public `Extractor` API for Observational Memory with:
- **inline (XML/tag-based)** and **structured (Zod/schema-based)**
extraction modes
- slug validation, runtime-resolved/dynamic `instructions` and optional
`schema`
- per-extractor `onExtracted` hooks to normalize/transform values and
record failures safely.
- Extended Observational Memory configuration with extraction pipelines:
- `observationalMemory.observation.extract` and
`observationalMemory.reflection.extract`
- built-in extractors (current task, suggested response, thread title)
composed with user extractors.
- Implemented extraction end-to-end across observer/reflector:
- prompt generation includes extractor output sections and optional
“prior extracted values”
- parsing supports extracting values from model output while stripping
extractor sections
- structured extraction retries/fallback behavior is handled, and
extracted values are validated/merged.
- Persisted extracted values into thread observational memory metadata
under `threadOMMetadata.extracted`, including carry-forward of prior
extracted values into subsequent observer/reflector runs.
- Propagated extraction failures through the OM lifecycle (without
blocking successful extractions):
- added `extractionFailures` alongside `extractedValues` in OM end
markers and marker/telemetry payloads.
- Updated exports/types and documentation:
- new/extended types for `extractedValues` and `extractionFailures`
across OM configs, runners, and storage
- added Observational Memory docs sections for “Extractors” plus an
“Extractor API” reference.
- Added tests covering extractor logic and Observational Memory
persistence across:
- extractor unit behavior (inline/structured parsing, retries, hooks,
prompt composition)
- observational-memory API behavior (observe/reflect/buffer) and thread
metadata persistence
- marker schema changes and additional observational-memory lifecycle
assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

complexity: low Low-complexity PR tests: green ✅ Changed tests failed against base as expected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants