Stabilize memory context output (roadmap Sprint 1)#123
Conversation
Sharper retrieval, less dumping. Deterministic; no gated features. - people_map: stoplist junk capitalized sentence-openers (The/Do/She/He/ Keep/User/Taglish/...), so they stop being treated as "people". - Dedup: each event contributes a name at most once (kills per-occurrence event_id duplication that ballooned payloads). - Alias canonicalization: merge a single-token name into its full name (Janine -> Janine Tan); keep distinct aliases (Jana) separate. - Cap sizes: max 12 people, max 8 event_ids per person. - Payload slimming: compactContextResponse now enforces a deterministic max_payload_chars budget (default 12000), trimming heaviest fields first; new max_payload_chars + debug inputs on the memory-context schema. - Tests: junk removal, dedup, alias merge, caps, and payload-budget slimming. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughReworks ChangesContext stabilization
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant compactContextResponse
participant slimContextResponse
Caller->>compactContextResponse: pack, events, input(max_payload_chars, debug)
compactContextResponse->>compactContextResponse: build default payload
alt debug true
compactContextResponse-->>Caller: full payload
else payload oversized
compactContextResponse->>slimContextResponse: payload, maxChars
slimContextResponse->>slimContextResponse: trim people_map, lists, summary
slimContextResponse-->>compactContextResponse: trimmed payload
compactContextResponse-->>Caller: trimmed payload
end
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7c35f37234
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| response.key_points = list(response.key_points).slice(0, 6); | ||
| response.open_loops = list(response.open_loops).slice(0, 6); | ||
| response.risks = list(response.risks).slice(0, 6); | ||
| response.active_projects = list(response.active_projects).slice(0, 6); |
There was a problem hiding this comment.
Include decisions in payload slimming
When an active context pack is decision-heavy (or has older persisted decisions entries with large text), the new max_payload_chars cap can still be exceeded because slimming truncates key_points, open_loops, risks, and active_projects but leaves decisions unbounded. In that scenario get_memory_context can continue returning oversized payloads despite the new budget, so decisions needs to be capped/trimmed as part of the same slimming pass or the function should re-check and keep trimming until it is actually under budget.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
lib/services/memory-distillation-service.ts (1)
157-173: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winAdd a final cap before returning.
slimContextResponsestill leavesdecisionsandoperating_rulesuntouched, so the last return can exceedmaxChars; trim those fields or hard-cap the remaining lists before returning.🤖 Prompt for 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. In `@lib/services/memory-distillation-service.ts` around lines 157 - 173, slimContextResponse still can return payloads over maxChars because the final fallback only trims people_map and summary while leaving fields like decisions and operating_rules untouched. Update slimContextResponse to apply a last-pass cap before the final return by trimming those remaining large arrays/collections or otherwise hard-capping the remaining content after the existing payloadChars checks, so the function can guarantee the response stays within maxChars.
🤖 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 `@lib/services/pandora-mcp-tools.ts`:
- Line 19: The `get_memory_context` tool registration schema in
`pandora-mcp-server` is missing `max_payload_chars` and `debug`, even though
`memoryContextInputSchema` already defines them. Update the schema used when
registering `getMemoryContextTool` so it mirrors `memoryContextInputSchema`
exactly and accepts these two optional fields, ensuring they reach
`getMemoryContextTool` without MCP validation stripping or rejecting them.
---
Nitpick comments:
In `@lib/services/memory-distillation-service.ts`:
- Around line 157-173: slimContextResponse still can return payloads over
maxChars because the final fallback only trims people_map and summary while
leaving fields like decisions and operating_rules untouched. Update
slimContextResponse to apply a last-pass cap before the final return by trimming
those remaining large arrays/collections or otherwise hard-capping the remaining
content after the existing payloadChars checks, so the function can guarantee
the response stays within maxChars.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: b659656e-26e4-48e5-a308-0ed890171a16
📒 Files selected for processing (3)
lib/services/memory-distillation-service.tslib/services/pandora-mcp-tools.tstests/unit/context-stabilization.test.ts
| const namespaceSchema = z.enum(["real_life", "au"]); | ||
| export const latestContextPackInputSchema = z.object({ namespace: namespaceSchema, pack_type: z.enum(["daily", "master"]).optional() }); | ||
| export const memoryContextInputSchema = z.object({ namespace: namespaceSchema, query: z.string().optional(), current_task: z.string().optional(), max_items: z.number().int().positive().max(100).optional(), include_risks: z.boolean().optional(), include_people: z.boolean().optional(), include_projects: z.boolean().optional() }); | ||
| export const memoryContextInputSchema = z.object({ namespace: namespaceSchema, query: z.string().optional(), current_task: z.string().optional(), max_items: z.number().int().positive().max(100).optional(), include_risks: z.boolean().optional(), include_people: z.boolean().optional(), include_projects: z.boolean().optional(), max_payload_chars: z.number().int().positive().max(200000).optional(), debug: z.boolean().optional() }); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm the server registration schema and whether args are passed through untouched.
rg -nP 'registerTool\(\s*"get_memory_context"' -A3 lib/services/pandora-mcp-server.ts
rg -nP 'max_payload_chars|debug' lib/services/pandora-mcp-server.tsRepository: besfeng23/Memory
Length of output: 1775
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the tool implementation and the surrounding validation flow.
ast-grep outline lib/services/pandora-mcp-tools.ts --view expanded
sed -n '1,260p' lib/services/pandora-mcp-tools.ts | cat -n
echo
echo '---'
echo
# Find the exact handler signature and any re-parsing of args.
rg -n "getMemoryContextTool|memoryContextInputSchema|parse\(|safeParse\(|args: unknown|inputSchema" lib/services/pandora-mcp-tools.ts lib/services/pandora-mcp-server.tsRepository: besfeng23/Memory
Length of output: 47229
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n '"`@modelcontextprotocol/sdk`"|mcp' package.json package-lock.json pnpm-lock.yaml yarn.lockRepository: besfeng23/Memory
Length of output: 388
🌐 Web query:
@modelcontextprotocol/sdk Server.registerTool inputSchema unknown properties handler args stripped or preserved
💡 Result:
In the Model Context Protocol (MCP) TypeScript SDK, the handling of input arguments depends on how you define your inputSchema and whether the schema effectively validates the incoming data. 1. Schema Validation and Stripping: The inputSchema provided to registerTool is used to validate incoming JSON-RPC tool call arguments [1][2]. If a schema is defined but does not explicitly include specific properties, or if validation fails or strips them, those properties will not reach your tool handler [3]. The SDK is designed to ensure that the arguments passed to your handler strictly conform to the provided inputSchema [1][4]. 2. Standard Schema and Zod Support: The SDK (as of v2) natively supports any "Standard Schema" library (e.g., Zod) [1][4]. When you pass a proper z.object({...}) schema, the SDK uses it to parse and validate the arguments [1][2]. If your handler receives an empty object {} even when the client sends data, it often indicates that the schema provided was incorrectly constructed (e.g., passing a raw object shape instead of a wrapped Zod object in older versions) or that the validation logic stripped the unexpected fields [3]. 3. Compatibility for Raw Shapes: While earlier versions of the SDK experienced issues where raw Zod shapes were incorrectly handled or caused arguments to be stripped [3][5], recent versions include compatibility layers that auto-wrap raw Zod shapes into z.object({...}) to prevent this behavior [6][7][8]. Recommendation: To ensure all properties are preserved, always wrap your input definitions in z.object({...}) [1][7][2]. If you continue to see arguments being stripped, verify that your schema definition matches the structure of the incoming data exactly; the SDK will discard any properties not defined in the schema to ensure strict adherence to the protocol's type safety requirements [1][3].
Citations:
- 1: https://ts.sdk.modelcontextprotocol.io/v2/documents/Documents.Server_Guide.html
- 2: https://github.com/modelcontextprotocol/typescript-sdk/blob/HEAD/docs/server.md
- 3: Bug:
server.tool()silently ignores ZodObject schemas and strips all arguments modelcontextprotocol/typescript-sdk#1291 - 4: feat: support Standard Schema for tool/prompt schemas modelcontextprotocol/typescript-sdk#1689
- 5: Tool arguments are not passed into registered tool handlers modelcontextprotocol/typescript-sdk#1026
- 6: modelcontextprotocol/typescript-sdk@182ec53
- 7: feat(compat): registerTool/registerPrompt accept raw Zod shape, auto-wrap with z.object() modelcontextprotocol/typescript-sdk#1901
- 8: https://github.com/modelcontextprotocol/typescript-sdk/blob/2c0c481c/packages/server/src/server/mcp.ts
🌐 Web query:
site:github.com modelcontextprotocol sdk registerTool inputSchema args unknown properties
💡 Result:
In the Model Context Protocol (MCP) SDK, handling of "unknown" or additional properties within a tool's inputSchema is determined by the underlying JSON Schema validation settings. MCP specifications (via SEP-2106 and related initiatives) align tool schemas with JSON Schema 2020-12 [1][2]. Under this specification, tool inputs are not strictly prohibited from containing unknown properties by default, but the behavior depends on how you define your schema [3][4]: 1. Default Behavior: If you define your inputSchema simply as an object with properties, the JSON Schema default behavior allows for additional properties [3][4]. 2. Restricting Unknowns: To explicitly reject unknown properties, you should define your schema with "additionalProperties": false [3][5]. 3. TypeScript SDK Behavior: The MCP TypeScript SDK uses Zod for validation [6][7]. When using Zod schemas for inputSchema: - If you want validation to strictly reject unknown properties, use z.object({...}).strict() [8]. - If you want to preserve or allow extra properties, you can use .passthrough() [8]. - Be aware that in some SDK versions, if you do not explicitly set strictness, there may be nuances in how Zod translates to JSON Schema regarding the additionalProperties field [8]. If you are encountering issues where extra properties are being dropped or blocked, verify if your Zod schema is configured with .strict() (which blocks extras) or if the SDK version you are using is applying default JSON Schema behaviors that differ from your expectations [8]. As of recent updates, the SDK is designed to be more compliant with passing through full JSON Schema 2020-12 keywords [2][9].
Citations:
- 1: SEP-2106: Tools
inputSchema&outputSchemaConform to JSON Schema 2020-12 modelcontextprotocol/modelcontextprotocol#2106 - 2: feat(core,server,client): implement SEP-2106 (tool schemas conform to JSON Schema 2020-12) modelcontextprotocol/typescript-sdk#2249
- 3: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/ff960c9e/docs/specification/draft/server/tools.mdx
- 4: SEP-834: Tools
inputSchema&outputSchemaconform to JSON Schema 2020-12 modelcontextprotocol/modelcontextprotocol#881 - 5: SEP-1613: Establish JSON Schema 2020-12 as Default Dialect for MCP modelcontextprotocol/modelcontextprotocol#1613
- 6: https://github.com/cloudflare/cloudflare-docs/blob/production/src/content/docs/agents/model-context-protocol/protocol/tools.mdx
- 7: https://github.com/microsoft/skills/blob/main/.github/skills/mcp-builder/reference/node%5Fmcp%5Fserver.md
- 8: Additional parameters are not passed through to tools modelcontextprotocol/typescript-sdk#147
- 9: SEP-1613: use
.catchall()on inputSchema/outputSchema to support JSON Schema 2020-12 modelcontextprotocol/typescript-sdk#1135
🌐 Web query:
"@modelcontextprotocol/sdk" registerTool inputSchema handler args validate preserve unknown keys
💡 Result:
In the MCP TypeScript SDK (v2), the registerTool method associates a tool with a name, metadata, and a handler [1]. The inputSchema parameter defines the argument structure and handles validation using the Standard Schema interface [2][3]. Key details regarding your query: 1. Input Schema and Validation: The registerTool method expects an inputSchema that conforms to the Standard Schema specification (e.g., Zod, ArkType, or Valibot) [2][3]. This schema is used by the SDK to advertise the tool's capabilities via tools/list and to validate incoming arguments during tools/call [3]. 2. Handling Unknown Keys: The behavior regarding unknown keys in the input depends on the underlying schema library configuration (e.g., Zod) [4]. By default, Zod objects often "strip" unknown keys [4]. To change this behavior: - To reject unknown keys: Use.strict on your Zod schema [4]. - To preserve unknown keys: Use.passthrough on your Zod schema [4]. 3. Handler Arguments: When an inputSchema is provided, the handler is invoked with (args, ctx) [5]. The args object contains the validated and processed parameters [5]. 4. Compatibility: While v2 natively requires a full Standard Schema object (e.g., z.object({...})), recent updates (as of April 2026) added compatibility to automatically wrap "raw" Zod shapes (e.g., { key: z.string }) into a z.object for convenience [6][1]. Important Note on Schema Types: Passing a plain JSON Schema object (instead of a Standard Schema compatible object) can cause the SDK to misinterpret the schema or silently drop it [7]. If you need to use a raw JSON Schema, you must wrap it using a tool like fromJsonSchema (available in @modelcontextprotocol/core) with an appropriate validator [8].
Citations:
- 1: https://deepwiki.com/modelcontextprotocol/typescript-sdk/3.2-tool-registration-and-execution
- 2: https://ts.sdk.modelcontextprotocol.io/v2/documents/Documents.Server_Guide.html
- 3: https://github.com/modelcontextprotocol/typescript-sdk/blob/7d7e62cc/packages/core/src/util/standardSchema.ts
- 4: Additional parameters are not passed through to tools modelcontextprotocol/typescript-sdk#147
- 5: https://github.com/modelcontextprotocol/typescript-sdk/blob/542d5c95860c03d0c1a689f579b925250e25de6c/packages/server/src/server/mcp.ts
- 6: feat(compat): registerTool/registerPrompt accept raw Zod shape, auto-wrap with z.object() modelcontextprotocol/typescript-sdk#1901
- 7: server.tool() silently drops inputSchema when passed plain JSON Schema objects instead of Zod schemas modelcontextprotocol/typescript-sdk#1585
- 8: feat: support Standard Schema for tool/prompt schemas modelcontextprotocol/typescript-sdk#1689
🌐 Web query:
site:github.com/modelcontextprotocol/typescript-sdk registerTool inputSchema zod.parse handler
💡 Result:
In the Model Context Protocol (MCP) TypeScript SDK, the registerTool method allows you to define a tool with a schema for its arguments (inputSchema) and a handler function to execute the tool's logic [1][2]. Standard Pattern The recommended, native way to define the inputSchema is by passing a Standard Schema object, such as a Zod schema created with z.object({...}) [3][4][5]. When defined this way, the SDK automatically handles validation, and the handler receives the validated arguments as an object [3][6]. Example: server.registerTool( 'calculate-bmi', { title: 'BMI Calculator', description: 'Calculate Body Mass Index', inputSchema: z.object({ weightKg: z.number, heightM: z.number }), }, async ({ weightKg, heightM }) => { // Handler logic const bmi = weightKg / (heightM * heightM); return { content: [{ type: 'text', text: BMI is ${bmi} }], }; }); Compatibility for Raw Shapes For backward compatibility, the SDK also accepts raw Zod shapes (e.g., { weightKg: z.number(), heightM: z.number() }) [4][6]. If you pass a raw object shape, the SDK internally auto-wraps it with z.object() at runtime [4][6]. This usage is deprecated and intended to be removed in future major versions [6]. Key Notes: - Validation: The SDK uses the provided schema to validate the tool input before it reaches your handler [7]. - JSON Schema: The SDK uses these schemas to inform clients about the tool's expected input via the tools/list protocol message [7][5]. - Union Types: Support for complex schemas like z.union or z.discriminatedUnion is implemented to ensure they are correctly exposed to clients and validated [7]. - Library Agnostic: With the adoption of Standard Schema, the SDK is no longer strictly coupled to Zod; other libraries that support the Standard Schema interface can also be used [5][8].
Citations:
- 1: https://github.com/modelcontextprotocol/typescript-sdk/blob/5e0249f57fdc1d7b7d69cd6140952a8e4e7ae695/packages/server/src/server/mcp.ts
- 2: https://github.com/modelcontextprotocol/typescript-sdk/blob/0657c3bea9218f67494850562c0c449548c972c1/packages/server/src/server/mcp.ts
- 3: https://github.com/modelcontextprotocol/typescript-sdk/blob/2c0c481c/examples/server/src/serverGuide.examples.ts
- 4: feat(compat): registerTool/registerPrompt accept raw Zod shape, auto-wrap with z.object() modelcontextprotocol/typescript-sdk#1901
- 5: feat: support Standard Schema for tool/prompt schemas modelcontextprotocol/typescript-sdk#1689
- 6: modelcontextprotocol/typescript-sdk@182ec53
- 7: fix(server): preserve inputSchema for z.discriminatedUnion / z.union modelcontextprotocol/typescript-sdk#2017
- 8: https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/server.md
🌐 Web query:
site:github.com/modelcontextprotocol/typescript-sdk registerTool inputSchema zod.parse handler args unknown keys
💡 Result:
When working with Zod schemas in the Model Context Protocol (MCP) TypeScript SDK, the handling of unknown keys depends on the Zod configuration and the SDK version [1][2]. Default Zod object validation behavior is to strip unknown keys [1]. If you want your tool handlers or schema validation to behave differently, you can use the following Zod methods: 1..strip: This is the default Zod behavior. Any keys present in the input that are not defined in your schema are removed during validation [1]. 2..passthrough: Use this method if you want to preserve unknown keys in the validated output [1][3]. 3..strict: Use this method if you want validation to fail when unknown keys are present [1]. In the context of the MCP SDK, there has been a transition toward using default (stripping) behavior to improve type safety and consistency, moving away from older SDK versions that heavily utilized.passthrough [2]. If you are encountering issues where arguments are missing or being stripped unexpectedly: - Ensure you are passing the schema object correctly to the tool registration method [4]. - If you need to allow additional parameters that are not explicitly defined in your schema, chain.passthrough to your Zod object definition [1][3]. - When working with Zod v4 compatibility in newer SDK versions, be aware of how internal parsing methods are handled, as the SDK has undergone changes to maintain cross-version compatibility [5][6]. For general Zod parsing (outside of the direct tool handler flow), you can use Zod's.parse or.safeParse methods, which respect the.strip/.passthrough/.strict configuration defined on the schema [7][8].
Citations:
- 1: Additional parameters are not passed through to tools modelcontextprotocol/typescript-sdk#147
- 2: What's with the use of .passthrough() in zod? modelcontextprotocol/typescript-sdk#182
- 3: _meta schema in ResultSchema strips custom metadata modelcontextprotocol/typescript-sdk#1293
- 4: Bug:
server.tool()silently ignores ZodObject schemas and strips all arguments modelcontextprotocol/typescript-sdk#1291 - 5: MCP SDK v1.17.5 Incompatible with Zod v4 - Breaking Changes modelcontextprotocol/typescript-sdk#925
- 6: feat: zod v4 modelcontextprotocol/typescript-sdk#869
- 7: https://github.com/modelcontextprotocol/typescript-sdk/blob/327243ce/packages/core/src/util/schema.ts
- 8: https://github.com/modelcontextprotocol/typescript-sdk/blob/ccb78f20438a853f0205b8ed7f642af7780208e6/packages/core/src/util/schema.ts
Mirror max_payload_chars and debug in get_memory_context. lib/services/pandora-mcp-server.ts:12 omits those fields from the tool registration schema, so MCP validation can drop or reject them before getMemoryContextTool sees them.
🤖 Prompt for 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.
In `@lib/services/pandora-mcp-tools.ts` at line 19, The `get_memory_context` tool
registration schema in `pandora-mcp-server` is missing `max_payload_chars` and
`debug`, even though `memoryContextInputSchema` already defines them. Update the
schema used when registering `getMemoryContextTool` so it mirrors
`memoryContextInputSchema` exactly and accepts these two optional fields,
ensuring they reach `getMemoryContextTool` without MCP validation stripping or
rejecting them.
What
Roadmap Sprint 1 (#1 — "stabilize output"). Sharper retrieval, less dumping. Deterministic; no gated features enabled.
Problem (observed live)
extractPeopleMentionstreated every capitalized word as a person and pushed the event id once per match occurrence — sopeople_mapfilled with junk (The,Do,She,He,Keep,User) and a single event's id repeated dozens of times, ballooningget_memory_contextto ~50k chars.Changes —
lib/services/memory-distillation-service.tsThe/Do/She/He/Keep/User/Taglish/...).Janine→Janine Tan); keep genuinely distinct aliases (Jana) separate.compactContextResponseenforces a deterministicmax_payload_charsbudget (default 12000), trimming the heaviest fields first (people ids/notes → list lengths → summary).debug: truereturns the full payload.max_payload_chars/debuginputs onmemoryContextInputSchema.Schema changes
None.
Tests —
tests/unit/context-stabilization.test.ts(5/5)Junk removal, per-event dedup, alias merge vs. distinct alias, caps, and payload-budget slimming (+ debug bypass).
Verification
first-reviewed-memory-fixture→spawnSync npm ENOENT) is the pre-existing sandbox-only flake in an untouched file.Hard-rules compliance
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests