@kinqs/brainrouter-mcp-server 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +144 -0
- package/README.md +56 -0
- package/agents/README.md +120 -0
- package/agents/code-reviewer.md +97 -0
- package/agents/security-auditor.md +101 -0
- package/agents/test-engineer.md +95 -0
- package/dist/__tests__/agent_mode.test.d.ts +1 -0
- package/dist/__tests__/api-routes.test.d.ts +1 -0
- package/dist/__tests__/api-routes.test.js +170 -0
- package/dist/__tests__/crypto.test.d.ts +1 -0
- package/dist/__tests__/crypto.test.js +28 -0
- package/dist/__tests__/host-integrations.test.d.ts +1 -0
- package/dist/__tests__/host-integrations.test.js +82 -0
- package/dist/__tests__/integration.test.d.ts +1 -0
- package/dist/__tests__/integration.test.js +50 -0
- package/dist/__tests__/loader.test.d.ts +1 -0
- package/dist/__tests__/loader.test.js +89 -0
- package/dist/__tests__/neural-spark.test.d.ts +1 -0
- package/dist/__tests__/neural-spark.test.js +112 -0
- package/dist/__tests__/pagination.test.d.ts +1 -0
- package/dist/__tests__/pagination.test.js +23 -0
- package/dist/__tests__/redaction.test.d.ts +1 -0
- package/dist/__tests__/redaction.test.js +17 -0
- package/dist/__tests__/registry.test.d.ts +1 -0
- package/dist/__tests__/registry.test.js +56 -0
- package/dist/__tests__/retry.test.d.ts +1 -0
- package/dist/__tests__/retry.test.js +30 -0
- package/dist/__tests__/skill-activation.test.d.ts +1 -0
- package/dist/__tests__/skill-activation.test.js +112 -0
- package/dist/__tests__/working-memory.test.d.ts +1 -0
- package/dist/__tests__/working-memory.test.js +200 -0
- package/dist/__tests__/workspace-paths.test.d.ts +1 -0
- package/dist/__tests__/workspace-paths.test.js +56 -0
- package/dist/__tests__/writer.test.d.ts +1 -0
- package/dist/__tests__/writer.test.js +94 -0
- package/dist/api/auth/crypto.d.ts +4 -0
- package/dist/api/auth/crypto.js +54 -0
- package/dist/api/middleware/auth.d.ts +12 -0
- package/dist/api/middleware/auth.js +90 -0
- package/dist/api/pagination.d.ts +18 -0
- package/dist/api/pagination.js +32 -0
- package/dist/api/routes/auth.d.ts +1 -0
- package/dist/api/routes/auth.js +130 -0
- package/dist/api/routes/chat-completions.d.ts +7 -0
- package/dist/api/routes/chat-completions.js +474 -0
- package/dist/api/routes/contradictions.d.ts +1 -0
- package/dist/api/routes/contradictions.js +28 -0
- package/dist/api/routes/evidence.d.ts +1 -0
- package/dist/api/routes/evidence.js +59 -0
- package/dist/api/routes/governance.d.ts +1 -0
- package/dist/api/routes/governance.js +95 -0
- package/dist/api/routes/graph.d.ts +1 -0
- package/dist/api/routes/graph.js +25 -0
- package/dist/api/routes/hooks.d.ts +1 -0
- package/dist/api/routes/hooks.js +88 -0
- package/dist/api/routes/memories.d.ts +1 -0
- package/dist/api/routes/memories.js +92 -0
- package/dist/api/routes/persona.d.ts +1 -0
- package/dist/api/routes/persona.js +9 -0
- package/dist/api/routes/scenes.d.ts +1 -0
- package/dist/api/routes/scenes.js +35 -0
- package/dist/api/routes/skills.d.ts +1 -0
- package/dist/api/routes/skills.js +14 -0
- package/dist/api/routes/stats.d.ts +1 -0
- package/dist/api/routes/stats.js +8 -0
- package/dist/api/routes/users.d.ts +1 -0
- package/dist/api/routes/users.js +82 -0
- package/dist/api/routes/working.d.ts +1 -0
- package/dist/api/routes/working.js +88 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +492 -0
- package/dist/integrations/claude-code.d.ts +12 -0
- package/dist/integrations/claude-code.js +35 -0
- package/dist/integrations/codex.d.ts +12 -0
- package/dist/integrations/codex.js +34 -0
- package/dist/integrations/generic-mcp.d.ts +52 -0
- package/dist/integrations/generic-mcp.js +118 -0
- package/dist/loader.d.ts +29 -0
- package/dist/loader.js +200 -0
- package/dist/memory/capture.d.ts +35 -0
- package/dist/memory/capture.js +230 -0
- package/dist/memory/config.d.ts +2 -0
- package/dist/memory/config.js +3 -0
- package/dist/memory/engine.d.ts +203 -0
- package/dist/memory/engine.js +626 -0
- package/dist/memory/llm-semaphore.d.ts +41 -0
- package/dist/memory/llm-semaphore.js +81 -0
- package/dist/memory/memory-type-config.d.ts +11 -0
- package/dist/memory/memory-type-config.js +65 -0
- package/dist/memory/pipeline/cognitive-contradiction.d.ts +7 -0
- package/dist/memory/pipeline/cognitive-contradiction.js +59 -0
- package/dist/memory/pipeline/cognitive-dedup.d.ts +23 -0
- package/dist/memory/pipeline/cognitive-dedup.js +38 -0
- package/dist/memory/pipeline/cognitive-extractor.d.ts +21 -0
- package/dist/memory/pipeline/cognitive-extractor.js +183 -0
- package/dist/memory/pipeline/contextual-focus-builder.d.ts +13 -0
- package/dist/memory/pipeline/contextual-focus-builder.js +135 -0
- package/dist/memory/pipeline/focus-direction-shift.d.ts +10 -0
- package/dist/memory/pipeline/focus-direction-shift.js +27 -0
- package/dist/memory/pipeline/graph-builder.d.ts +11 -0
- package/dist/memory/pipeline/graph-builder.js +88 -0
- package/dist/memory/pipeline/graph-recall.d.ts +13 -0
- package/dist/memory/pipeline/graph-recall.js +55 -0
- package/dist/memory/pipeline/identity-distiller.d.ts +15 -0
- package/dist/memory/pipeline/identity-distiller.js +40 -0
- package/dist/memory/pipeline/l1-contradiction.d.ts +7 -0
- package/dist/memory/pipeline/l1-contradiction.js +66 -0
- package/dist/memory/pipeline/l1-dedup.d.ts +23 -0
- package/dist/memory/pipeline/l1-dedup.js +39 -0
- package/dist/memory/pipeline/l1-extractor.d.ts +21 -0
- package/dist/memory/pipeline/l1-extractor.js +180 -0
- package/dist/memory/pipeline/l2-direction-shift.d.ts +10 -0
- package/dist/memory/pipeline/l2-direction-shift.js +27 -0
- package/dist/memory/pipeline/l2-scene.d.ts +15 -0
- package/dist/memory/pipeline/l2-scene.js +140 -0
- package/dist/memory/pipeline/l3-distiller.d.ts +15 -0
- package/dist/memory/pipeline/l3-distiller.js +40 -0
- package/dist/memory/pipeline/neural-spark.d.ts +27 -0
- package/dist/memory/pipeline/neural-spark.js +78 -0
- package/dist/memory/pipeline/skill-prewarm.d.ts +63 -0
- package/dist/memory/pipeline/skill-prewarm.js +127 -0
- package/dist/memory/pipeline/task-queue.d.ts +54 -0
- package/dist/memory/pipeline/task-queue.js +117 -0
- package/dist/memory/prompts/cognitive-contradiction.d.ts +1 -0
- package/dist/memory/prompts/cognitive-contradiction.js +25 -0
- package/dist/memory/prompts/cognitive-extraction.d.ts +10 -0
- package/dist/memory/prompts/cognitive-extraction.js +114 -0
- package/dist/memory/prompts/core-identity.d.ts +6 -0
- package/dist/memory/prompts/core-identity.js +60 -0
- package/dist/memory/prompts/focus-direction-shift.d.ts +5 -0
- package/dist/memory/prompts/focus-direction-shift.js +32 -0
- package/dist/memory/prompts/focus-scene-cluster.d.ts +2 -0
- package/dist/memory/prompts/focus-scene-cluster.js +33 -0
- package/dist/memory/prompts/focus-scene.d.ts +7 -0
- package/dist/memory/prompts/focus-scene.js +40 -0
- package/dist/memory/prompts/graph-extraction-batch.d.ts +14 -0
- package/dist/memory/prompts/graph-extraction-batch.js +54 -0
- package/dist/memory/prompts/graph-extraction.d.ts +2 -0
- package/dist/memory/prompts/graph-extraction.js +53 -0
- package/dist/memory/prompts/l1-contradiction-batch.d.ts +16 -0
- package/dist/memory/prompts/l1-contradiction-batch.js +47 -0
- package/dist/memory/prompts/l1-contradiction.d.ts +1 -0
- package/dist/memory/prompts/l1-contradiction.js +25 -0
- package/dist/memory/prompts/l1-extraction.d.ts +10 -0
- package/dist/memory/prompts/l1-extraction.js +114 -0
- package/dist/memory/prompts/l2-direction-shift.d.ts +5 -0
- package/dist/memory/prompts/l2-direction-shift.js +32 -0
- package/dist/memory/prompts/l2-scene-cluster.d.ts +2 -0
- package/dist/memory/prompts/l2-scene-cluster.js +33 -0
- package/dist/memory/prompts/l2-scene.d.ts +7 -0
- package/dist/memory/prompts/l2-scene.js +40 -0
- package/dist/memory/prompts/l3-persona.d.ts +6 -0
- package/dist/memory/prompts/l3-persona.js +60 -0
- package/dist/memory/recall.d.ts +47 -0
- package/dist/memory/recall.js +427 -0
- package/dist/memory/redaction.d.ts +1 -0
- package/dist/memory/redaction.js +24 -0
- package/dist/memory/retry.d.ts +13 -0
- package/dist/memory/retry.js +53 -0
- package/dist/memory/scheduler.d.ts +9 -0
- package/dist/memory/scheduler.js +16 -0
- package/dist/memory/skill-hints-loader.d.ts +30 -0
- package/dist/memory/skill-hints-loader.js +100 -0
- package/dist/memory/store/embedding.d.ts +16 -0
- package/dist/memory/store/embedding.js +68 -0
- package/dist/memory/store/reranker.d.ts +24 -0
- package/dist/memory/store/reranker.js +83 -0
- package/dist/memory/store/sqlite.d.ts +167 -0
- package/dist/memory/store/sqlite.js +1816 -0
- package/dist/memory/store/types.d.ts +101 -0
- package/dist/memory/store/types.js +1 -0
- package/dist/memory/types.d.ts +207 -0
- package/dist/memory/types.js +7 -0
- package/dist/memory/validation.d.ts +441 -0
- package/dist/memory/validation.js +129 -0
- package/dist/memory/working/canvas.d.ts +5 -0
- package/dist/memory/working/canvas.js +43 -0
- package/dist/memory/working/offload.d.ts +71 -0
- package/dist/memory/working/offload.js +211 -0
- package/dist/memory/working/step-log.d.ts +16 -0
- package/dist/memory/working/step-log.js +35 -0
- package/dist/registry.d.ts +34 -0
- package/dist/registry.js +305 -0
- package/dist/resolver.d.ts +17 -0
- package/dist/resolver.js +126 -0
- package/dist/scripts/validate-foreign-workspace-path.d.ts +1 -0
- package/dist/scripts/validate-foreign-workspace-path.js +39 -0
- package/dist/tools/agent_memory_tools.d.ts +485 -0
- package/dist/tools/agent_memory_tools.js +793 -0
- package/dist/tools/create_skill.d.ts +46 -0
- package/dist/tools/create_skill.js +46 -0
- package/dist/tools/get_doc.d.ts +21 -0
- package/dist/tools/get_doc.js +24 -0
- package/dist/tools/get_persona.d.ts +15 -0
- package/dist/tools/get_persona.js +20 -0
- package/dist/tools/get_reference.d.ts +15 -0
- package/dist/tools/get_reference.js +20 -0
- package/dist/tools/get_skill.d.ts +34 -0
- package/dist/tools/get_skill.js +65 -0
- package/dist/tools/get_template_doc.d.ts +21 -0
- package/dist/tools/get_template_doc.js +24 -0
- package/dist/tools/list_docs.d.ts +15 -0
- package/dist/tools/list_docs.js +16 -0
- package/dist/tools/list_skills.d.ts +18 -0
- package/dist/tools/list_skills.js +17 -0
- package/dist/tools/list_template_docs.d.ts +15 -0
- package/dist/tools/list_template_docs.js +16 -0
- package/dist/tools/memory-engineering.d.ts +225 -0
- package/dist/tools/memory-engineering.js +284 -0
- package/dist/tools/memory-explain.d.ts +34 -0
- package/dist/tools/memory-explain.js +109 -0
- package/dist/tools/memory-governance.d.ts +171 -0
- package/dist/tools/memory-governance.js +224 -0
- package/dist/tools/memory-hooks.d.ts +67 -0
- package/dist/tools/memory-hooks.js +102 -0
- package/dist/tools/memory-working.d.ts +98 -0
- package/dist/tools/memory-working.js +101 -0
- package/dist/tools/memory_capture_turn.d.ts +66 -0
- package/dist/tools/memory_capture_turn.js +85 -0
- package/dist/tools/memory_consolidate.d.ts +55 -0
- package/dist/tools/memory_consolidate.js +176 -0
- package/dist/tools/memory_contradictions.d.ts +53 -0
- package/dist/tools/memory_contradictions.js +52 -0
- package/dist/tools/memory_graph_query.d.ts +51 -0
- package/dist/tools/memory_graph_query.js +35 -0
- package/dist/tools/memory_mark_cited.d.ts +43 -0
- package/dist/tools/memory_mark_cited.js +63 -0
- package/dist/tools/memory_recall.d.ts +77 -0
- package/dist/tools/memory_recall.js +81 -0
- package/dist/tools/memory_register_skill_hints.d.ts +49 -0
- package/dist/tools/memory_register_skill_hints.js +55 -0
- package/dist/tools/memory_resolve_session.d.ts +24 -0
- package/dist/tools/memory_resolve_session.js +133 -0
- package/dist/tools/memory_search.d.ts +146 -0
- package/dist/tools/memory_search.js +84 -0
- package/dist/tools/search_skills.d.ts +18 -0
- package/dist/tools/search_skills.js +17 -0
- package/dist/tools/update_doc.d.ts +24 -0
- package/dist/tools/update_doc.js +35 -0
- package/dist/tools/update_skill.d.ts +30 -0
- package/dist/tools/update_skill.js +80 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.js +4 -0
- package/dist/writer.d.ts +30 -0
- package/dist/writer.js +220 -0
- package/docs/TEMPLATE ONLY +1 -0
- package/docs/api/API.md +64 -0
- package/docs/api/security/SECURITY.md +58 -0
- package/docs/deployment/DockerDeployment.md +30 -0
- package/docs/design/Design.md +59 -0
- package/docs/design/themes/apple.md +101 -0
- package/docs/design/themes/dieter-grid.md +100 -0
- package/docs/design/themes/gallery-white.md +100 -0
- package/docs/design/themes/pinterest.md +101 -0
- package/docs/design/themes/realty-open-house.md +101 -0
- package/docs/design/themes/vodafone.md +101 -0
- package/docs/hooks/Hooks.md +30 -0
- package/docs/schema/Schema.md +35 -0
- package/docs/strategy/ScalingStrategy.md +19 -0
- package/package.json +88 -0
- package/references/accessibility-checklist.md +160 -0
- package/references/orchestration-patterns.md +370 -0
- package/references/performance-checklist.md +153 -0
- package/references/security-checklist.md +134 -0
- package/references/testing-patterns.md +236 -0
- package/skills/agent/adr-skill/SKILL.md +299 -0
- package/skills/agent/agentic-engineering-workflow/SKILL.md +95 -0
- package/skills/agent/bootstrap-skill/SKILL.md +103 -0
- package/skills/agent/context-engineering/SKILL.md +307 -0
- package/skills/agent/debugging-and-error-recovery/SKILL.md +308 -0
- package/skills/agent/developer-growth-analysis/SKILL.md +328 -0
- package/skills/agent/doubt-driven-skill/SKILL.md +249 -0
- package/skills/agent/handover-skill/SKILL.md +112 -0
- package/skills/agent/idea-refine-skill/SKILL.md +185 -0
- package/skills/agent/idea-refine-skill/examples.md +238 -0
- package/skills/agent/idea-refine-skill/frameworks.md +99 -0
- package/skills/agent/idea-refine-skill/refinement-criteria.md +113 -0
- package/skills/agent/interview-skill/SKILL.md +226 -0
- package/skills/agent/planning-skill/SKILL.md +270 -0
- package/skills/agent/skill-authoring/SKILL.md +189 -0
- package/skills/agent/source-driven-skill/SKILL.md +197 -0
- package/skills/agent/spec-driven-skill/SKILL.md +221 -0
- package/skills/agent/sync-skill/SKILL.md +92 -0
- package/skills/agent/using-agent-skills/SKILL.md +189 -0
- package/skills/api/a11y-skill/SKILL.md +88 -0
- package/skills/api/api-skill/SKILL.md +123 -0
- package/skills/api/auth-skill/SKILL.md +80 -0
- package/skills/api/debug-skill/SKILL.md +535 -0
- package/skills/api/performance-skill/SKILL.md +100 -0
- package/skills/api/testing-skill/SKILL.md +100 -0
- package/skills/codebase/code-review-and-quality/SKILL.md +228 -0
- package/skills/codebase/code-simplification/SKILL.md +352 -0
- package/skills/codebase/code-structure-cleanup/SKILL.md +142 -0
- package/skills/codebase/concerns-skill/SKILL.md +89 -0
- package/skills/codebase/conventions-skill/SKILL.md +95 -0
- package/skills/codebase/doc-management-skill/SKILL.md +47 -0
- package/skills/codebase/git-workflow-skill/SKILL.md +312 -0
- package/skills/communication/1-3-1-rule/SKILL.md +120 -0
- package/skills/design/brutalist-skill/SKILL.md +131 -0
- package/skills/design/concept-diagrams/SKILL.md +387 -0
- package/skills/design/concept-diagrams/examples/apartment-floor-plan-conversion.md +244 -0
- package/skills/design/concept-diagrams/examples/automated-password-reset-flow.md +276 -0
- package/skills/design/concept-diagrams/examples/autonomous-llm-research-agent-flow.md +240 -0
- package/skills/design/concept-diagrams/examples/banana-journey-tree-to-smoothie.md +161 -0
- package/skills/design/concept-diagrams/examples/commercial-aircraft-structure.md +209 -0
- package/skills/design/concept-diagrams/examples/cpu-ooo-microarchitecture.md +236 -0
- package/skills/design/concept-diagrams/examples/electricity-grid-flow.md +182 -0
- package/skills/design/concept-diagrams/examples/feature-film-production-pipeline.md +172 -0
- package/skills/design/concept-diagrams/examples/hospital-emergency-department-flow.md +165 -0
- package/skills/design/concept-diagrams/examples/ml-benchmark-grouped-bar-chart.md +114 -0
- package/skills/design/concept-diagrams/examples/place-order-uml-sequence.md +325 -0
- package/skills/design/concept-diagrams/examples/smart-city-infrastructure.md +173 -0
- package/skills/design/concept-diagrams/examples/smartphone-layer-anatomy.md +154 -0
- package/skills/design/concept-diagrams/examples/sn2-reaction-mechanism.md +247 -0
- package/skills/design/concept-diagrams/examples/wind-turbine-structure.md +338 -0
- package/skills/design/concept-diagrams/references/dashboard-patterns.md +43 -0
- package/skills/design/concept-diagrams/references/infrastructure-patterns.md +144 -0
- package/skills/design/concept-diagrams/references/physical-shape-cookbook.md +42 -0
- package/skills/design/concept-diagrams/templates/template.html +174 -0
- package/skills/design/gpt-tasteskill/SKILL.md +114 -0
- package/skills/design/minimalist-skill/SKILL.md +116 -0
- package/skills/design/output-skill/SKILL.md +87 -0
- package/skills/design/redesign-skill/SKILL.md +213 -0
- package/skills/design/soft-skill/SKILL.md +132 -0
- package/skills/design/stitch-skill/EXAMPLE.md +121 -0
- package/skills/design/stitch-skill/SKILL.md +222 -0
- package/skills/design/taste-skill/SKILL.md +269 -0
- package/skills/devops/ci-cd-skill/SKILL.md +402 -0
- package/skills/devops/docker-skill/SKILL.md +297 -0
- package/skills/devops/domain-skill/SKILL.md +234 -0
- package/skills/lifecycle/changelog-generator/SKILL.md +135 -0
- package/skills/lifecycle/incremental-skill/SKILL.md +257 -0
- package/skills/lifecycle/migration-skill/SKILL.md +218 -0
- package/skills/lifecycle/shipping-skill/SKILL.md +321 -0
- package/skills/memory/agent-memory/SKILL.md +122 -0
- package/skills/qa/browser-testing-skill/SKILL.md +314 -0
- package/skills/ux/adversarial-ux-skill/SKILL.md +168 -0
|
@@ -0,0 +1,793 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import { memoryEngine } from "../memory/engine.js";
|
|
4
|
+
import { L1CommitPayloadSchema, ContradictionDecisionCommitSchema, GraphCommitSchema, L2CommitSchema, L3CommitSchema, normalizeSceneName, normalizeSkillTag, normalizeMemoryContent, normalizeEntityName, validateL0RecordOwnership, validateL1RecordOwnership, } from "../memory/validation.js";
|
|
5
|
+
import { EXTRACT_MEMORIES_SYSTEM_PROMPT, formatExtractionPrompt } from "../memory/prompts/l1-extraction.js";
|
|
6
|
+
import { L1_CONTRADICTION_PROMPT } from "../memory/prompts/l1-contradiction.js";
|
|
7
|
+
import { GRAPH_EXTRACTION_SYSTEM_PROMPT } from "../memory/prompts/graph-extraction.js";
|
|
8
|
+
import { L2_SCENE_SYSTEM_PROMPT } from "../memory/prompts/l2-scene.js";
|
|
9
|
+
import { L3_PERSONA_SYSTEM_PROMPT, formatL3PersonaPrompt } from "../memory/prompts/l3-persona.js";
|
|
10
|
+
import { deduplicateMemories } from "../memory/pipeline/l1-dedup.js";
|
|
11
|
+
import { L2_MAX_SCENES } from "../memory/scheduler.js";
|
|
12
|
+
// ============================
|
|
13
|
+
// Schemas for MCP Tool Registration
|
|
14
|
+
// ============================
|
|
15
|
+
export const memoryGetExtractionWorkSchema = {
|
|
16
|
+
name: "memory_get_extraction_work",
|
|
17
|
+
description: "Get pending conversational L0 messages that need to be distilled into L1 memories.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
userId: { type: "string", description: "The ID of the user." },
|
|
22
|
+
sessionKey: { type: "string", description: "The session key." },
|
|
23
|
+
limit: { type: "number", description: "Maximum number of L0 messages to retrieve.", default: 10 },
|
|
24
|
+
activeSkill: { type: "string", description: "The currently active skill." }
|
|
25
|
+
},
|
|
26
|
+
required: ["userId", "sessionKey"]
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const memoryCommitExtractedL1Schema = {
|
|
30
|
+
name: "memory_commit_extracted_l1",
|
|
31
|
+
description: "Commit newly extracted L1 memories for a session, automatically generating vector embeddings and running deduplication.",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
userId: { type: "string" },
|
|
36
|
+
sessionKey: { type: "string" },
|
|
37
|
+
sessionId: { type: "string", default: "" },
|
|
38
|
+
sourceL0Ids: { type: "array", items: { type: "string" } },
|
|
39
|
+
scenes: {
|
|
40
|
+
type: "array",
|
|
41
|
+
items: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
sceneName: { type: "string" },
|
|
45
|
+
memories: {
|
|
46
|
+
type: "array",
|
|
47
|
+
items: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
content: { type: "string" },
|
|
51
|
+
type: { type: "string", enum: ["persona", "episodic", "instruction", "skill_context"] },
|
|
52
|
+
priority: { type: "number", minimum: 0, maximum: 100, default: 50 },
|
|
53
|
+
skillTag: { type: "string", default: "" },
|
|
54
|
+
metadata: { type: "object", default: {} }
|
|
55
|
+
},
|
|
56
|
+
required: ["content", "type"]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
required: ["sceneName", "memories"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
required: ["userId", "sessionKey", "scenes"]
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
export const memoryGetContradictionWorkSchema = {
|
|
68
|
+
name: "memory_get_contradiction_work",
|
|
69
|
+
description: "Get pending L1 memories that need to be evaluated for semantic contradictions or temporal updates against existing memories.",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: {
|
|
73
|
+
userId: { type: "string" },
|
|
74
|
+
limit: { type: "number", default: 20 }
|
|
75
|
+
},
|
|
76
|
+
required: ["userId"]
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
export const memoryCommitContradictionDecisionsSchema = {
|
|
80
|
+
name: "memory_commit_contradiction_decisions",
|
|
81
|
+
description: "Commit decisions on contradiction candidates, invalidating/superseding old records or logging genuine conflicts.",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
userId: { type: "string" },
|
|
86
|
+
decisions: {
|
|
87
|
+
type: "array",
|
|
88
|
+
items: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
newRecordId: { type: "string" },
|
|
92
|
+
existingRecordId: { type: "string" },
|
|
93
|
+
decision: { type: "string", enum: ["no_conflict", "temporal_update", "genuine_conflict"] },
|
|
94
|
+
reason: { type: "string" },
|
|
95
|
+
confidence: { type: "number", minimum: 0, maximum: 1, default: 1.0 }
|
|
96
|
+
},
|
|
97
|
+
required: ["newRecordId", "existingRecordId", "decision"]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
required: ["userId", "decisions"]
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
export const memoryGetGraphWorkSchema = {
|
|
105
|
+
name: "memory_get_graph_work",
|
|
106
|
+
description: "Get pending L1 memories that have not yet had GraphRAG entities and relationships extracted from them.",
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: "object",
|
|
109
|
+
properties: {
|
|
110
|
+
userId: { type: "string" },
|
|
111
|
+
limit: { type: "number", default: 20 }
|
|
112
|
+
},
|
|
113
|
+
required: ["userId"]
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
export const memoryCommitGraphSchema = {
|
|
117
|
+
name: "memory_commit_graph",
|
|
118
|
+
description: "Commit entities and relations extracted from an L1 memory, updating the GraphRAG knowledge graph.",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
userId: { type: "string" },
|
|
123
|
+
sourceRecordId: { type: "string" },
|
|
124
|
+
entities: {
|
|
125
|
+
type: "array",
|
|
126
|
+
items: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
entity: { type: "string" },
|
|
130
|
+
type: { type: "string", default: "concept" },
|
|
131
|
+
confidence: { type: "number", minimum: 0, maximum: 1, default: 1.0 },
|
|
132
|
+
skillTag: { type: "string", default: "" },
|
|
133
|
+
sourceRecordId: { type: "string" }
|
|
134
|
+
},
|
|
135
|
+
required: ["entity"]
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
relations: {
|
|
139
|
+
type: "array",
|
|
140
|
+
items: {
|
|
141
|
+
type: "object",
|
|
142
|
+
properties: {
|
|
143
|
+
from: { type: "string" },
|
|
144
|
+
to: { type: "string" },
|
|
145
|
+
relation: { type: "string", default: "relates_to" },
|
|
146
|
+
confidence: { type: "number", minimum: 0, maximum: 1, default: 1.0 },
|
|
147
|
+
skillTag: { type: "string", default: "" },
|
|
148
|
+
sourceRecordId: { type: "string" }
|
|
149
|
+
},
|
|
150
|
+
required: ["from", "to"]
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
required: ["userId"]
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
export const memoryGetL2WorkSchema = {
|
|
158
|
+
name: "memory_get_l2_work",
|
|
159
|
+
description: "Get L1 memories grouped by scenes to perform scene narrative summary distillation or cold scene merges.",
|
|
160
|
+
inputSchema: {
|
|
161
|
+
type: "object",
|
|
162
|
+
properties: {
|
|
163
|
+
userId: { type: "string" }
|
|
164
|
+
},
|
|
165
|
+
required: ["userId"]
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
export const memoryCommitL2Schema = {
|
|
169
|
+
name: "memory_commit_l2",
|
|
170
|
+
description: "Commit scene summaries, scene name renames (clustering), or cold scene merge distillations.",
|
|
171
|
+
inputSchema: {
|
|
172
|
+
type: "object",
|
|
173
|
+
properties: {
|
|
174
|
+
userId: { type: "string" },
|
|
175
|
+
renames: {
|
|
176
|
+
type: "array",
|
|
177
|
+
items: {
|
|
178
|
+
type: "object",
|
|
179
|
+
properties: {
|
|
180
|
+
oldName: { type: "string" },
|
|
181
|
+
newName: { type: "string" }
|
|
182
|
+
},
|
|
183
|
+
required: ["oldName", "newName"]
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
scenes: {
|
|
187
|
+
type: "array",
|
|
188
|
+
items: {
|
|
189
|
+
type: "object",
|
|
190
|
+
properties: {
|
|
191
|
+
sceneName: { type: "string" },
|
|
192
|
+
summaryMd: { type: "string" },
|
|
193
|
+
heatScore: { type: "number", minimum: 0, maximum: 100 }
|
|
194
|
+
},
|
|
195
|
+
required: ["sceneName", "summaryMd"]
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
merges: {
|
|
199
|
+
type: "array",
|
|
200
|
+
items: {
|
|
201
|
+
type: "object",
|
|
202
|
+
properties: {
|
|
203
|
+
sceneIds: { type: "array", items: { type: "string" } },
|
|
204
|
+
mergedSummaryMd: { type: "string" }
|
|
205
|
+
},
|
|
206
|
+
required: ["sceneIds", "mergedSummaryMd"]
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
required: ["userId"]
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
export const memoryGetL3WorkSchema = {
|
|
214
|
+
name: "memory_get_l3_work",
|
|
215
|
+
description: "Get L1 persona and instruction memories across all sessions to compile a synthesized L3 Narrative Profile.",
|
|
216
|
+
inputSchema: {
|
|
217
|
+
type: "object",
|
|
218
|
+
properties: {
|
|
219
|
+
userId: { type: "string" }
|
|
220
|
+
},
|
|
221
|
+
required: ["userId"]
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
export const memoryCommitL3Schema = {
|
|
225
|
+
name: "memory_commit_l3",
|
|
226
|
+
description: "Commit a synthesized L3 Narrative Profile summary, invalidating persona caches.",
|
|
227
|
+
inputSchema: {
|
|
228
|
+
type: "object",
|
|
229
|
+
properties: {
|
|
230
|
+
userId: { type: "string" },
|
|
231
|
+
personaMd: { type: "string" }
|
|
232
|
+
},
|
|
233
|
+
required: ["userId", "personaMd"]
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
// ============================
|
|
237
|
+
// Tool Dispatcher Handlers
|
|
238
|
+
// ============================
|
|
239
|
+
export async function handleMemoryGetExtractionWork(args) {
|
|
240
|
+
const params = z.object({
|
|
241
|
+
userId: z.string(),
|
|
242
|
+
sessionKey: z.string(),
|
|
243
|
+
limit: z.number().optional().default(10),
|
|
244
|
+
activeSkill: z.string().optional(),
|
|
245
|
+
}).parse(args);
|
|
246
|
+
const store = memoryEngine.store;
|
|
247
|
+
try {
|
|
248
|
+
const unextractedCount = store.getUnextractedL0Count(params.userId, params.sessionKey);
|
|
249
|
+
if (unextractedCount === 0) {
|
|
250
|
+
return {
|
|
251
|
+
content: [{
|
|
252
|
+
type: "text",
|
|
253
|
+
text: JSON.stringify({ status: "no_work", message: "No unextracted L0 messages in this session." }, null, 2)
|
|
254
|
+
}]
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const messages = store.getRecentL0Messages(params.userId, params.sessionKey, params.limit, "", true);
|
|
258
|
+
const existingSceneNames = store.getTopL2Scenes(params.userId, 20).map((s) => s.sceneName);
|
|
259
|
+
const skillHints = params.activeSkill ? (store.getSkillHints(params.activeSkill) ?? undefined) : undefined;
|
|
260
|
+
// Build the instruction templates
|
|
261
|
+
const qualifiedMessages = messages.filter((m) => {
|
|
262
|
+
const clean = m.messageText.trim();
|
|
263
|
+
return clean.length >= 3 && !/^[^a-zA-Z\u4e00-\u9fa5]+$/.test(clean);
|
|
264
|
+
});
|
|
265
|
+
const userPrompt = formatExtractionPrompt({
|
|
266
|
+
newMessages: qualifiedMessages,
|
|
267
|
+
backgroundMessages: [],
|
|
268
|
+
previousSceneName: "None",
|
|
269
|
+
existingSceneNames,
|
|
270
|
+
activeSkill: params.activeSkill,
|
|
271
|
+
skillHints
|
|
272
|
+
});
|
|
273
|
+
return {
|
|
274
|
+
content: [{
|
|
275
|
+
type: "text",
|
|
276
|
+
text: JSON.stringify({
|
|
277
|
+
status: "work_available",
|
|
278
|
+
userId: params.userId,
|
|
279
|
+
sessionKey: params.sessionKey,
|
|
280
|
+
messages,
|
|
281
|
+
unextractedCount,
|
|
282
|
+
remainingUnextractedCount: Math.max(0, unextractedCount - messages.length),
|
|
283
|
+
existingSceneNames,
|
|
284
|
+
skillHints,
|
|
285
|
+
prompts: {
|
|
286
|
+
systemPrompt: EXTRACT_MEMORIES_SYSTEM_PROMPT,
|
|
287
|
+
userPrompt
|
|
288
|
+
}
|
|
289
|
+
}, null, 2)
|
|
290
|
+
}]
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
return {
|
|
295
|
+
isError: true,
|
|
296
|
+
content: [{ type: "text", text: `Failed to retrieve extraction work: ${err.message}` }]
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
export async function handleMemoryCommitExtractedL1(args) {
|
|
301
|
+
const payload = L1CommitPayloadSchema.parse(args);
|
|
302
|
+
const store = memoryEngine.store;
|
|
303
|
+
const embeddingService = memoryEngine.capturePipeline.embeddingService;
|
|
304
|
+
try {
|
|
305
|
+
if (payload.sourceL0Ids.length > 0) {
|
|
306
|
+
validateL0RecordOwnership(store, payload.userId, payload.sourceL0Ids);
|
|
307
|
+
}
|
|
308
|
+
const records = [];
|
|
309
|
+
const now = new Date().toISOString();
|
|
310
|
+
for (const group of payload.scenes) {
|
|
311
|
+
const sceneName = normalizeSceneName(group.sceneName);
|
|
312
|
+
for (const mem of group.memories) {
|
|
313
|
+
records.push({
|
|
314
|
+
id: `l1_${payload.sessionKey}_${Date.now()}_${crypto.randomBytes(4).toString("hex")}`,
|
|
315
|
+
userId: payload.userId,
|
|
316
|
+
sessionKey: payload.sessionKey,
|
|
317
|
+
sessionId: payload.sessionId,
|
|
318
|
+
content: normalizeMemoryContent(mem.content),
|
|
319
|
+
type: mem.type,
|
|
320
|
+
priority: mem.priority,
|
|
321
|
+
sceneName,
|
|
322
|
+
skillTag: normalizeSkillTag(mem.skillTag),
|
|
323
|
+
halfLifeDays: mem.type === "instruction" ? null : (mem.type === "persona" ? 180 : (mem.type === "skill_context" ? 7 : 30)),
|
|
324
|
+
supersededBy: null,
|
|
325
|
+
timestampStr: "",
|
|
326
|
+
timestampStart: "",
|
|
327
|
+
timestampEnd: "",
|
|
328
|
+
createdTime: now,
|
|
329
|
+
updatedTime: now,
|
|
330
|
+
metadata: mem.metadata,
|
|
331
|
+
citationCount: 0,
|
|
332
|
+
lastCitedAt: null,
|
|
333
|
+
neverCitedCount: 0,
|
|
334
|
+
archived: false,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// Deduplication check
|
|
339
|
+
const { uniqueRecords, droppedCount } = await deduplicateMemories({
|
|
340
|
+
records,
|
|
341
|
+
store,
|
|
342
|
+
userId: payload.userId
|
|
343
|
+
});
|
|
344
|
+
const entries = [];
|
|
345
|
+
for (const record of uniqueRecords) {
|
|
346
|
+
let embedding;
|
|
347
|
+
if (embeddingService.isReady()) {
|
|
348
|
+
try {
|
|
349
|
+
embedding = await embeddingService.embed(record.content);
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
console.error(`[BrainRouter] Embedding failed during commit for ${record.id}:`, err.message);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
entries.push({ record, embedding });
|
|
356
|
+
}
|
|
357
|
+
if (entries.length > 0) {
|
|
358
|
+
store.upsertL1Batch(entries);
|
|
359
|
+
store.incrementSchedulerL1Count(payload.userId, entries.length);
|
|
360
|
+
}
|
|
361
|
+
if (payload.sourceL0Ids.length > 0) {
|
|
362
|
+
store.markL0ExtractedByIds(payload.userId, payload.sourceL0Ids);
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
content: [{
|
|
366
|
+
type: "text",
|
|
367
|
+
text: JSON.stringify({
|
|
368
|
+
committedCount: entries.length,
|
|
369
|
+
committedIds: uniqueRecords.map(r => r.id),
|
|
370
|
+
droppedDuplicateCount: droppedCount,
|
|
371
|
+
validationErrors: []
|
|
372
|
+
}, null, 2)
|
|
373
|
+
}]
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
return {
|
|
378
|
+
isError: true,
|
|
379
|
+
content: [{ type: "text", text: `Failed to commit L1 memories: ${err.message}` }]
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
export async function handleMemoryGetContradictionWork(args) {
|
|
384
|
+
const params = z.object({
|
|
385
|
+
userId: z.string(),
|
|
386
|
+
limit: z.number().optional().default(20),
|
|
387
|
+
}).parse(args);
|
|
388
|
+
const store = memoryEngine.store;
|
|
389
|
+
try {
|
|
390
|
+
const pendingL1s = store.getPendingContradictionL1s(params.userId, params.limit);
|
|
391
|
+
if (pendingL1s.length === 0) {
|
|
392
|
+
return {
|
|
393
|
+
content: [{
|
|
394
|
+
type: "text",
|
|
395
|
+
text: JSON.stringify({ status: "no_work", message: "No pending contradiction checks." }, null, 2)
|
|
396
|
+
}]
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
const pairs = [];
|
|
400
|
+
for (const newRecord of pendingL1s) {
|
|
401
|
+
const candidates = store.searchL1Fts(params.userId, newRecord.content, 5);
|
|
402
|
+
for (const cand of candidates) {
|
|
403
|
+
if (cand.record_id === newRecord.id)
|
|
404
|
+
continue;
|
|
405
|
+
pairs.push({
|
|
406
|
+
newRecord: {
|
|
407
|
+
id: newRecord.id,
|
|
408
|
+
content: newRecord.content,
|
|
409
|
+
type: newRecord.type
|
|
410
|
+
},
|
|
411
|
+
existingRecord: {
|
|
412
|
+
id: cand.record_id,
|
|
413
|
+
content: cand.content,
|
|
414
|
+
type: cand.type
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
content: [{
|
|
421
|
+
type: "text",
|
|
422
|
+
text: JSON.stringify({
|
|
423
|
+
status: pairs.length > 0 ? "work_available" : "no_work",
|
|
424
|
+
userId: params.userId,
|
|
425
|
+
pairs,
|
|
426
|
+
prompts: {
|
|
427
|
+
systemPrompt: L1_CONTRADICTION_PROMPT
|
|
428
|
+
}
|
|
429
|
+
}, null, 2)
|
|
430
|
+
}]
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
catch (err) {
|
|
434
|
+
return {
|
|
435
|
+
isError: true,
|
|
436
|
+
content: [{ type: "text", text: `Failed to retrieve contradiction work: ${err.message}` }]
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
export async function handleMemoryCommitContradictionDecisions(args) {
|
|
441
|
+
const payload = ContradictionDecisionCommitSchema.parse(args);
|
|
442
|
+
const store = memoryEngine.store;
|
|
443
|
+
try {
|
|
444
|
+
const allIds = payload.decisions.flatMap(d => [d.newRecordId, d.existingRecordId]);
|
|
445
|
+
validateL1RecordOwnership(store, payload.userId, [...new Set(allIds)]);
|
|
446
|
+
let processedCount = 0;
|
|
447
|
+
const processedIds = [];
|
|
448
|
+
for (const decision of payload.decisions) {
|
|
449
|
+
const newRec = store.getL1Record(payload.userId, decision.newRecordId);
|
|
450
|
+
if (!newRec)
|
|
451
|
+
continue;
|
|
452
|
+
if (decision.decision === "temporal_update") {
|
|
453
|
+
store.invalidateL1Record(payload.userId, decision.existingRecordId, decision.newRecordId, newRec.createdTime);
|
|
454
|
+
processedCount++;
|
|
455
|
+
processedIds.push(decision.newRecordId);
|
|
456
|
+
}
|
|
457
|
+
else if (decision.decision === "genuine_conflict") {
|
|
458
|
+
store.upsertContradiction({
|
|
459
|
+
id: `conflict_${crypto.randomBytes(4).toString("hex")}`,
|
|
460
|
+
userId: payload.userId,
|
|
461
|
+
recordIdA: decision.existingRecordId,
|
|
462
|
+
recordIdB: decision.newRecordId,
|
|
463
|
+
reason: decision.reason || "Genuine contradiction",
|
|
464
|
+
confidence: decision.confidence
|
|
465
|
+
});
|
|
466
|
+
processedCount++;
|
|
467
|
+
processedIds.push(decision.newRecordId);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// no_conflict
|
|
471
|
+
processedCount++;
|
|
472
|
+
processedIds.push(decision.newRecordId);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const uniqueNewIds = [...new Set(payload.decisions.map(d => d.newRecordId))];
|
|
476
|
+
store.markL1ContradictionChecked(payload.userId, uniqueNewIds);
|
|
477
|
+
return {
|
|
478
|
+
content: [{
|
|
479
|
+
type: "text",
|
|
480
|
+
text: JSON.stringify({
|
|
481
|
+
committedCount: processedCount,
|
|
482
|
+
committedIds: processedIds,
|
|
483
|
+
droppedDuplicateCount: 0,
|
|
484
|
+
validationErrors: []
|
|
485
|
+
}, null, 2)
|
|
486
|
+
}]
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
catch (err) {
|
|
490
|
+
return {
|
|
491
|
+
isError: true,
|
|
492
|
+
content: [{ type: "text", text: `Failed to commit contradiction decisions: ${err.message}` }]
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
export async function handleMemoryGetGraphWork(args) {
|
|
497
|
+
const params = z.object({
|
|
498
|
+
userId: z.string(),
|
|
499
|
+
limit: z.number().optional().default(20),
|
|
500
|
+
}).parse(args);
|
|
501
|
+
const store = memoryEngine.store;
|
|
502
|
+
try {
|
|
503
|
+
const pendingL1s = store.getPendingGraphL1s(params.userId, params.limit);
|
|
504
|
+
if (pendingL1s.length === 0) {
|
|
505
|
+
return {
|
|
506
|
+
content: [{
|
|
507
|
+
type: "text",
|
|
508
|
+
text: JSON.stringify({ status: "no_work", message: "No pending graph extractions." }, null, 2)
|
|
509
|
+
}]
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
content: [{
|
|
514
|
+
type: "text",
|
|
515
|
+
text: JSON.stringify({
|
|
516
|
+
status: "work_available",
|
|
517
|
+
userId: params.userId,
|
|
518
|
+
records: pendingL1s.map((r) => ({
|
|
519
|
+
id: r.id,
|
|
520
|
+
content: r.content,
|
|
521
|
+
skillTag: r.skillTag
|
|
522
|
+
})),
|
|
523
|
+
prompts: {
|
|
524
|
+
systemPrompt: GRAPH_EXTRACTION_SYSTEM_PROMPT
|
|
525
|
+
}
|
|
526
|
+
}, null, 2)
|
|
527
|
+
}]
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
catch (err) {
|
|
531
|
+
return {
|
|
532
|
+
isError: true,
|
|
533
|
+
content: [{ type: "text", text: `Failed to retrieve graph work: ${err.message}` }]
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
export async function handleMemoryCommitGraph(args) {
|
|
538
|
+
const payload = GraphCommitSchema.parse(args);
|
|
539
|
+
const store = memoryEngine.store;
|
|
540
|
+
try {
|
|
541
|
+
if (payload.sourceRecordId) {
|
|
542
|
+
validateL1RecordOwnership(store, payload.userId, [payload.sourceRecordId]);
|
|
543
|
+
}
|
|
544
|
+
const entityMap = new Map();
|
|
545
|
+
const committedIds = [];
|
|
546
|
+
// 1. Upsert Nodes
|
|
547
|
+
for (const ent of payload.entities) {
|
|
548
|
+
const entityName = normalizeEntityName(ent.entity);
|
|
549
|
+
const existing = store.getGraphNodeByEntity(payload.userId, entityName);
|
|
550
|
+
const nodeId = existing?.id ?? `gn_${crypto.randomBytes(6).toString("hex")}`;
|
|
551
|
+
entityMap.set(entityName.toLowerCase(), nodeId);
|
|
552
|
+
const node = {
|
|
553
|
+
id: nodeId,
|
|
554
|
+
userId: payload.userId,
|
|
555
|
+
entity: ent.entity,
|
|
556
|
+
entityType: ent.type || "concept",
|
|
557
|
+
skillTag: ent.skillTag || "",
|
|
558
|
+
confidence: ent.confidence || 1.0,
|
|
559
|
+
sourceRecordId: ent.sourceRecordId || payload.sourceRecordId || "",
|
|
560
|
+
createdTime: new Date().toISOString()
|
|
561
|
+
};
|
|
562
|
+
store.upsertGraphNode(node);
|
|
563
|
+
committedIds.push(nodeId);
|
|
564
|
+
}
|
|
565
|
+
// 2. Upsert Edges
|
|
566
|
+
for (const rel of payload.relations) {
|
|
567
|
+
const fromName = normalizeEntityName(rel.from);
|
|
568
|
+
const toName = normalizeEntityName(rel.to);
|
|
569
|
+
let fromNodeId = entityMap.get(fromName.toLowerCase());
|
|
570
|
+
if (!fromNodeId) {
|
|
571
|
+
fromNodeId = store.getGraphNodeByEntity(payload.userId, fromName)?.id;
|
|
572
|
+
}
|
|
573
|
+
let toNodeId = entityMap.get(toName.toLowerCase());
|
|
574
|
+
if (!toNodeId) {
|
|
575
|
+
toNodeId = store.getGraphNodeByEntity(payload.userId, toName)?.id;
|
|
576
|
+
}
|
|
577
|
+
if (!fromNodeId || !toNodeId)
|
|
578
|
+
continue;
|
|
579
|
+
const edgeId = `ge_${crypto.randomBytes(6).toString("hex")}`;
|
|
580
|
+
const edge = {
|
|
581
|
+
id: edgeId,
|
|
582
|
+
userId: payload.userId,
|
|
583
|
+
fromNodeId,
|
|
584
|
+
toNodeId,
|
|
585
|
+
relation: rel.relation || "relates_to",
|
|
586
|
+
skillTag: rel.skillTag || "",
|
|
587
|
+
confidence: rel.confidence || 1.0,
|
|
588
|
+
sourceRecordId: rel.sourceRecordId || payload.sourceRecordId || "",
|
|
589
|
+
createdTime: new Date().toISOString()
|
|
590
|
+
};
|
|
591
|
+
store.upsertGraphEdge(edge);
|
|
592
|
+
committedIds.push(edgeId);
|
|
593
|
+
}
|
|
594
|
+
if (payload.sourceRecordId) {
|
|
595
|
+
store.markL1GraphExtracted(payload.userId, [payload.sourceRecordId]);
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
content: [{
|
|
599
|
+
type: "text",
|
|
600
|
+
text: JSON.stringify({
|
|
601
|
+
committedCount: committedIds.length,
|
|
602
|
+
committedIds,
|
|
603
|
+
droppedDuplicateCount: 0,
|
|
604
|
+
validationErrors: []
|
|
605
|
+
}, null, 2)
|
|
606
|
+
}]
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
catch (err) {
|
|
610
|
+
return {
|
|
611
|
+
isError: true,
|
|
612
|
+
content: [{ type: "text", text: `Failed to commit graph elements: ${err.message}` }]
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
export async function handleMemoryGetL2Work(args) {
|
|
617
|
+
const params = z.object({
|
|
618
|
+
userId: z.string(),
|
|
619
|
+
}).parse(args);
|
|
620
|
+
const store = memoryEngine.store;
|
|
621
|
+
try {
|
|
622
|
+
const countState = store.getSchedulerState(params.userId);
|
|
623
|
+
const sceneNames = store.getDistinctSceneNames(params.userId);
|
|
624
|
+
const topL2Scenes = store.getTopL2Scenes(params.userId, 50);
|
|
625
|
+
const scenes = [];
|
|
626
|
+
for (const name of sceneNames) {
|
|
627
|
+
const l1s = store.getL1sByScene(params.userId, name, 30);
|
|
628
|
+
if (l1s.length > 0) {
|
|
629
|
+
scenes.push({ sceneName: name, memories: l1s });
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const sceneCount = store.getL2SceneCount(params.userId);
|
|
633
|
+
const overflow = sceneCount - L2_MAX_SCENES + 1;
|
|
634
|
+
const coldScenes = overflow > 0 ? store.getColdL2Scenes(params.userId, overflow + 3) : [];
|
|
635
|
+
return {
|
|
636
|
+
content: [{
|
|
637
|
+
type: "text",
|
|
638
|
+
text: JSON.stringify({
|
|
639
|
+
status: scenes.length > 0 ? "work_available" : "no_work",
|
|
640
|
+
userId: params.userId,
|
|
641
|
+
schedulerState: countState,
|
|
642
|
+
scenes,
|
|
643
|
+
existingL2Scenes: topL2Scenes,
|
|
644
|
+
coldScenesToMerge: coldScenes,
|
|
645
|
+
prompts: {
|
|
646
|
+
systemPrompt: L2_SCENE_SYSTEM_PROMPT
|
|
647
|
+
}
|
|
648
|
+
}, null, 2)
|
|
649
|
+
}]
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
catch (err) {
|
|
653
|
+
return {
|
|
654
|
+
isError: true,
|
|
655
|
+
content: [{ type: "text", text: `Failed to retrieve L2 work: ${err.message}` }]
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
export async function handleMemoryCommitL2(args) {
|
|
660
|
+
const payload = L2CommitSchema.parse(args);
|
|
661
|
+
const store = memoryEngine.store;
|
|
662
|
+
try {
|
|
663
|
+
const committedIds = [];
|
|
664
|
+
const now = new Date().toISOString();
|
|
665
|
+
// 1. Renames (clustering canonicalization)
|
|
666
|
+
for (const r of payload.renames) {
|
|
667
|
+
store.renameSceneInL1Records(payload.userId, r.oldName, r.newName);
|
|
668
|
+
}
|
|
669
|
+
// 2. Main distilled scenes
|
|
670
|
+
for (const scene of payload.scenes) {
|
|
671
|
+
const existing = store.getL2SceneByName(payload.userId, scene.sceneName);
|
|
672
|
+
const record = {
|
|
673
|
+
id: existing?.id ?? `l2_${crypto.randomBytes(6).toString("hex")}`,
|
|
674
|
+
userId: payload.userId,
|
|
675
|
+
sceneName: scene.sceneName,
|
|
676
|
+
summaryMd: scene.summaryMd,
|
|
677
|
+
heatScore: scene.heatScore !== undefined ? scene.heatScore : (existing ? Math.min(100, existing.heatScore + 30) : 100),
|
|
678
|
+
lastActiveTime: now,
|
|
679
|
+
createdTime: existing?.createdTime ?? now,
|
|
680
|
+
updatedTime: now
|
|
681
|
+
};
|
|
682
|
+
store.upsertL2Scene(record);
|
|
683
|
+
committedIds.push(record.id);
|
|
684
|
+
}
|
|
685
|
+
// 3. Merges into [Archived]
|
|
686
|
+
for (const merge of payload.merges) {
|
|
687
|
+
const existingArchive = store.getL2SceneByName(payload.userId, "[Archived]");
|
|
688
|
+
const record = {
|
|
689
|
+
id: existingArchive?.id ?? `l2_${crypto.randomBytes(6).toString("hex")}`,
|
|
690
|
+
userId: payload.userId,
|
|
691
|
+
sceneName: "[Archived]",
|
|
692
|
+
summaryMd: merge.mergedSummaryMd,
|
|
693
|
+
heatScore: 10,
|
|
694
|
+
lastActiveTime: now,
|
|
695
|
+
createdTime: existingArchive?.createdTime ?? now,
|
|
696
|
+
updatedTime: now
|
|
697
|
+
};
|
|
698
|
+
store.upsertL2Scene(record);
|
|
699
|
+
store.deleteL2Scenes(payload.userId, merge.sceneIds);
|
|
700
|
+
committedIds.push(record.id);
|
|
701
|
+
}
|
|
702
|
+
store.resetSchedulerL2Count(payload.userId);
|
|
703
|
+
store.decayL2HeatScores(payload.userId);
|
|
704
|
+
return {
|
|
705
|
+
content: [{
|
|
706
|
+
type: "text",
|
|
707
|
+
text: JSON.stringify({
|
|
708
|
+
committedCount: committedIds.length,
|
|
709
|
+
committedIds,
|
|
710
|
+
droppedDuplicateCount: 0,
|
|
711
|
+
validationErrors: []
|
|
712
|
+
}, null, 2)
|
|
713
|
+
}]
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
catch (err) {
|
|
717
|
+
return {
|
|
718
|
+
isError: true,
|
|
719
|
+
content: [{ type: "text", text: `Failed to commit L2 scenes: ${err.message}` }]
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
export async function handleMemoryGetL3Work(args) {
|
|
724
|
+
const params = z.object({
|
|
725
|
+
userId: z.string(),
|
|
726
|
+
}).parse(args);
|
|
727
|
+
const store = memoryEngine.store;
|
|
728
|
+
try {
|
|
729
|
+
const memories = store.getPersonaAndInstructionL1s(params.userId, 100);
|
|
730
|
+
const existing = store.getL3Persona(params.userId);
|
|
731
|
+
return {
|
|
732
|
+
content: [{
|
|
733
|
+
type: "text",
|
|
734
|
+
text: JSON.stringify({
|
|
735
|
+
status: memories.length > 0 ? "work_available" : "no_work",
|
|
736
|
+
userId: params.userId,
|
|
737
|
+
memories,
|
|
738
|
+
existingPersona: existing,
|
|
739
|
+
prompts: {
|
|
740
|
+
systemPrompt: L3_PERSONA_SYSTEM_PROMPT,
|
|
741
|
+
userPrompt: formatL3PersonaPrompt(memories)
|
|
742
|
+
}
|
|
743
|
+
}, null, 2)
|
|
744
|
+
}]
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
catch (err) {
|
|
748
|
+
return {
|
|
749
|
+
isError: true,
|
|
750
|
+
content: [{ type: "text", text: `Failed to retrieve L3 work: ${err.message}` }]
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
export async function handleMemoryCommitL3(args) {
|
|
755
|
+
const payload = L3CommitSchema.parse(args);
|
|
756
|
+
const store = memoryEngine.store;
|
|
757
|
+
try {
|
|
758
|
+
const memories = store.getPersonaAndInstructionL1s(payload.userId, 100);
|
|
759
|
+
const existing = store.getL3Persona(payload.userId);
|
|
760
|
+
const now = new Date().toISOString();
|
|
761
|
+
const record = {
|
|
762
|
+
userId: payload.userId,
|
|
763
|
+
personaMd: payload.personaMd,
|
|
764
|
+
l1CountAtGeneration: memories.length,
|
|
765
|
+
createdTime: existing?.createdTime ?? now,
|
|
766
|
+
updatedTime: now
|
|
767
|
+
};
|
|
768
|
+
store.upsertL3Persona(record);
|
|
769
|
+
// Invalidate local in-memory cache
|
|
770
|
+
const cache = memoryEngine.personaCache;
|
|
771
|
+
if (cache) {
|
|
772
|
+
cache.set(payload.userId, { personaMd: payload.personaMd, cachedAt: Date.now() });
|
|
773
|
+
}
|
|
774
|
+
store.resetSchedulerL3Count(payload.userId);
|
|
775
|
+
return {
|
|
776
|
+
content: [{
|
|
777
|
+
type: "text",
|
|
778
|
+
text: JSON.stringify({
|
|
779
|
+
committedCount: 1,
|
|
780
|
+
committedIds: [payload.userId],
|
|
781
|
+
droppedDuplicateCount: 0,
|
|
782
|
+
validationErrors: []
|
|
783
|
+
}, null, 2)
|
|
784
|
+
}]
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
catch (err) {
|
|
788
|
+
return {
|
|
789
|
+
isError: true,
|
|
790
|
+
content: [{ type: "text", text: `Failed to commit L3 persona: ${err.message}` }]
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
}
|