Skip to content

feat(memory): add observational memory extractors#18653

Open
TylerBarnes wants to merge 2 commits into
feat/inline-json-injectionfrom
feat/om-extractors
Open

feat(memory): add observational memory extractors#18653
TylerBarnes wants to merge 2 commits into
feat/inline-json-injectionfrom
feat/om-extractors

Conversation

@TylerBarnes

@TylerBarnes TylerBarnes commented Jun 29, 2026

Copy link
Copy Markdown
Member

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.

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 feat(memory): support inline json prompt injection #18652

Stack

Introduces a public Extractor API for Observational Memory with inline XML extraction and structured follow-up extraction modes. Persists extracted values into thread OM metadata, carries them forward into future observer/reflector prompts, and exposes extraction results in OM streaming markers.

Also threads agent context through processor execution so extractor hooks can access the running agent, updates storage types with extraction fields on BufferedObservationChunk, and documents the new API with focused unit and integration coverage.

Co-Authored-By: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
@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 29, 2026 11:59pm
mastra-playground-ui Ready Ready Preview, Comment Jun 29, 2026 11:59pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
mastra-studio-preview Ignored Ignored Preview Jun 29, 2026 11:59pm

Request Review

@changeset-bot

changeset-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7fe1030

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

This PR includes changesets to release 25 packages
Name Type
@mastra/memory Minor
@mastra/core Patch
mastracode Patch
@mastra/agent-builder Patch
@mastra/editor Patch
@internal/playground Patch
@mastra/express Patch
@mastra/fastify Patch
@mastra/hono Patch
@mastra/koa Patch
@mastra/nestjs Patch
@mastra/opencode Patch
@mastra/longmemeval Patch
@mastra/mcp-docs-server Patch
@mastra/client-js Patch
@mastra/server Patch
mastra Patch
@mastra/deployer-cloud Patch
@mastra/react Patch
@mastra/playground-ui Patch
@mastra/deployer Patch
create-mastra 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

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 99324a5b-c52d-4f93-9614-15db93e6ad5f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/om-extractors

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

@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 34 +60
Lines changed 2970 +60
Author merged PRs 564 -20
Test files changed Yes -10
Final score 90

Applied label: complexity: critical


Changed test gate

Changed tests failed against the base branch as expected.

Label: tests: green ✅

@socket-security

socket-security Bot commented Jun 29, 2026

Copy link
Copy Markdown

Dependency limit exceeded — report not shown.

This pull request scan exceeded the 10,000-dependency limit applied to this scan, so the results are incomplete and may be inaccurate. To avoid reporting false positives, Socket has not posted a report.

Upgrade your plan to raise the dependency limit and get complete reports, or view the partial scan in the dashboard.

Socket is always free for open source. If this is a non-commercial open source project, contact us to request a free Team account.

@dane-ai-mastra dane-ai-mastra Bot added the tests: green ✅ Changed tests failed against base as expected label Jun 29, 2026
})
```

Extractor behavior is derived from whether you provide a schema. Schema-backed extractors run as a follow-up structured output call after the Observer or Reflector finishes. The follow-up call adds model latency and usage, but it uses the same temporary in-memory Observer or Reflector thread so providers that support prompt caching can reuse the shared prompt prefix. Schema-less extractors are inline string extractors emitted directly in the Observer or Reflector response.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this is overly explanatory. We can just say that

  • adding a schema makes it do a follow up structured output request (don't need to talk about tradeoffs)
  • it should be assumed that we're preserving prompt caching, don't need to over explain internals
  • yes schema less extractors are inline in the first request

})
```

By default, OM includes the previous extraction in later extraction prompts. Set `includePreviousExtraction: false` for values that should only come from the current OM run.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

wording is a bit confusing. we should say something like: when its false the observer does not see the last extracted value (or something)

```typescript title="src/mastra/agents/agent.ts"
new Extractor({
name: 'Latest blocker',
instructions: 'Extract only the latest blocker mentioned in this conversation window.',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

weird instructions. should be more like: extract any blockers the agent is running into

Comment on lines +251 to +271
Use `WorkingMemoryExtractor` when the Observer or Reflector should update working memory instead of relying on the main agent to call the working memory tool:

```typescript title="src/mastra/agents/agent.ts"
import { Memory, WorkingMemoryExtractor } from '@mastra/memory'

const memory = new Memory({
options: {
workingMemory: {
enabled: true,
injectTools: false,
},
observationalMemory: {
observation: {
extract: [new WorkingMemoryExtractor()],
},
},
},
})
```

`WorkingMemoryExtractor` uses the normal extractor pipeline. It reads the active working memory template or schema, uses structured extraction when working memory has a JSON schema, writes updates through the memory instance, and doesn't duplicate the value under OM extracted metadata.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this doesn't belong here, we should add a note about working memory here and start with the sugar setting, then add a note about what that configures internally. But this should be in a working memory section.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We should probably also update the working memory page linking over here

},
{
name: 'extract',
type: 'Extractor<any>[]',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

why any type?

},
{
name: 'extract',
type: 'Extractor<any>[]',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

same

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

also this section is duplicated?

Comment on lines +458 to +469
Use `WorkingMemoryExtractor` when OM should update working memory. Set `workingMemory.injectTools` to `false` when the main agent shouldn't receive the working memory update tool.

```typescript title="src/mastra/agents/agent.ts"
import { Memory, WorkingMemoryExtractor } from '@mastra/memory'

const memory = new Memory({
options: {
workingMemory: {
enabled: true,
injectTools: false,
},
observationalMemory: {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this is out of date, and not sure it even belongs on this page at all?

}

export async function createTemporaryOmMemoryContext(prefix: string): Promise<TemporaryOmMemoryContext> {
const { Memory } = await import('../../index');

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

why a dynamic import?

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: critical Critical-complexity PR Documentation Improvements or additions to documentation tests: green ✅ Changed tests failed against base as expected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant