@mastra/memory 1.31.0-alpha.1 → 1.31.0-alpha.2

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.
@@ -3,7 +3,7 @@ name: mastra-memory
3
3
  description: Documentation for @mastra/memory. Use when working with @mastra/memory APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/memory"
6
- version: "1.31.0-alpha.1"
6
+ version: "1.31.0-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.31.0-alpha.1",
2
+ "version": "1.31.0-alpha.2",
3
3
  "package": "@mastra/memory",
4
4
  "exports": {},
5
5
  "modules": {
@@ -849,6 +849,39 @@ Transform hooks are always awaited, on every path (manual `observe()`/`reflect()
849
849
 
850
850
  Because hooks receive `threadId` and `resourceId`, you can also use them to update [working memory](https://mastra.ai/docs/memory/working-memory) via `memory.updateWorkingMemory()` during a cycle. These external updates aren't atomic with the OM text commit.
851
851
 
852
+ ### Redact skill results
853
+
854
+ Agent skills are injected into the agent as tools (`skill`, `skill_search`, `skill_read`). Their results contain the skill's full instructions or file contents, so without redaction the Observer re-observes that text every time a skill is used. `skillResultRedactor()` is a ready-made `beforeObservation` hook that replaces those results with a placeholder and leaves everything else in place. The tool call survives, so the Observer still records which skill was used and what it was called with.
855
+
856
+ ```typescript
857
+ import { Memory } from '@mastra/memory'
858
+ import { skillResultRedactor } from '@mastra/memory/hooks'
859
+
860
+ const memory = new Memory({
861
+ options: {
862
+ observationalMemory: {
863
+ model: 'google/gemini-2.5-flash',
864
+ hooks: {
865
+ beforeObservation: skillResultRedactor(),
866
+ },
867
+ },
868
+ },
869
+ })
870
+ ```
871
+
872
+ Pass `toolNames` to redact results from a different set of tools. Because a hook is a function over the messages, it composes with your own transforms by chaining the outputs. Await each chained hook so an async one isn't discarded:
873
+
874
+ ```typescript
875
+ const dropSkillResults = skillResultRedactor()
876
+
877
+ hooks: {
878
+ beforeObservation: async input => {
879
+ const messages = (await dropSkillResults(input))?.messages ?? input.messages
880
+ return { messages: messages.filter(m => m.role !== 'signal') }
881
+ },
882
+ }
883
+ ```
884
+
852
885
  ## Migrating existing threads
853
886
 
854
887
  No manual migration needed. OM reads existing messages and observes them lazily when thresholds are exceeded.
@@ -73,9 +73,9 @@ OM performs thresholding with fast local token estimation. Text uses `tokenx`, a
73
73
 
74
74
  **observation.maxTokensPerBatch** (`number`): Maximum tokens per batch when observing multiple threads in resource scope. Threads are chunked into batches of this size and processed in parallel. Lower values mean more parallelism but more API calls.
75
75
 
76
- **observation.modelSettings** (`ObservationalMemoryModelSettings`): Model settings for the Observer agent. The maxOutputTokens: 100\_000 default is only applied with default model selection (no model set, "default", or a ModelByInputTokens selector). Custom models get no maxOutputTokens default.
76
+ **observation.modelSettings** (`ObservationalMemoryModelSettings`): Model settings for the Observer agent. The temperature: 0.3 default is only applied when the resolved model is known to support temperature. The maxOutputTokens: 100\_000 default is only applied with default model selection (no model set, "default", or a ModelByInputTokens selector). Custom models get no maxOutputTokens default.
77
77
 
78
- **observation.modelSettings.temperature** (`number`): Temperature for generation. Lower values produce more consistent output.
78
+ **observation.modelSettings.temperature** (`number`): Temperature for generation. Lower values produce more consistent output. The 0.3 default is only applied when the resolved model is known to support temperature.
79
79
 
80
80
  **observation.modelSettings.maxOutputTokens** (`number`): Maximum output tokens. Set high to prevent truncation of observations. The 100000 default is only applied with default model selection; custom models get no default.
81
81
 
@@ -107,9 +107,9 @@ OM performs thresholding with fast local token estimation. Text uses `tokenx`, a
107
107
 
108
108
  **reflection.observationTokens** (`number`): Token count of observations that triggers reflection. When observation tokens exceed this threshold, the Reflector agent is called to condense them.
109
109
 
110
- **reflection.modelSettings** (`ObservationalMemoryModelSettings`): Model settings for the Reflector agent. The maxOutputTokens: 100\_000 default is only applied with default model selection (no model set, "default", or a ModelByInputTokens selector). Custom models get no maxOutputTokens default.
110
+ **reflection.modelSettings** (`ObservationalMemoryModelSettings`): Model settings for the Reflector agent. The temperature: 0 default is only applied when the resolved model is known to support temperature. The maxOutputTokens: 100\_000 default is only applied with default model selection (no model set, "default", or a ModelByInputTokens selector). Custom models get no maxOutputTokens default.
111
111
 
112
- **reflection.modelSettings.temperature** (`number`): Temperature for generation. Lower values produce more consistent output.
112
+ **reflection.modelSettings.temperature** (`number`): Temperature for generation. Lower values produce more consistent output. The 0 default is only applied when the resolved model is known to support temperature.
113
113
 
114
114
  **reflection.modelSettings.maxOutputTokens** (`number`): Maximum output tokens. Set high to prevent truncation of observations. The 100000 default is only applied with default model selection; custom models get no default.
115
115
 
@@ -883,6 +883,36 @@ const selector = new ModelByInputTokens({
883
883
 
884
884
  **getThresholds** (`() => number[]`): Returns the configured thresholds in ascending order. Useful for introspection.
885
885
 
886
+ ### skillResultRedactor
887
+
888
+ `skillResultRedactor` builds a `beforeObservation` transform hook that redacts the results of the built-in Agent Skills tools (`skill`, `skill_search`, and `skill_read`) before the Observer model sees them. Each result is replaced with a placeholder while the tool call is kept, so the Observer still records which skill was used and what it was called with, without the skill text.
889
+
890
+ ```typescript
891
+ import { Memory } from '@mastra/memory'
892
+ import { skillResultRedactor } from '@mastra/memory/hooks'
893
+
894
+ const memory = new Memory({
895
+ options: {
896
+ observationalMemory: {
897
+ model: 'google/gemini-2.5-flash',
898
+ hooks: {
899
+ beforeObservation: skillResultRedactor(),
900
+ },
901
+ },
902
+ },
903
+ })
904
+ ```
905
+
906
+ #### Parameters
907
+
908
+ **toolNames** (`readonly string[]`): Tool names whose results are redacted. Defaults to the built-in skill tools: skill, skill\_search, and skill\_read. Use this to redact a different set of tool results.
909
+
910
+ #### Returns
911
+
912
+ `(input: { messages: MastraDBMessage[] } & ObserveHookContext) => { messages: MastraDBMessage[] } | undefined`
913
+
914
+ The hook returns messages with matching tool results replaced by a placeholder, or `undefined` when no message matched (which passes the payload through unchanged). Tool calls, arguments, and every other message are left as they are.
915
+
886
916
  ### Related
887
917
 
888
918
  - [Observational Memory](https://mastra.ai/docs/memory/observational-memory)
package/dist/hooks.cjs ADDED
@@ -0,0 +1,158 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/processors/observational-memory/hooks.ts
3
+ /**
4
+ * Tool ids of the built-in Agent Skills tools created by `createSkillTools()`
5
+ * in `@mastra/core` (`packages/core/src/workspace/skills/tools.ts`).
6
+ */
7
+ const SKILL_TOOL_NAMES = [
8
+ "skill",
9
+ "skill_search",
10
+ "skill_read"
11
+ ];
12
+ /**
13
+ * Written in place of a redacted tool result. The Observer still records the
14
+ * call and its outcome; only the payload is replaced.
15
+ */
16
+ const REDACTED_TOOL_RESULT = "[tool result omitted]";
17
+ function isRedactableToolResult(part, toolNames) {
18
+ if (part?.type !== "tool-invocation") return false;
19
+ if (part.toolInvocation.state !== "result") return false;
20
+ const toolName = part.toolInvocation.toolName;
21
+ if (typeof toolName !== "string" || !toolNames.has(toolName)) return false;
22
+ return part.toolInvocation.result !== void 0 || hasStoredModelOutput(part);
23
+ }
24
+ function hasStoredModelOutput(part) {
25
+ if (part?.type !== "tool-invocation") return false;
26
+ const mastra = part.providerMetadata?.mastra;
27
+ return !!mastra && typeof mastra === "object" && "modelOutput" in mastra;
28
+ }
29
+ /**
30
+ * Legacy messages carry tool calls in a second `toolInvocations` array, which
31
+ * `AIV5Adapter` falls back to when `parts` holds no tool invocation
32
+ * (`AIV5Adapter.ts:264`). Leave it alone and a redacted result can be
33
+ * resurrected from that array downstream. Only rewritten when it actually
34
+ * holds a matching result, so non-legacy messages keep their array by
35
+ * reference.
36
+ */
37
+ function redactLegacyToolInvocations(toolInvocations, toolNames) {
38
+ if (!Array.isArray(toolInvocations)) return {
39
+ toolInvocations,
40
+ changed: false
41
+ };
42
+ let changed = false;
43
+ const next = toolInvocations.map((invocation) => {
44
+ if (invocation?.state !== "result" || typeof invocation.toolName !== "string" || !toolNames.has(invocation.toolName) || invocation.result === void 0) return invocation;
45
+ changed = true;
46
+ return {
47
+ ...invocation,
48
+ result: REDACTED_TOOL_RESULT
49
+ };
50
+ });
51
+ return changed ? {
52
+ toolInvocations: next,
53
+ changed: true
54
+ } : {
55
+ toolInvocations,
56
+ changed: false
57
+ };
58
+ }
59
+ /**
60
+ * Replace the result payload of a tool invocation with a placeholder, keeping
61
+ * the call's identity (tool name, arguments, terminal state). The Observer
62
+ * still records that the tool ran and what it was called with.
63
+ */
64
+ function redactToolResult(part) {
65
+ const redacted = {
66
+ ...part,
67
+ toolInvocation: {
68
+ ...part.toolInvocation,
69
+ result: REDACTED_TOOL_RESULT
70
+ }
71
+ };
72
+ if (hasStoredModelOutput(part)) {
73
+ const providerMetadata = part.providerMetadata ?? {};
74
+ const mastra = providerMetadata.mastra;
75
+ return {
76
+ ...redacted,
77
+ providerMetadata: {
78
+ ...providerMetadata,
79
+ mastra: {
80
+ ...mastra,
81
+ modelOutput: REDACTED_TOOL_RESULT
82
+ }
83
+ }
84
+ };
85
+ }
86
+ return redacted;
87
+ }
88
+ /**
89
+ * Build a `beforeObservation` hook that keeps Agent Skills results out of the
90
+ * Observer payload.
91
+ *
92
+ * The `skill` tool returns a skill's instructions verbatim as its result, and
93
+ * `skill_read` / `skill_search` return skill file contents, so without redaction
94
+ * the Observer re-observes the full skill text every time a skill is used.
95
+ * `skillResultRedactor()` replaces the result payload with a placeholder and
96
+ * leaves the tool call in place, so the Observer still records which skill was
97
+ * used without the skill text.
98
+ *
99
+ * ```typescript
100
+ * const memory = new Memory({
101
+ * options: {
102
+ * observationalMemory: {
103
+ * model: 'google/gemini-2.5-flash',
104
+ * hooks: { beforeObservation: skillResultRedactor() },
105
+ * },
106
+ * },
107
+ * });
108
+ * ```
109
+ *
110
+ * Because a hook is a function over the messages, this composes with your own
111
+ * transforms by chaining the outputs. Await each chained hook so an async one
112
+ * doesn't resolve to a promise that gets discarded:
113
+ *
114
+ * ```typescript
115
+ * const dropSkillResults = skillResultRedactor();
116
+ *
117
+ * hooks: {
118
+ * beforeObservation: async input => {
119
+ * const messages = (await dropSkillResults(input))?.messages ?? input.messages;
120
+ * return { messages: messages.filter(m => m.role !== 'signal') };
121
+ * },
122
+ * }
123
+ * ```
124
+ */
125
+ function skillResultRedactor(options) {
126
+ const toolNames = new Set(options?.toolNames ?? SKILL_TOOL_NAMES);
127
+ return ({ messages }) => {
128
+ let changed = false;
129
+ const transformed = messages.map((message) => {
130
+ const parts = message.content?.parts;
131
+ let messageChanged = false;
132
+ const legacy = redactLegacyToolInvocations(message.content?.toolInvocations, toolNames);
133
+ if (legacy.changed) messageChanged = true;
134
+ let nextParts = parts;
135
+ if (Array.isArray(parts)) nextParts = parts.map((part) => {
136
+ if (!isRedactableToolResult(part, toolNames)) return part;
137
+ messageChanged = true;
138
+ return redactToolResult(part);
139
+ });
140
+ if (!messageChanged) return message;
141
+ changed = true;
142
+ return {
143
+ ...message,
144
+ content: {
145
+ ...message.content,
146
+ parts: nextParts,
147
+ toolInvocations: legacy.toolInvocations
148
+ }
149
+ };
150
+ });
151
+ return changed ? { messages: transformed } : void 0;
152
+ };
153
+ }
154
+ //#endregion
155
+ exports.SKILL_TOOL_NAMES = SKILL_TOOL_NAMES;
156
+ exports.skillResultRedactor = skillResultRedactor;
157
+
158
+ //# sourceMappingURL=hooks.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.cjs","names":[],"sources":["../src/processors/observational-memory/hooks.ts"],"sourcesContent":["import type { MastraDBMessage } from '@mastra/core/agent';\n\nimport type { ObserveTransformHooks } from './types';\n\ntype MessagePart = MastraDBMessage['content']['parts'][number];\n\ntype ToolInvocationPart = Extract<MessagePart, { type: 'tool-invocation' }>;\n\ntype BeforeObservationHook = NonNullable<ObserveTransformHooks['beforeObservation']>;\n\ntype ToolInvocations = NonNullable<MastraDBMessage['content']['toolInvocations']>;\ntype StoredToolInvocation = ToolInvocations[number];\n\n/**\n * Tool ids of the built-in Agent Skills tools created by `createSkillTools()`\n * in `@mastra/core` (`packages/core/src/workspace/skills/tools.ts`).\n */\nexport const SKILL_TOOL_NAMES = ['skill', 'skill_search', 'skill_read'] as const;\n\n/**\n * A `beforeObservation` transform hook: it only rewrites messages. It receives\n * the messages about to be sent to the Observer and returns `{ messages }` to\n * replace them, or `undefined` to pass the payload through unchanged.\n */\nexport type ObserverMessageTransform = (\n ...args: Parameters<BeforeObservationHook>\n) => { messages: MastraDBMessage[] } | undefined;\n\nexport interface SkillResultRedactorOptions {\n /**\n * Tool names whose results are redacted. Defaults to\n * {@link SKILL_TOOL_NAMES}.\n */\n toolNames?: readonly string[];\n}\n\n/**\n * Written in place of a redacted tool result. The Observer still records the\n * call and its outcome; only the payload is replaced.\n */\nconst REDACTED_TOOL_RESULT = '[tool result omitted]';\n\nfunction isRedactableToolResult(part: MessagePart, toolNames: Set<string>): part is ToolInvocationPart {\n if (part?.type !== 'tool-invocation') return false;\n // Only `state: 'result'` parts render a `Tool Result <name>` body, so only\n // those carry the tool's output.\n if (part.toolInvocation.state !== 'result') return false;\n const toolName = part.toolInvocation.toolName;\n if (typeof toolName !== 'string' || !toolNames.has(toolName)) return false;\n // Nothing to redact when the tool returned no payload.\n return part.toolInvocation.result !== undefined || hasStoredModelOutput(part);\n}\n\nfunction hasStoredModelOutput(part: MessagePart): boolean {\n if (part?.type !== 'tool-invocation') return false;\n const mastra = part.providerMetadata?.mastra;\n return !!mastra && typeof mastra === 'object' && 'modelOutput' in mastra;\n}\n\n/**\n * Legacy messages carry tool calls in a second `toolInvocations` array, which\n * `AIV5Adapter` falls back to when `parts` holds no tool invocation\n * (`AIV5Adapter.ts:264`). Leave it alone and a redacted result can be\n * resurrected from that array downstream. Only rewritten when it actually\n * holds a matching result, so non-legacy messages keep their array by\n * reference.\n */\nfunction redactLegacyToolInvocations(\n toolInvocations: ToolInvocations | undefined,\n toolNames: Set<string>,\n): { toolInvocations: ToolInvocations | undefined; changed: boolean } {\n if (!Array.isArray(toolInvocations)) return { toolInvocations, changed: false };\n\n let changed = false;\n const next: ToolInvocations = toolInvocations.map(invocation => {\n if (\n invocation?.state !== 'result' ||\n typeof invocation.toolName !== 'string' ||\n !toolNames.has(invocation.toolName) ||\n invocation.result === undefined\n ) {\n return invocation;\n }\n changed = true;\n return { ...invocation, result: REDACTED_TOOL_RESULT } as StoredToolInvocation;\n });\n\n return changed ? { toolInvocations: next, changed: true } : { toolInvocations, changed: false };\n}\n\n/**\n * Replace the result payload of a tool invocation with a placeholder, keeping\n * the call's identity (tool name, arguments, terminal state). The Observer\n * still records that the tool ran and what it was called with.\n */\nfunction redactToolResult(part: ToolInvocationPart): ToolInvocationPart {\n const redacted: ToolInvocationPart = {\n ...part,\n toolInvocation: { ...part.toolInvocation, result: REDACTED_TOOL_RESULT },\n };\n\n // `resolveToolResultValue` prefers `providerMetadata.mastra.modelOutput` over\n // `toolInvocation.result`, so a stored model output has to be replaced too.\n // Copy rather than mutate: these message objects are shared with the stored\n // history, which keeps the full result.\n if (hasStoredModelOutput(part)) {\n const providerMetadata = part.providerMetadata ?? {};\n const mastra = providerMetadata.mastra as Record<string, unknown>;\n return {\n ...redacted,\n providerMetadata: { ...providerMetadata, mastra: { ...mastra, modelOutput: REDACTED_TOOL_RESULT } },\n };\n }\n\n return redacted;\n}\n\n/**\n * Build a `beforeObservation` hook that keeps Agent Skills results out of the\n * Observer payload.\n *\n * The `skill` tool returns a skill's instructions verbatim as its result, and\n * `skill_read` / `skill_search` return skill file contents, so without redaction\n * the Observer re-observes the full skill text every time a skill is used.\n * `skillResultRedactor()` replaces the result payload with a placeholder and\n * leaves the tool call in place, so the Observer still records which skill was\n * used without the skill text.\n *\n * ```typescript\n * const memory = new Memory({\n * options: {\n * observationalMemory: {\n * model: 'google/gemini-2.5-flash',\n * hooks: { beforeObservation: skillResultRedactor() },\n * },\n * },\n * });\n * ```\n *\n * Because a hook is a function over the messages, this composes with your own\n * transforms by chaining the outputs. Await each chained hook so an async one\n * doesn't resolve to a promise that gets discarded:\n *\n * ```typescript\n * const dropSkillResults = skillResultRedactor();\n *\n * hooks: {\n * beforeObservation: async input => {\n * const messages = (await dropSkillResults(input))?.messages ?? input.messages;\n * return { messages: messages.filter(m => m.role !== 'signal') };\n * },\n * }\n * ```\n */\nexport function skillResultRedactor(options?: SkillResultRedactorOptions): ObserverMessageTransform {\n const toolNames = new Set<string>(options?.toolNames ?? SKILL_TOOL_NAMES);\n\n return ({ messages }) => {\n let changed = false;\n\n const transformed = messages.map(message => {\n const parts = message.content?.parts;\n\n let messageChanged = false;\n\n // Legacy-only messages carry no `parts` at all, so this runs before the\n // parts check rather than being skipped by it.\n const legacy = redactLegacyToolInvocations(message.content?.toolInvocations, toolNames);\n if (legacy.changed) messageChanged = true;\n\n let nextParts = parts;\n if (Array.isArray(parts)) {\n nextParts = parts.map(part => {\n if (!isRedactableToolResult(part, toolNames)) return part;\n messageChanged = true;\n return redactToolResult(part);\n });\n }\n\n if (!messageChanged) return message;\n\n changed = true;\n return {\n ...message,\n content: { ...message.content, parts: nextParts, toolInvocations: legacy.toolInvocations },\n };\n });\n\n // `undefined` means \"pass through unchanged\", so leave untouched payloads alone.\n return changed ? { messages: transformed } : undefined;\n };\n}\n"],"mappings":";;;;;;AAiBA,MAAa,mBAAmB;CAAC;CAAS;CAAgB;AAAY;;;;;AAuBtE,MAAM,uBAAuB;AAE7B,SAAS,uBAAuB,MAAmB,WAAoD;CACrG,IAAI,MAAM,SAAS,mBAAmB,OAAO;CAG7C,IAAI,KAAK,eAAe,UAAU,UAAU,OAAO;CACnD,MAAM,WAAW,KAAK,eAAe;CACrC,IAAI,OAAO,aAAa,YAAY,CAAC,UAAU,IAAI,QAAQ,GAAG,OAAO;CAErE,OAAO,KAAK,eAAe,WAAW,KAAA,KAAa,qBAAqB,IAAI;AAC9E;AAEA,SAAS,qBAAqB,MAA4B;CACxD,IAAI,MAAM,SAAS,mBAAmB,OAAO;CAC7C,MAAM,SAAS,KAAK,kBAAkB;CACtC,OAAO,CAAC,CAAC,UAAU,OAAO,WAAW,YAAY,iBAAiB;AACpE;;;;;;;;;AAUA,SAAS,4BACP,iBACA,WACoE;CACpE,IAAI,CAAC,MAAM,QAAQ,eAAe,GAAG,OAAO;EAAE;EAAiB,SAAS;CAAM;CAE9E,IAAI,UAAU;CACd,MAAM,OAAwB,gBAAgB,KAAI,eAAc;EAC9D,IACE,YAAY,UAAU,YACtB,OAAO,WAAW,aAAa,YAC/B,CAAC,UAAU,IAAI,WAAW,QAAQ,KAClC,WAAW,WAAW,KAAA,GAEtB,OAAO;EAET,UAAU;EACV,OAAO;GAAE,GAAG;GAAY,QAAQ;EAAqB;CACvD,CAAC;CAED,OAAO,UAAU;EAAE,iBAAiB;EAAM,SAAS;CAAK,IAAI;EAAE;EAAiB,SAAS;CAAM;AAChG;;;;;;AAOA,SAAS,iBAAiB,MAA8C;CACtE,MAAM,WAA+B;EACnC,GAAG;EACH,gBAAgB;GAAE,GAAG,KAAK;GAAgB,QAAQ;EAAqB;CACzE;CAMA,IAAI,qBAAqB,IAAI,GAAG;EAC9B,MAAM,mBAAmB,KAAK,oBAAoB,CAAC;EACnD,MAAM,SAAS,iBAAiB;EAChC,OAAO;GACL,GAAG;GACH,kBAAkB;IAAE,GAAG;IAAkB,QAAQ;KAAE,GAAG;KAAQ,aAAa;IAAqB;GAAE;EACpG;CACF;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,oBAAoB,SAAgE;CAClG,MAAM,YAAY,IAAI,IAAY,SAAS,aAAa,gBAAgB;CAExE,QAAQ,EAAE,eAAe;EACvB,IAAI,UAAU;EAEd,MAAM,cAAc,SAAS,KAAI,YAAW;GAC1C,MAAM,QAAQ,QAAQ,SAAS;GAE/B,IAAI,iBAAiB;GAIrB,MAAM,SAAS,4BAA4B,QAAQ,SAAS,iBAAiB,SAAS;GACtF,IAAI,OAAO,SAAS,iBAAiB;GAErC,IAAI,YAAY;GAChB,IAAI,MAAM,QAAQ,KAAK,GACrB,YAAY,MAAM,KAAI,SAAQ;IAC5B,IAAI,CAAC,uBAAuB,MAAM,SAAS,GAAG,OAAO;IACrD,iBAAiB;IACjB,OAAO,iBAAiB,IAAI;GAC9B,CAAC;GAGH,IAAI,CAAC,gBAAgB,OAAO;GAE5B,UAAU;GACV,OAAO;IACL,GAAG;IACH,SAAS;KAAE,GAAG,QAAQ;KAAS,OAAO;KAAW,iBAAiB,OAAO;IAAgB;GAC3F;EACF,CAAC;EAGD,OAAO,UAAU,EAAE,UAAU,YAAY,IAAI,KAAA;CAC/C;AACF"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Prebuilt Observational Memory transform hooks.
3
+ *
4
+ * These are ready-made `beforeObservation` hooks you can pass to
5
+ * `observationalMemory.hooks`, so common redaction needs don't require writing
6
+ * the hook yourself.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { Memory } from '@mastra/memory';
11
+ * import { skillResultRedactor } from '@mastra/memory/hooks';
12
+ *
13
+ * const memory = new Memory({
14
+ * options: {
15
+ * observationalMemory: {
16
+ * model: 'google/gemini-2.5-flash',
17
+ * hooks: { beforeObservation: skillResultRedactor() },
18
+ * },
19
+ * },
20
+ * });
21
+ * ```
22
+ */
23
+ export { skillResultRedactor, SKILL_TOOL_NAMES } from './processors/observational-memory/hooks.js';
24
+ export type { ObserverMessageTransform, SkillResultRedactorOptions } from './processors/observational-memory/hooks.js';
25
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAChG,YAAY,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC"}
package/dist/hooks.js ADDED
@@ -0,0 +1,156 @@
1
+ //#region src/processors/observational-memory/hooks.ts
2
+ /**
3
+ * Tool ids of the built-in Agent Skills tools created by `createSkillTools()`
4
+ * in `@mastra/core` (`packages/core/src/workspace/skills/tools.ts`).
5
+ */
6
+ const SKILL_TOOL_NAMES = [
7
+ "skill",
8
+ "skill_search",
9
+ "skill_read"
10
+ ];
11
+ /**
12
+ * Written in place of a redacted tool result. The Observer still records the
13
+ * call and its outcome; only the payload is replaced.
14
+ */
15
+ const REDACTED_TOOL_RESULT = "[tool result omitted]";
16
+ function isRedactableToolResult(part, toolNames) {
17
+ if (part?.type !== "tool-invocation") return false;
18
+ if (part.toolInvocation.state !== "result") return false;
19
+ const toolName = part.toolInvocation.toolName;
20
+ if (typeof toolName !== "string" || !toolNames.has(toolName)) return false;
21
+ return part.toolInvocation.result !== void 0 || hasStoredModelOutput(part);
22
+ }
23
+ function hasStoredModelOutput(part) {
24
+ if (part?.type !== "tool-invocation") return false;
25
+ const mastra = part.providerMetadata?.mastra;
26
+ return !!mastra && typeof mastra === "object" && "modelOutput" in mastra;
27
+ }
28
+ /**
29
+ * Legacy messages carry tool calls in a second `toolInvocations` array, which
30
+ * `AIV5Adapter` falls back to when `parts` holds no tool invocation
31
+ * (`AIV5Adapter.ts:264`). Leave it alone and a redacted result can be
32
+ * resurrected from that array downstream. Only rewritten when it actually
33
+ * holds a matching result, so non-legacy messages keep their array by
34
+ * reference.
35
+ */
36
+ function redactLegacyToolInvocations(toolInvocations, toolNames) {
37
+ if (!Array.isArray(toolInvocations)) return {
38
+ toolInvocations,
39
+ changed: false
40
+ };
41
+ let changed = false;
42
+ const next = toolInvocations.map((invocation) => {
43
+ if (invocation?.state !== "result" || typeof invocation.toolName !== "string" || !toolNames.has(invocation.toolName) || invocation.result === void 0) return invocation;
44
+ changed = true;
45
+ return {
46
+ ...invocation,
47
+ result: REDACTED_TOOL_RESULT
48
+ };
49
+ });
50
+ return changed ? {
51
+ toolInvocations: next,
52
+ changed: true
53
+ } : {
54
+ toolInvocations,
55
+ changed: false
56
+ };
57
+ }
58
+ /**
59
+ * Replace the result payload of a tool invocation with a placeholder, keeping
60
+ * the call's identity (tool name, arguments, terminal state). The Observer
61
+ * still records that the tool ran and what it was called with.
62
+ */
63
+ function redactToolResult(part) {
64
+ const redacted = {
65
+ ...part,
66
+ toolInvocation: {
67
+ ...part.toolInvocation,
68
+ result: REDACTED_TOOL_RESULT
69
+ }
70
+ };
71
+ if (hasStoredModelOutput(part)) {
72
+ const providerMetadata = part.providerMetadata ?? {};
73
+ const mastra = providerMetadata.mastra;
74
+ return {
75
+ ...redacted,
76
+ providerMetadata: {
77
+ ...providerMetadata,
78
+ mastra: {
79
+ ...mastra,
80
+ modelOutput: REDACTED_TOOL_RESULT
81
+ }
82
+ }
83
+ };
84
+ }
85
+ return redacted;
86
+ }
87
+ /**
88
+ * Build a `beforeObservation` hook that keeps Agent Skills results out of the
89
+ * Observer payload.
90
+ *
91
+ * The `skill` tool returns a skill's instructions verbatim as its result, and
92
+ * `skill_read` / `skill_search` return skill file contents, so without redaction
93
+ * the Observer re-observes the full skill text every time a skill is used.
94
+ * `skillResultRedactor()` replaces the result payload with a placeholder and
95
+ * leaves the tool call in place, so the Observer still records which skill was
96
+ * used without the skill text.
97
+ *
98
+ * ```typescript
99
+ * const memory = new Memory({
100
+ * options: {
101
+ * observationalMemory: {
102
+ * model: 'google/gemini-2.5-flash',
103
+ * hooks: { beforeObservation: skillResultRedactor() },
104
+ * },
105
+ * },
106
+ * });
107
+ * ```
108
+ *
109
+ * Because a hook is a function over the messages, this composes with your own
110
+ * transforms by chaining the outputs. Await each chained hook so an async one
111
+ * doesn't resolve to a promise that gets discarded:
112
+ *
113
+ * ```typescript
114
+ * const dropSkillResults = skillResultRedactor();
115
+ *
116
+ * hooks: {
117
+ * beforeObservation: async input => {
118
+ * const messages = (await dropSkillResults(input))?.messages ?? input.messages;
119
+ * return { messages: messages.filter(m => m.role !== 'signal') };
120
+ * },
121
+ * }
122
+ * ```
123
+ */
124
+ function skillResultRedactor(options) {
125
+ const toolNames = new Set(options?.toolNames ?? SKILL_TOOL_NAMES);
126
+ return ({ messages }) => {
127
+ let changed = false;
128
+ const transformed = messages.map((message) => {
129
+ const parts = message.content?.parts;
130
+ let messageChanged = false;
131
+ const legacy = redactLegacyToolInvocations(message.content?.toolInvocations, toolNames);
132
+ if (legacy.changed) messageChanged = true;
133
+ let nextParts = parts;
134
+ if (Array.isArray(parts)) nextParts = parts.map((part) => {
135
+ if (!isRedactableToolResult(part, toolNames)) return part;
136
+ messageChanged = true;
137
+ return redactToolResult(part);
138
+ });
139
+ if (!messageChanged) return message;
140
+ changed = true;
141
+ return {
142
+ ...message,
143
+ content: {
144
+ ...message.content,
145
+ parts: nextParts,
146
+ toolInvocations: legacy.toolInvocations
147
+ }
148
+ };
149
+ });
150
+ return changed ? { messages: transformed } : void 0;
151
+ };
152
+ }
153
+ //#endregion
154
+ export { SKILL_TOOL_NAMES, skillResultRedactor };
155
+
156
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","names":[],"sources":["../src/processors/observational-memory/hooks.ts"],"sourcesContent":["import type { MastraDBMessage } from '@mastra/core/agent';\n\nimport type { ObserveTransformHooks } from './types';\n\ntype MessagePart = MastraDBMessage['content']['parts'][number];\n\ntype ToolInvocationPart = Extract<MessagePart, { type: 'tool-invocation' }>;\n\ntype BeforeObservationHook = NonNullable<ObserveTransformHooks['beforeObservation']>;\n\ntype ToolInvocations = NonNullable<MastraDBMessage['content']['toolInvocations']>;\ntype StoredToolInvocation = ToolInvocations[number];\n\n/**\n * Tool ids of the built-in Agent Skills tools created by `createSkillTools()`\n * in `@mastra/core` (`packages/core/src/workspace/skills/tools.ts`).\n */\nexport const SKILL_TOOL_NAMES = ['skill', 'skill_search', 'skill_read'] as const;\n\n/**\n * A `beforeObservation` transform hook: it only rewrites messages. It receives\n * the messages about to be sent to the Observer and returns `{ messages }` to\n * replace them, or `undefined` to pass the payload through unchanged.\n */\nexport type ObserverMessageTransform = (\n ...args: Parameters<BeforeObservationHook>\n) => { messages: MastraDBMessage[] } | undefined;\n\nexport interface SkillResultRedactorOptions {\n /**\n * Tool names whose results are redacted. Defaults to\n * {@link SKILL_TOOL_NAMES}.\n */\n toolNames?: readonly string[];\n}\n\n/**\n * Written in place of a redacted tool result. The Observer still records the\n * call and its outcome; only the payload is replaced.\n */\nconst REDACTED_TOOL_RESULT = '[tool result omitted]';\n\nfunction isRedactableToolResult(part: MessagePart, toolNames: Set<string>): part is ToolInvocationPart {\n if (part?.type !== 'tool-invocation') return false;\n // Only `state: 'result'` parts render a `Tool Result <name>` body, so only\n // those carry the tool's output.\n if (part.toolInvocation.state !== 'result') return false;\n const toolName = part.toolInvocation.toolName;\n if (typeof toolName !== 'string' || !toolNames.has(toolName)) return false;\n // Nothing to redact when the tool returned no payload.\n return part.toolInvocation.result !== undefined || hasStoredModelOutput(part);\n}\n\nfunction hasStoredModelOutput(part: MessagePart): boolean {\n if (part?.type !== 'tool-invocation') return false;\n const mastra = part.providerMetadata?.mastra;\n return !!mastra && typeof mastra === 'object' && 'modelOutput' in mastra;\n}\n\n/**\n * Legacy messages carry tool calls in a second `toolInvocations` array, which\n * `AIV5Adapter` falls back to when `parts` holds no tool invocation\n * (`AIV5Adapter.ts:264`). Leave it alone and a redacted result can be\n * resurrected from that array downstream. Only rewritten when it actually\n * holds a matching result, so non-legacy messages keep their array by\n * reference.\n */\nfunction redactLegacyToolInvocations(\n toolInvocations: ToolInvocations | undefined,\n toolNames: Set<string>,\n): { toolInvocations: ToolInvocations | undefined; changed: boolean } {\n if (!Array.isArray(toolInvocations)) return { toolInvocations, changed: false };\n\n let changed = false;\n const next: ToolInvocations = toolInvocations.map(invocation => {\n if (\n invocation?.state !== 'result' ||\n typeof invocation.toolName !== 'string' ||\n !toolNames.has(invocation.toolName) ||\n invocation.result === undefined\n ) {\n return invocation;\n }\n changed = true;\n return { ...invocation, result: REDACTED_TOOL_RESULT } as StoredToolInvocation;\n });\n\n return changed ? { toolInvocations: next, changed: true } : { toolInvocations, changed: false };\n}\n\n/**\n * Replace the result payload of a tool invocation with a placeholder, keeping\n * the call's identity (tool name, arguments, terminal state). The Observer\n * still records that the tool ran and what it was called with.\n */\nfunction redactToolResult(part: ToolInvocationPart): ToolInvocationPart {\n const redacted: ToolInvocationPart = {\n ...part,\n toolInvocation: { ...part.toolInvocation, result: REDACTED_TOOL_RESULT },\n };\n\n // `resolveToolResultValue` prefers `providerMetadata.mastra.modelOutput` over\n // `toolInvocation.result`, so a stored model output has to be replaced too.\n // Copy rather than mutate: these message objects are shared with the stored\n // history, which keeps the full result.\n if (hasStoredModelOutput(part)) {\n const providerMetadata = part.providerMetadata ?? {};\n const mastra = providerMetadata.mastra as Record<string, unknown>;\n return {\n ...redacted,\n providerMetadata: { ...providerMetadata, mastra: { ...mastra, modelOutput: REDACTED_TOOL_RESULT } },\n };\n }\n\n return redacted;\n}\n\n/**\n * Build a `beforeObservation` hook that keeps Agent Skills results out of the\n * Observer payload.\n *\n * The `skill` tool returns a skill's instructions verbatim as its result, and\n * `skill_read` / `skill_search` return skill file contents, so without redaction\n * the Observer re-observes the full skill text every time a skill is used.\n * `skillResultRedactor()` replaces the result payload with a placeholder and\n * leaves the tool call in place, so the Observer still records which skill was\n * used without the skill text.\n *\n * ```typescript\n * const memory = new Memory({\n * options: {\n * observationalMemory: {\n * model: 'google/gemini-2.5-flash',\n * hooks: { beforeObservation: skillResultRedactor() },\n * },\n * },\n * });\n * ```\n *\n * Because a hook is a function over the messages, this composes with your own\n * transforms by chaining the outputs. Await each chained hook so an async one\n * doesn't resolve to a promise that gets discarded:\n *\n * ```typescript\n * const dropSkillResults = skillResultRedactor();\n *\n * hooks: {\n * beforeObservation: async input => {\n * const messages = (await dropSkillResults(input))?.messages ?? input.messages;\n * return { messages: messages.filter(m => m.role !== 'signal') };\n * },\n * }\n * ```\n */\nexport function skillResultRedactor(options?: SkillResultRedactorOptions): ObserverMessageTransform {\n const toolNames = new Set<string>(options?.toolNames ?? SKILL_TOOL_NAMES);\n\n return ({ messages }) => {\n let changed = false;\n\n const transformed = messages.map(message => {\n const parts = message.content?.parts;\n\n let messageChanged = false;\n\n // Legacy-only messages carry no `parts` at all, so this runs before the\n // parts check rather than being skipped by it.\n const legacy = redactLegacyToolInvocations(message.content?.toolInvocations, toolNames);\n if (legacy.changed) messageChanged = true;\n\n let nextParts = parts;\n if (Array.isArray(parts)) {\n nextParts = parts.map(part => {\n if (!isRedactableToolResult(part, toolNames)) return part;\n messageChanged = true;\n return redactToolResult(part);\n });\n }\n\n if (!messageChanged) return message;\n\n changed = true;\n return {\n ...message,\n content: { ...message.content, parts: nextParts, toolInvocations: legacy.toolInvocations },\n };\n });\n\n // `undefined` means \"pass through unchanged\", so leave untouched payloads alone.\n return changed ? { messages: transformed } : undefined;\n };\n}\n"],"mappings":";;;;;AAiBA,MAAa,mBAAmB;CAAC;CAAS;CAAgB;AAAY;;;;;AAuBtE,MAAM,uBAAuB;AAE7B,SAAS,uBAAuB,MAAmB,WAAoD;CACrG,IAAI,MAAM,SAAS,mBAAmB,OAAO;CAG7C,IAAI,KAAK,eAAe,UAAU,UAAU,OAAO;CACnD,MAAM,WAAW,KAAK,eAAe;CACrC,IAAI,OAAO,aAAa,YAAY,CAAC,UAAU,IAAI,QAAQ,GAAG,OAAO;CAErE,OAAO,KAAK,eAAe,WAAW,KAAA,KAAa,qBAAqB,IAAI;AAC9E;AAEA,SAAS,qBAAqB,MAA4B;CACxD,IAAI,MAAM,SAAS,mBAAmB,OAAO;CAC7C,MAAM,SAAS,KAAK,kBAAkB;CACtC,OAAO,CAAC,CAAC,UAAU,OAAO,WAAW,YAAY,iBAAiB;AACpE;;;;;;;;;AAUA,SAAS,4BACP,iBACA,WACoE;CACpE,IAAI,CAAC,MAAM,QAAQ,eAAe,GAAG,OAAO;EAAE;EAAiB,SAAS;CAAM;CAE9E,IAAI,UAAU;CACd,MAAM,OAAwB,gBAAgB,KAAI,eAAc;EAC9D,IACE,YAAY,UAAU,YACtB,OAAO,WAAW,aAAa,YAC/B,CAAC,UAAU,IAAI,WAAW,QAAQ,KAClC,WAAW,WAAW,KAAA,GAEtB,OAAO;EAET,UAAU;EACV,OAAO;GAAE,GAAG;GAAY,QAAQ;EAAqB;CACvD,CAAC;CAED,OAAO,UAAU;EAAE,iBAAiB;EAAM,SAAS;CAAK,IAAI;EAAE;EAAiB,SAAS;CAAM;AAChG;;;;;;AAOA,SAAS,iBAAiB,MAA8C;CACtE,MAAM,WAA+B;EACnC,GAAG;EACH,gBAAgB;GAAE,GAAG,KAAK;GAAgB,QAAQ;EAAqB;CACzE;CAMA,IAAI,qBAAqB,IAAI,GAAG;EAC9B,MAAM,mBAAmB,KAAK,oBAAoB,CAAC;EACnD,MAAM,SAAS,iBAAiB;EAChC,OAAO;GACL,GAAG;GACH,kBAAkB;IAAE,GAAG;IAAkB,QAAQ;KAAE,GAAG;KAAQ,aAAa;IAAqB;GAAE;EACpG;CACF;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,oBAAoB,SAAgE;CAClG,MAAM,YAAY,IAAI,IAAY,SAAS,aAAa,gBAAgB;CAExE,QAAQ,EAAE,eAAe;EACvB,IAAI,UAAU;EAEd,MAAM,cAAc,SAAS,KAAI,YAAW;GAC1C,MAAM,QAAQ,QAAQ,SAAS;GAE/B,IAAI,iBAAiB;GAIrB,MAAM,SAAS,4BAA4B,QAAQ,SAAS,iBAAiB,SAAS;GACtF,IAAI,OAAO,SAAS,iBAAiB;GAErC,IAAI,YAAY;GAChB,IAAI,MAAM,QAAQ,KAAK,GACrB,YAAY,MAAM,KAAI,SAAQ;IAC5B,IAAI,CAAC,uBAAuB,MAAM,SAAS,GAAG,OAAO;IACrD,iBAAiB;IACjB,OAAO,iBAAiB,IAAI;GAC9B,CAAC;GAGH,IAAI,CAAC,gBAAgB,OAAO;GAE5B,UAAU;GACV,OAAO;IACL,GAAG;IACH,SAAS;KAAE,GAAG,QAAQ;KAAS,OAAO;KAAW,iBAAiB,OAAO;IAAgB;GAC3F;EACF,CAAC;EAGD,OAAO,UAAU,EAAE,UAAU,YAAY,IAAI,KAAA;CAC/C;AACF"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_src = require("./src-BCvV2aGL.cjs");
2
+ const require_src = require("./src-C4niho1P.cjs");
3
3
  let _mastra_core_processors = require("@mastra/core/processors");
4
4
  exports.Extractor = require_src.Extractor;
5
5
  exports.KnowledgeSemanticIndexCoordinator = require_src.KnowledgeSemanticIndexCoordinator;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { C as SUMMARIZE_THREAD_DEFAULTS, G as ModelByInputTokens, H as KnowledgeSemanticIndexCoordinator, S as WorkingMemoryExtractor, U as StaleKnowledgeSemanticIndexError, V as Subconscious, X as Extractor, a as extractWorkingMemoryContent, b as WorkingMemoryStateProcessor, c as getObservationsAsOf, i as WorkingMemory, n as MessageHistory, o as extractWorkingMemoryTags, r as SemanticRecall, s as removeWorkingMemoryTags, t as Memory, v as WORKING_MEMORY_STATE_ID, w as summarizeConversation, x as deepMergeWorkingMemory, y as WORKING_MEMORY_STATE_PROCESSOR_ID } from "./src-Ju0u9OWc.js";
1
+ import { C as SUMMARIZE_THREAD_DEFAULTS, G as ModelByInputTokens, H as KnowledgeSemanticIndexCoordinator, S as WorkingMemoryExtractor, U as StaleKnowledgeSemanticIndexError, V as Subconscious, X as Extractor, a as extractWorkingMemoryContent, b as WorkingMemoryStateProcessor, c as getObservationsAsOf, i as WorkingMemory, n as MessageHistory, o as extractWorkingMemoryTags, r as SemanticRecall, s as removeWorkingMemoryTags, t as Memory, v as WORKING_MEMORY_STATE_ID, w as summarizeConversation, x as deepMergeWorkingMemory, y as WORKING_MEMORY_STATE_PROCESSOR_ID } from "./src-DquR-jTR.js";
2
2
  export { Extractor, KnowledgeSemanticIndexCoordinator, Memory, MessageHistory, ModelByInputTokens, SUMMARIZE_THREAD_DEFAULTS, SemanticRecall, StaleKnowledgeSemanticIndexError, Subconscious, WORKING_MEMORY_STATE_ID, WORKING_MEMORY_STATE_PROCESSOR_ID, WorkingMemory, WorkingMemoryExtractor, WorkingMemoryStateProcessor, deepMergeWorkingMemory, extractWorkingMemoryContent, extractWorkingMemoryTags, getObservationsAsOf, removeWorkingMemoryTags, summarizeConversation };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_src = require("../src-BCvV2aGL.cjs");
2
+ const require_src = require("../src-C4niho1P.cjs");
3
3
  exports.Extractor = require_src.Extractor;
4
4
  exports.KnowledgeSemanticIndexCoordinator = require_src.KnowledgeSemanticIndexCoordinator;
5
5
  exports.ModelByInputTokens = require_src.ModelByInputTokens;
@@ -1,2 +1,2 @@
1
- import { A as formatMessagesForObserver, B as OBSERVATION_CONTINUATION_HINT, D as buildObserverPrompt, E as OBSERVER_SYSTEM_PROMPT, F as parseAnchorId, G as ModelByInputTokens, H as KnowledgeSemanticIndexCoordinator, I as stripEphemeralAnchorIds, J as publishSubconsciousActivity, K as SUBCONSCIOUS_ACTIVITY_STATE_ID, L as OBSERVATIONAL_MEMORY_DEFAULTS, M as optimizeObservationsForContext, N as parseObserverOutput, O as buildObserverSystemPrompt, P as injectAnchorIds, R as OBSERVATION_CONTEXT_INSTRUCTIONS, S as WorkingMemoryExtractor, T as TokenCounter, U as StaleKnowledgeSemanticIndexError, V as Subconscious, W as SubconsciousRemindExtractor, X as Extractor, Y as renderSubconsciousActivity, _ as wrapInObservationGroup, c as getObservationsAsOf, d as combineObservationGroupRanges, f as deriveObservationGroupProvenance, g as stripObservationGroups, h as renderObservationGroupsForReflection, j as hasCurrentTaskSection, k as extractCurrentTask, l as ObservationalMemoryProcessor, m as reconcileObservationGroupsFromReflection, p as parseObservationGroups, q as buildSubconsciousActivitySnapshot, u as ObservationalMemory, w as summarizeConversation, z as OBSERVATION_CONTEXT_PROMPT } from "../src-Ju0u9OWc.js";
1
+ import { A as formatMessagesForObserver, B as OBSERVATION_CONTINUATION_HINT, D as buildObserverPrompt, E as OBSERVER_SYSTEM_PROMPT, F as parseAnchorId, G as ModelByInputTokens, H as KnowledgeSemanticIndexCoordinator, I as stripEphemeralAnchorIds, J as publishSubconsciousActivity, K as SUBCONSCIOUS_ACTIVITY_STATE_ID, L as OBSERVATIONAL_MEMORY_DEFAULTS, M as optimizeObservationsForContext, N as parseObserverOutput, O as buildObserverSystemPrompt, P as injectAnchorIds, R as OBSERVATION_CONTEXT_INSTRUCTIONS, S as WorkingMemoryExtractor, T as TokenCounter, U as StaleKnowledgeSemanticIndexError, V as Subconscious, W as SubconsciousRemindExtractor, X as Extractor, Y as renderSubconsciousActivity, _ as wrapInObservationGroup, c as getObservationsAsOf, d as combineObservationGroupRanges, f as deriveObservationGroupProvenance, g as stripObservationGroups, h as renderObservationGroupsForReflection, j as hasCurrentTaskSection, k as extractCurrentTask, l as ObservationalMemoryProcessor, m as reconcileObservationGroupsFromReflection, p as parseObservationGroups, q as buildSubconsciousActivitySnapshot, u as ObservationalMemory, w as summarizeConversation, z as OBSERVATION_CONTEXT_PROMPT } from "../src-DquR-jTR.js";
2
2
  export { Extractor, KnowledgeSemanticIndexCoordinator, ModelByInputTokens, OBSERVATIONAL_MEMORY_DEFAULTS, OBSERVATION_CONTEXT_INSTRUCTIONS, OBSERVATION_CONTEXT_PROMPT, OBSERVATION_CONTINUATION_HINT, OBSERVER_SYSTEM_PROMPT, ObservationalMemory, ObservationalMemoryProcessor, SUBCONSCIOUS_ACTIVITY_STATE_ID, StaleKnowledgeSemanticIndexError, Subconscious, SubconsciousRemindExtractor, TokenCounter, WorkingMemoryExtractor, buildObserverPrompt, buildObserverSystemPrompt, buildSubconsciousActivitySnapshot, combineObservationGroupRanges, deriveObservationGroupProvenance, extractCurrentTask, formatMessagesForObserver, getObservationsAsOf, hasCurrentTaskSection, injectAnchorIds, optimizeObservationsForContext, parseAnchorId, parseObservationGroups, parseObserverOutput, publishSubconsciousActivity, reconcileObservationGroupsFromReflection, renderObservationGroupsForReflection, renderSubconsciousActivity, stripEphemeralAnchorIds, stripObservationGroups, summarizeConversation, wrapInObservationGroup };
@@ -0,0 +1,63 @@
1
+ import type { MastraDBMessage } from '@mastra/core/agent';
2
+ import type { ObserveTransformHooks } from './types.js';
3
+ type BeforeObservationHook = NonNullable<ObserveTransformHooks['beforeObservation']>;
4
+ /**
5
+ * Tool ids of the built-in Agent Skills tools created by `createSkillTools()`
6
+ * in `@mastra/core` (`packages/core/src/workspace/skills/tools.ts`).
7
+ */
8
+ export declare const SKILL_TOOL_NAMES: readonly ["skill", "skill_search", "skill_read"];
9
+ /**
10
+ * A `beforeObservation` transform hook: it only rewrites messages. It receives
11
+ * the messages about to be sent to the Observer and returns `{ messages }` to
12
+ * replace them, or `undefined` to pass the payload through unchanged.
13
+ */
14
+ export type ObserverMessageTransform = (...args: Parameters<BeforeObservationHook>) => {
15
+ messages: MastraDBMessage[];
16
+ } | undefined;
17
+ export interface SkillResultRedactorOptions {
18
+ /**
19
+ * Tool names whose results are redacted. Defaults to
20
+ * {@link SKILL_TOOL_NAMES}.
21
+ */
22
+ toolNames?: readonly string[];
23
+ }
24
+ /**
25
+ * Build a `beforeObservation` hook that keeps Agent Skills results out of the
26
+ * Observer payload.
27
+ *
28
+ * The `skill` tool returns a skill's instructions verbatim as its result, and
29
+ * `skill_read` / `skill_search` return skill file contents, so without redaction
30
+ * the Observer re-observes the full skill text every time a skill is used.
31
+ * `skillResultRedactor()` replaces the result payload with a placeholder and
32
+ * leaves the tool call in place, so the Observer still records which skill was
33
+ * used without the skill text.
34
+ *
35
+ * ```typescript
36
+ * const memory = new Memory({
37
+ * options: {
38
+ * observationalMemory: {
39
+ * model: 'google/gemini-2.5-flash',
40
+ * hooks: { beforeObservation: skillResultRedactor() },
41
+ * },
42
+ * },
43
+ * });
44
+ * ```
45
+ *
46
+ * Because a hook is a function over the messages, this composes with your own
47
+ * transforms by chaining the outputs. Await each chained hook so an async one
48
+ * doesn't resolve to a promise that gets discarded:
49
+ *
50
+ * ```typescript
51
+ * const dropSkillResults = skillResultRedactor();
52
+ *
53
+ * hooks: {
54
+ * beforeObservation: async input => {
55
+ * const messages = (await dropSkillResults(input))?.messages ?? input.messages;
56
+ * return { messages: messages.filter(m => m.role !== 'signal') };
57
+ * },
58
+ * }
59
+ * ```
60
+ */
61
+ export declare function skillResultRedactor(options?: SkillResultRedactorOptions): ObserverMessageTransform;
62
+ export {};
63
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/processors/observational-memory/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAMrD,KAAK,qBAAqB,GAAG,WAAW,CAAC,qBAAqB,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAKrF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,kDAAmD,CAAC;AAEjF;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,GAAG,IAAI,EAAE,UAAU,CAAC,qBAAqB,CAAC,KACvC;IAAE,QAAQ,EAAE,eAAe,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAmFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,wBAAwB,CAqClG"}
@@ -1 +1 @@
1
- {"version":3,"file":"observation-groups.d.ts","sourceRoot":"","sources":["../../../src/processors/observational-memory/observation-groups.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkDD,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,EAAE,SAAqB,EACvB,eAAe,CAAC,EAAE,MAAM,EAAE,EAC1B,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAIR;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA0B/E;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CASnE;AASD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAgBhF;AAED,wBAAgB,oCAAoC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBxF;AAOD,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAiChH;AAED,wBAAgB,wCAAwC,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyBnH"}
1
+ {"version":3,"file":"observation-groups.d.ts","sourceRoot":"","sources":["../../../src/processors/observational-memory/observation-groups.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAgKD,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,EAAE,SAAqB,EACvB,eAAe,CAAC,EAAE,MAAM,EAAE,EAC1B,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAIR;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAyB/E;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAQnE;AAmCD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAiChF;AAED,wBAAgB,oCAAoC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAaxF;AAcD,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CA6ChH;AAED,wBAAgB,wCAAwC,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyBnH"}