cogmemory 0.0.1-beta.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.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # Cognitive Memory — SDK
2
+
3
+ TypeScript client for [Cognitive Memory](../../apps/cognitive-memory): deterministic
4
+ four-tier memory for agents, served as a credentialed storage layer.
5
+
6
+ ~3.2kB gzipped, ESM-first, one small peer dependency.
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ npm i @astracollab/cogmem ofetch
12
+ ```
13
+
14
+ `ofetch` is a peer dependency on purpose — it is ~5kB, works in Node, Deno,
15
+ Workers and the browser, and bundling a second copy inside every consumer that
16
+ already has one helps nobody.
17
+
18
+ ## Use
19
+
20
+ ```ts
21
+ import { createClient, runTurn } from "@astracollab/cogmem"
22
+
23
+ const memory = createClient({
24
+ apiKey: process.env.COGNITIVE_MEMORY_KEY!,
25
+ baseUrl: "http://localhost:3000",
26
+ debug: process.env.DEBUG !== undefined
27
+ })
28
+ ```
29
+
30
+ Get a key from the dashboard. It is shown once, because only a hash is stored.
31
+
32
+ ## The two calls that matter
33
+
34
+ ```ts
35
+ // Before the model runs.
36
+ const { text, totalTokens } = await memory.context.build({ userMessage })
37
+
38
+ // After the reply finishes streaming.
39
+ const learned = await memory.turns.learn({ userMessage, assistantResponse })
40
+ ```
41
+
42
+ `runTurn` does both, in the right order, and will not let a memory failure take
43
+ down a turn that already produced an answer:
44
+
45
+ ```ts
46
+ const { context, learning, learningSkipped } = await runTurn(
47
+ memory,
48
+ { userMessage, run: (ctx) => callYourModel(ctx, userMessage) },
49
+ { domain: "database" } // enables guardrails for a domain you measure
50
+ )
51
+ ```
52
+
53
+ `learningSkipped` is set when memory did not learn, and why. A silent skip is
54
+ indistinguishable from a working one until the thing you taught it never comes
55
+ back.
56
+
57
+ ## Resources
58
+
59
+ Each maps one-to-one onto an endpoint, so the class is a namespace rather than a
60
+ second copy of the service:
61
+
62
+ ```ts
63
+ memory.memories // create, list, get, promote, remove
64
+ memory.context // build
65
+ memory.recall // search
66
+ memory.turns // learn
67
+ memory.tensions // list, create, resolve
68
+ memory.selfModel // get, record
69
+ memory.stats // get
70
+ memory.health() // no key spent
71
+ ```
72
+
73
+ ## Errors
74
+
75
+ Every failure arrives as a `CognitiveMemoryError` carrying the service's own tag,
76
+ status, the scope that was missing, and any field issues — so callers ask
77
+ semantic questions rather than matching status codes.
78
+
79
+ ```ts
80
+ import { CognitiveMemoryError } from "@astracollab/cogmem"
81
+
82
+ try {
83
+ await memory.memories.create({ items: [{ content: "the build id is ZQ7X4M2K" }] })
84
+ } catch (error) {
85
+ if (!(error instanceof CognitiveMemoryError)) throw error
86
+
87
+ if (error.isScopeError()) {
88
+ // 403, and the service said which scope would have worked
89
+ console.error(`key needs ${error.requiredScope}`)
90
+ } else if (error.isValidationError()) {
91
+ console.error(error.issues) // ["Expected string at [query]"]
92
+ } else if (error.isNotFoundError()) {
93
+ // 404 also covers another organisation's id, by design
94
+ } else if (error.isServerError()) {
95
+ // safe to retry
96
+ }
97
+ }
98
+ ```
99
+
100
+ Transport failures — no response at all — are re-thrown untouched, so a network
101
+ error is never confused with an API error.
102
+
103
+ ## Helpers
104
+
105
+ ```ts
106
+ import { runTurn, recallOrExplain, seedMemories } from "@astracollab/cogmem"
107
+
108
+ // Formatted for injection, and honest when nothing matched.
109
+ const facts = await recallOrExplain(memory, "staging build id")
110
+ // → 'Remembered (1 match):\n- The staging build id is ZQ7X4M2K (deployment) [L1, relevance 0.75]'
111
+ // → 'Nothing in memory matches "…". If you were not told, say so rather than guessing.'
112
+
113
+ // Idempotent: restatements come back under `merged`, not as errors.
114
+ await seedMemories(memory, { facts: ["file naming is kebab-case", "the port is 2291"] })
115
+ ```
116
+
117
+ ## Types
118
+
119
+ Every response and request type is exported, with literal unions rather than
120
+ `string` so an editor offers exactly the valid values:
121
+
122
+ ```ts
123
+ import type { Memory, MemoryTier, InclusionReason, SelfModel } from "@astracollab/cogmem"
124
+
125
+ const tier: MemoryTier = "L1" // "L0" | "L1" | "L2" | "L3"
126
+ const reason: InclusionReason = "trigger" // index | trigger | tension | guardrail
127
+ ```
128
+
129
+ ## Development
130
+
131
+ ```sh
132
+ pnpm build # vite library build: ESM + CJS + rolled-up .d.ts
133
+ pnpm test
134
+ ```
135
+
136
+ The HTTP layer is tested by mocking `fetch` — the thing worth testing is that
137
+ every request is authenticated and that errors are translated, and mocking the
138
+ SDK instead would test the mock. The helpers are tested against a mocked client,
139
+ because there the behaviour under test is the composition.
@@ -0,0 +1,22 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("ai"),e=require("zod"),l=e.z.object({promotions:e.z.array(e.z.object({memoryId:e.z.string(),targetTier:e.z.literal("L1"),signalType:e.z.enum(["anticipatory","tension","proprioceptive","recency"]),urgency:e.z.number().min(0).max(1)})),demotions:e.z.array(e.z.object({memoryId:e.z.string(),targetTier:e.z.literal("L2"),reason:e.z.string()})),pins:e.z.array(e.z.object({memoryId:e.z.string(),targetTier:e.z.literal("L0"),reason:e.z.string()})),detectedTensions:e.z.array(e.z.object({claimA:e.z.string().describe("First conflicting claim or statement"),claimB:e.z.string().describe("Contradicting statement from code or user"),impact:e.z.enum(["low","medium","critical"]),actionableQuestion:e.z.string().describe("Specific clarifying question the agent should resolve")})),trajectoryPrediction:e.z.object({predictedDomains:e.z.array(e.z.string()),predictedFiles:e.z.array(e.z.string()),prefetchMemoryIds:e.z.array(e.z.string()),confidence:e.z.number().min(0).max(1)}).optional(),selfModelUpdate:e.z.object({domain:e.z.string(),success:e.z.boolean().optional(),failurePatternObserved:e.z.string().optional()}).optional()}),d=t=>async({turnText:r,assistantReply:i,l0Prompt:n,l1Summaries:o,candidates:a})=>{try{const s=`You are the Cache Arbiter for an AI coding agent.
2
+ Evaluate the latest turn and candidate memories to decide what should be HOT (L1), COLD (L2), or PINNED (L0).
3
+
4
+ CURRENT TURN:
5
+ User: "${r}"
6
+ Assistant: "${i}"
7
+
8
+ L0 CORE STATE:
9
+ ${n||"(none)"}
10
+
11
+ CURRENT HOT L1 SUMMARIES:
12
+ ${JSON.stringify(o,null,2)}
13
+
14
+ WARM L2 CANDIDATE MEMORIES:
15
+ ${JSON.stringify(a,null,2)}
16
+
17
+ Analyze:
18
+ 1. What will the agent likely need in the NEXT 1-2 turns? (Anticipatory -> promote candidate to L1)
19
+ 2. Are any active L1 items no longer relevant? (Demote L1 to L2)
20
+ 3. Did the conversation reveal a contradiction between user claims and known facts? (Flag as detectedTension)
21
+ 4. Did the agent succeed or struggle in a specific domain? (Update self-model)`;return(await c.generateObject({model:t.model,schema:l,prompt:s})).object}catch{return{promotions:[],demotions:[],pins:[],detectedTensions:[]}}};exports.createModelArbiter=d;
22
+ //# sourceMappingURL=arbiter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arbiter.cjs","sources":["../src/cognitive/arbiter.ts"],"sourcesContent":["import { generateObject, type LanguageModel } from \"ai\";\nimport { z } from \"zod\";\nimport type { ArbiterEvaluationResult, ArbiterFn } from \"./types.js\";\n\nconst ArbiterSchema = z.object({\n promotions: z.array(\n z.object({\n memoryId: z.string(),\n targetTier: z.literal(\"L1\"),\n signalType: z.enum([\"anticipatory\", \"tension\", \"proprioceptive\", \"recency\"]),\n urgency: z.number().min(0).max(1),\n })\n ),\n demotions: z.array(\n z.object({\n memoryId: z.string(),\n targetTier: z.literal(\"L2\"),\n reason: z.string(),\n })\n ),\n pins: z.array(\n z.object({\n memoryId: z.string(),\n targetTier: z.literal(\"L0\"),\n reason: z.string(),\n })\n ),\n detectedTensions: z.array(\n z.object({\n claimA: z.string().describe(\"First conflicting claim or statement\"),\n claimB: z.string().describe(\"Contradicting statement from code or user\"),\n impact: z.enum([\"low\", \"medium\", \"critical\"]),\n actionableQuestion: z.string().describe(\"Specific clarifying question the agent should resolve\"),\n })\n ),\n trajectoryPrediction: z\n .object({\n predictedDomains: z.array(z.string()),\n predictedFiles: z.array(z.string()),\n prefetchMemoryIds: z.array(z.string()),\n confidence: z.number().min(0).max(1),\n })\n .optional(),\n selfModelUpdate: z\n .object({\n domain: z.string(),\n success: z.boolean().optional(),\n failurePatternObserved: z.string().optional(),\n })\n .optional(),\n});\n\nexport interface CreateModelArbiterOptions {\n /** Fast decision model (e.g., Gemini 1.5/2.5 Flash, Claude 3.5 Haiku, or GPT-4o-mini) */\n model: LanguageModel;\n /** Custom system prompt override if desired */\n systemPrompt?: string;\n}\n\n/**\n * Creates an Arbiter function powered by an AI SDK model with structured output.\n */\nexport const createModelArbiter = (options: CreateModelArbiterOptions): ArbiterFn => {\n return async ({ turnText, assistantReply, l0Prompt, l1Summaries, candidates }): Promise<ArbiterEvaluationResult> => {\n try {\n const prompt = `You are the Cache Arbiter for an AI coding agent.\nEvaluate the latest turn and candidate memories to decide what should be HOT (L1), COLD (L2), or PINNED (L0).\n\nCURRENT TURN:\nUser: \"${turnText}\"\nAssistant: \"${assistantReply}\"\n\nL0 CORE STATE:\n${l0Prompt || \"(none)\"}\n\nCURRENT HOT L1 SUMMARIES:\n${JSON.stringify(l1Summaries, null, 2)}\n\nWARM L2 CANDIDATE MEMORIES:\n${JSON.stringify(candidates, null, 2)}\n\nAnalyze:\n1. What will the agent likely need in the NEXT 1-2 turns? (Anticipatory -> promote candidate to L1)\n2. Are any active L1 items no longer relevant? (Demote L1 to L2)\n3. Did the conversation reveal a contradiction between user claims and known facts? (Flag as detectedTension)\n4. Did the agent succeed or struggle in a specific domain? (Update self-model)`;\n\n const result = await generateObject({\n model: options.model,\n schema: ArbiterSchema,\n prompt,\n });\n\n return result.object;\n } catch {\n // Return safe empty fallback on model failure so the cache remains stable\n return {\n promotions: [],\n demotions: [],\n pins: [],\n detectedTensions: [],\n };\n }\n };\n};\n"],"names":["ArbiterSchema","z","createModelArbiter","options","turnText","assistantReply","l0Prompt","l1Summaries","candidates","prompt","generateObject"],"mappings":"uHAIMA,EAAgBC,EAAAA,EAAE,OAAO,CAC7B,WAAYA,EAAAA,EAAE,MACZA,EAAAA,EAAE,OAAO,CACP,SAAUA,EAAAA,EAAE,OAAA,EACZ,WAAYA,EAAAA,EAAE,QAAQ,IAAI,EAC1B,WAAYA,EAAAA,EAAE,KAAK,CAAC,eAAgB,UAAW,iBAAkB,SAAS,CAAC,EAC3E,QAASA,EAAAA,EAAE,OAAA,EAAS,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA,CACjC,CAAA,EAEH,UAAWA,EAAAA,EAAE,MACXA,EAAAA,EAAE,OAAO,CACP,SAAUA,EAAAA,EAAE,OAAA,EACZ,WAAYA,EAAAA,EAAE,QAAQ,IAAI,EAC1B,OAAQA,EAAAA,EAAE,OAAA,CAAO,CAClB,CAAA,EAEH,KAAMA,EAAAA,EAAE,MACNA,EAAAA,EAAE,OAAO,CACP,SAAUA,EAAAA,EAAE,OAAA,EACZ,WAAYA,EAAAA,EAAE,QAAQ,IAAI,EAC1B,OAAQA,EAAAA,EAAE,OAAA,CAAO,CAClB,CAAA,EAEH,iBAAkBA,EAAAA,EAAE,MAClBA,EAAAA,EAAE,OAAO,CACP,OAAQA,EAAAA,EAAE,SAAS,SAAS,sCAAsC,EAClE,OAAQA,EAAAA,EAAE,SAAS,SAAS,2CAA2C,EACvE,OAAQA,EAAAA,EAAE,KAAK,CAAC,MAAO,SAAU,UAAU,CAAC,EAC5C,mBAAoBA,EAAAA,EAAE,OAAA,EAAS,SAAS,uDAAuD,CAAA,CAChG,CAAA,EAEH,qBAAsBA,EAAAA,EACnB,OAAO,CACN,iBAAkBA,EAAAA,EAAE,MAAMA,EAAAA,EAAE,QAAQ,EACpC,eAAgBA,EAAAA,EAAE,MAAMA,EAAAA,EAAE,QAAQ,EAClC,kBAAmBA,EAAAA,EAAE,MAAMA,EAAAA,EAAE,QAAQ,EACrC,WAAYA,EAAAA,EAAE,OAAA,EAAS,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA,CACpC,EACA,SAAA,EACH,gBAAiBA,EAAAA,EACd,OAAO,CACN,OAAQA,EAAAA,EAAE,OAAA,EACV,QAASA,EAAAA,EAAE,QAAA,EAAU,SAAA,EACrB,uBAAwBA,EAAAA,EAAE,OAAA,EAAS,SAAA,CAAS,CAC7C,EACA,SAAA,CACL,CAAC,EAYYC,EAAsBC,GAC1B,MAAO,CAAE,SAAAC,EAAU,eAAAC,EAAgB,SAAAC,EAAU,YAAAC,EAAa,WAAAC,KAAmD,CAClH,GAAI,CACF,MAAMC,EAAS;AAAA;AAAA;AAAA;AAAA,SAIZL,CAAQ;AAAA,cACHC,CAAc;AAAA;AAAA;AAAA,EAG1BC,GAAY,QAAQ;AAAA;AAAA;AAAA,EAGpB,KAAK,UAAUC,EAAa,KAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAGpC,KAAK,UAAUC,EAAY,KAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gFAc/B,OANe,MAAME,iBAAe,CAClC,MAAOP,EAAQ,MACf,OAAQH,EACR,OAAAS,CAAA,CACD,GAEa,MAChB,MAAQ,CAEN,MAAO,CACL,WAAY,CAAA,EACZ,UAAW,CAAA,EACX,KAAM,CAAA,EACN,iBAAkB,CAAA,CAAC,CAEvB,CACF"}
@@ -0,0 +1,72 @@
1
+ import { LanguageModel } from 'ai';
2
+
3
+ export declare interface ArbiterEvaluationResult {
4
+ promotions: Array<{
5
+ memoryId: string;
6
+ targetTier: "L1";
7
+ signalType: "anticipatory" | "tension" | "proprioceptive" | "recency";
8
+ urgency: number;
9
+ }>;
10
+ demotions: Array<{
11
+ memoryId: string;
12
+ targetTier: "L2";
13
+ reason: string;
14
+ }>;
15
+ pins: Array<{
16
+ memoryId: string;
17
+ targetTier: "L0";
18
+ reason: string;
19
+ }>;
20
+ detectedTensions: Array<{
21
+ claimA: string;
22
+ claimB: string;
23
+ impact: TensionImpact;
24
+ actionableQuestion: string;
25
+ }>;
26
+ trajectoryPrediction?: TrajectoryPrediction;
27
+ selfModelUpdate?: {
28
+ domain: string;
29
+ success?: boolean;
30
+ failurePatternObserved?: string;
31
+ };
32
+ }
33
+
34
+ export declare type ArbiterFn = (params: {
35
+ turnText: string;
36
+ assistantReply: string;
37
+ l0Prompt: string;
38
+ l1Summaries: Array<{
39
+ id: string;
40
+ bookmark: string;
41
+ domains: string[];
42
+ }>;
43
+ candidates: Array<{
44
+ id: string;
45
+ bookmark: string;
46
+ domains: string[];
47
+ hasTension?: boolean;
48
+ }>;
49
+ }) => Promise<ArbiterEvaluationResult>;
50
+
51
+ /**
52
+ * Creates an Arbiter function powered by an AI SDK model with structured output.
53
+ */
54
+ export declare const createModelArbiter: (options: CreateModelArbiterOptions) => ArbiterFn;
55
+
56
+ export declare interface CreateModelArbiterOptions {
57
+ /** Fast decision model (e.g., Gemini 1.5/2.5 Flash, Claude 3.5 Haiku, or GPT-4o-mini) */
58
+ model: LanguageModel;
59
+ /** Custom system prompt override if desired */
60
+ systemPrompt?: string;
61
+ }
62
+
63
+ declare type TensionImpact = "low" | "medium" | "critical";
64
+
65
+ declare interface TrajectoryPrediction {
66
+ predictedDomains: string[];
67
+ predictedFiles: string[];
68
+ prefetchMemoryIds: string[];
69
+ confidence: number;
70
+ }
71
+
72
+ export { }
@@ -0,0 +1,85 @@
1
+ import { generateObject as c } from "ai";
2
+ import { z as e } from "zod";
3
+ const l = e.object({
4
+ promotions: e.array(
5
+ e.object({
6
+ memoryId: e.string(),
7
+ targetTier: e.literal("L1"),
8
+ signalType: e.enum(["anticipatory", "tension", "proprioceptive", "recency"]),
9
+ urgency: e.number().min(0).max(1)
10
+ })
11
+ ),
12
+ demotions: e.array(
13
+ e.object({
14
+ memoryId: e.string(),
15
+ targetTier: e.literal("L2"),
16
+ reason: e.string()
17
+ })
18
+ ),
19
+ pins: e.array(
20
+ e.object({
21
+ memoryId: e.string(),
22
+ targetTier: e.literal("L0"),
23
+ reason: e.string()
24
+ })
25
+ ),
26
+ detectedTensions: e.array(
27
+ e.object({
28
+ claimA: e.string().describe("First conflicting claim or statement"),
29
+ claimB: e.string().describe("Contradicting statement from code or user"),
30
+ impact: e.enum(["low", "medium", "critical"]),
31
+ actionableQuestion: e.string().describe("Specific clarifying question the agent should resolve")
32
+ })
33
+ ),
34
+ trajectoryPrediction: e.object({
35
+ predictedDomains: e.array(e.string()),
36
+ predictedFiles: e.array(e.string()),
37
+ prefetchMemoryIds: e.array(e.string()),
38
+ confidence: e.number().min(0).max(1)
39
+ }).optional(),
40
+ selfModelUpdate: e.object({
41
+ domain: e.string(),
42
+ success: e.boolean().optional(),
43
+ failurePatternObserved: e.string().optional()
44
+ }).optional()
45
+ }), p = (t) => async ({ turnText: r, assistantReply: n, l0Prompt: i, l1Summaries: o, candidates: a }) => {
46
+ try {
47
+ const s = `You are the Cache Arbiter for an AI coding agent.
48
+ Evaluate the latest turn and candidate memories to decide what should be HOT (L1), COLD (L2), or PINNED (L0).
49
+
50
+ CURRENT TURN:
51
+ User: "${r}"
52
+ Assistant: "${n}"
53
+
54
+ L0 CORE STATE:
55
+ ${i || "(none)"}
56
+
57
+ CURRENT HOT L1 SUMMARIES:
58
+ ${JSON.stringify(o, null, 2)}
59
+
60
+ WARM L2 CANDIDATE MEMORIES:
61
+ ${JSON.stringify(a, null, 2)}
62
+
63
+ Analyze:
64
+ 1. What will the agent likely need in the NEXT 1-2 turns? (Anticipatory -> promote candidate to L1)
65
+ 2. Are any active L1 items no longer relevant? (Demote L1 to L2)
66
+ 3. Did the conversation reveal a contradiction between user claims and known facts? (Flag as detectedTension)
67
+ 4. Did the agent succeed or struggle in a specific domain? (Update self-model)`;
68
+ return (await c({
69
+ model: t.model,
70
+ schema: l,
71
+ prompt: s
72
+ })).object;
73
+ } catch {
74
+ return {
75
+ promotions: [],
76
+ demotions: [],
77
+ pins: [],
78
+ detectedTensions: []
79
+ };
80
+ }
81
+ };
82
+ export {
83
+ p as createModelArbiter
84
+ };
85
+ //# sourceMappingURL=arbiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arbiter.js","sources":["../src/cognitive/arbiter.ts"],"sourcesContent":["import { generateObject, type LanguageModel } from \"ai\";\nimport { z } from \"zod\";\nimport type { ArbiterEvaluationResult, ArbiterFn } from \"./types.js\";\n\nconst ArbiterSchema = z.object({\n promotions: z.array(\n z.object({\n memoryId: z.string(),\n targetTier: z.literal(\"L1\"),\n signalType: z.enum([\"anticipatory\", \"tension\", \"proprioceptive\", \"recency\"]),\n urgency: z.number().min(0).max(1),\n })\n ),\n demotions: z.array(\n z.object({\n memoryId: z.string(),\n targetTier: z.literal(\"L2\"),\n reason: z.string(),\n })\n ),\n pins: z.array(\n z.object({\n memoryId: z.string(),\n targetTier: z.literal(\"L0\"),\n reason: z.string(),\n })\n ),\n detectedTensions: z.array(\n z.object({\n claimA: z.string().describe(\"First conflicting claim or statement\"),\n claimB: z.string().describe(\"Contradicting statement from code or user\"),\n impact: z.enum([\"low\", \"medium\", \"critical\"]),\n actionableQuestion: z.string().describe(\"Specific clarifying question the agent should resolve\"),\n })\n ),\n trajectoryPrediction: z\n .object({\n predictedDomains: z.array(z.string()),\n predictedFiles: z.array(z.string()),\n prefetchMemoryIds: z.array(z.string()),\n confidence: z.number().min(0).max(1),\n })\n .optional(),\n selfModelUpdate: z\n .object({\n domain: z.string(),\n success: z.boolean().optional(),\n failurePatternObserved: z.string().optional(),\n })\n .optional(),\n});\n\nexport interface CreateModelArbiterOptions {\n /** Fast decision model (e.g., Gemini 1.5/2.5 Flash, Claude 3.5 Haiku, or GPT-4o-mini) */\n model: LanguageModel;\n /** Custom system prompt override if desired */\n systemPrompt?: string;\n}\n\n/**\n * Creates an Arbiter function powered by an AI SDK model with structured output.\n */\nexport const createModelArbiter = (options: CreateModelArbiterOptions): ArbiterFn => {\n return async ({ turnText, assistantReply, l0Prompt, l1Summaries, candidates }): Promise<ArbiterEvaluationResult> => {\n try {\n const prompt = `You are the Cache Arbiter for an AI coding agent.\nEvaluate the latest turn and candidate memories to decide what should be HOT (L1), COLD (L2), or PINNED (L0).\n\nCURRENT TURN:\nUser: \"${turnText}\"\nAssistant: \"${assistantReply}\"\n\nL0 CORE STATE:\n${l0Prompt || \"(none)\"}\n\nCURRENT HOT L1 SUMMARIES:\n${JSON.stringify(l1Summaries, null, 2)}\n\nWARM L2 CANDIDATE MEMORIES:\n${JSON.stringify(candidates, null, 2)}\n\nAnalyze:\n1. What will the agent likely need in the NEXT 1-2 turns? (Anticipatory -> promote candidate to L1)\n2. Are any active L1 items no longer relevant? (Demote L1 to L2)\n3. Did the conversation reveal a contradiction between user claims and known facts? (Flag as detectedTension)\n4. Did the agent succeed or struggle in a specific domain? (Update self-model)`;\n\n const result = await generateObject({\n model: options.model,\n schema: ArbiterSchema,\n prompt,\n });\n\n return result.object;\n } catch {\n // Return safe empty fallback on model failure so the cache remains stable\n return {\n promotions: [],\n demotions: [],\n pins: [],\n detectedTensions: [],\n };\n }\n };\n};\n"],"names":["ArbiterSchema","z","createModelArbiter","options","turnText","assistantReply","l0Prompt","l1Summaries","candidates","prompt","generateObject"],"mappings":";;AAIA,MAAMA,IAAgBC,EAAE,OAAO;AAAA,EAC7B,YAAYA,EAAE;AAAA,IACZA,EAAE,OAAO;AAAA,MACP,UAAUA,EAAE,OAAA;AAAA,MACZ,YAAYA,EAAE,QAAQ,IAAI;AAAA,MAC1B,YAAYA,EAAE,KAAK,CAAC,gBAAgB,WAAW,kBAAkB,SAAS,CAAC;AAAA,MAC3E,SAASA,EAAE,OAAA,EAAS,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,IAAA,CACjC;AAAA,EAAA;AAAA,EAEH,WAAWA,EAAE;AAAA,IACXA,EAAE,OAAO;AAAA,MACP,UAAUA,EAAE,OAAA;AAAA,MACZ,YAAYA,EAAE,QAAQ,IAAI;AAAA,MAC1B,QAAQA,EAAE,OAAA;AAAA,IAAO,CAClB;AAAA,EAAA;AAAA,EAEH,MAAMA,EAAE;AAAA,IACNA,EAAE,OAAO;AAAA,MACP,UAAUA,EAAE,OAAA;AAAA,MACZ,YAAYA,EAAE,QAAQ,IAAI;AAAA,MAC1B,QAAQA,EAAE,OAAA;AAAA,IAAO,CAClB;AAAA,EAAA;AAAA,EAEH,kBAAkBA,EAAE;AAAA,IAClBA,EAAE,OAAO;AAAA,MACP,QAAQA,EAAE,SAAS,SAAS,sCAAsC;AAAA,MAClE,QAAQA,EAAE,SAAS,SAAS,2CAA2C;AAAA,MACvE,QAAQA,EAAE,KAAK,CAAC,OAAO,UAAU,UAAU,CAAC;AAAA,MAC5C,oBAAoBA,EAAE,OAAA,EAAS,SAAS,uDAAuD;AAAA,IAAA,CAChG;AAAA,EAAA;AAAA,EAEH,sBAAsBA,EACnB,OAAO;AAAA,IACN,kBAAkBA,EAAE,MAAMA,EAAE,QAAQ;AAAA,IACpC,gBAAgBA,EAAE,MAAMA,EAAE,QAAQ;AAAA,IAClC,mBAAmBA,EAAE,MAAMA,EAAE,QAAQ;AAAA,IACrC,YAAYA,EAAE,OAAA,EAAS,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EAAA,CACpC,EACA,SAAA;AAAA,EACH,iBAAiBA,EACd,OAAO;AAAA,IACN,QAAQA,EAAE,OAAA;AAAA,IACV,SAASA,EAAE,QAAA,EAAU,SAAA;AAAA,IACrB,wBAAwBA,EAAE,OAAA,EAAS,SAAA;AAAA,EAAS,CAC7C,EACA,SAAA;AACL,CAAC,GAYYC,IAAqB,CAACC,MAC1B,OAAO,EAAE,UAAAC,GAAU,gBAAAC,GAAgB,UAAAC,GAAU,aAAAC,GAAa,YAAAC,QAAmD;AAClH,MAAI;AACF,UAAMC,IAAS;AAAA;AAAA;AAAA;AAAA,SAIZL,CAAQ;AAAA,cACHC,CAAc;AAAA;AAAA;AAAA,EAG1BC,KAAY,QAAQ;AAAA;AAAA;AAAA,EAGpB,KAAK,UAAUC,GAAa,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAGpC,KAAK,UAAUC,GAAY,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc/B,YANe,MAAME,EAAe;AAAA,MAClC,OAAOP,EAAQ;AAAA,MACf,QAAQH;AAAA,MACR,QAAAS;AAAA,IAAA,CACD,GAEa;AAAA,EAChB,QAAQ;AAEN,WAAO;AAAA,MACL,YAAY,CAAA;AAAA,MACZ,WAAW,CAAA;AAAA,MACX,MAAM,CAAA;AAAA,MACN,kBAAkB,CAAA;AAAA,IAAC;AAAA,EAEvB;AACF;"}
@@ -0,0 +1,15 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("ofetch");class b extends Error{static name="CognitiveMemoryError";code;status;requiredScope;issues;body;constructor(e,t){super(e),this.name="CognitiveMemoryError",this.status=t.status,this.code=t.code,this.body=t.body,this.requiredScope=t.requiredScope,this.issues=t.issues,Error.captureStackTrace&&Error.captureStackTrace(this,b)}isAuthError(){return this.status===401}isScopeError(){return this.status===403}isValidationError(){return this.status===400}isNotFoundError(){return this.status===404}isRateLimitError(){return this.status===429}isServerError(){return this.status>=500}}function E(i){const{apiKey:e,baseUrl:t=G(),timeout:s=3e4,retry:o=2,debug:n=!1,headers:r={}}=i;if(typeof e!="string"||e.trim()==="")throw new Error("cognitive-memory: apiKey is required. Issue one in the dashboard — the secret is shown only once.");const a=$.ofetch.create({baseURL:`${t.replace(/\/$/,"")}/api/v1`,timeout:s,retry:o,headers:{accept:"application/json",...r},onRequest({options:h,request:u}){h.headers.set("authorization",`Bearer ${e}`),h.headers.set("content-type","application/json"),n&&console.log("[cognitive-memory]",h.method??"GET",`${h.baseURL??""}${u??""}`)},onResponse({response:h,options:u,request:c}){n&&console.log("[cognitive-memory]",h.status,u.method??"GET",c??"")}});return async(h,u)=>{try{return await a(h,u)}catch(c){if(!(c instanceof $.FetchError)||!c.response)throw c;const d=c.response,m=d._data??void 0;throw new b(m?.message??`cognitive-memory: request failed with ${d.status}`,{status:d.status,code:m?.error??"UnknownError",...m===void 0?{}:{body:m},...m?.requiredScope===void 0?{}:{requiredScope:m.requiredScope},...m?.issues===void 0?{}:{issues:m.issues}})}}}function G(){return typeof window<"u"?window.location.origin:"http://localhost:3000"}class x{constructor(e){this.client=e}build(e={}){return this.client("/context",{method:"POST",body:e})}}class L{constructor(e){this.client=e}async list(e={}){return(await this.client("/memories",{method:"GET",query:e})).memories}async get(e){return(await this.client(`/memories/${encodeURIComponent(e)}`,{method:"GET"})).memory}create(e){return this.client("/memories",{method:"POST",body:e})}async promote(e,t){return(await this.client(`/memories/${encodeURIComponent(e)}`,{method:"PATCH",body:{tier:t}})).memory}remove(e){return this.client(`/memories/${encodeURIComponent(e)}`,{method:"DELETE"})}}class D{constructor(e){this.client=e}search(e){return this.client("/recall",{method:"POST",body:e})}}class R{constructor(e){this.client=e}get(){return this.client("/self-model",{method:"GET"})}record(e){return this.client("/self-model/outcome",{method:"POST",body:e})}}class O{constructor(e){this.client=e}get(){return this.client("/stats",{method:"GET"})}}const I=async i=>{const e=i.replace(/\/$/,""),t=await fetch(`${e}/api/v1/health`,{headers:{accept:"application/json"}});if(!t.ok)throw new Error(`cognitive-memory: health check failed with ${t.status}`);return await t.json()};class H{constructor(e){this.client=e}async list(e){return(await this.client("/tensions",{method:"GET",query:e===void 0?{}:{status:e}})).tensions}async create(e){return(await this.client("/tensions",{method:"POST",body:e})).tension}async resolve(e,t){return(await this.client(`/tensions/${encodeURIComponent(e)}`,{method:"POST",body:t})).tension}}class j{constructor(e){this.client=e}learn(e){return this.client("/turns",{method:"POST",body:e})}}class P{client;baseUrl;memories;context;recall;turns;tensions;selfModel;stats;constructor(e){this.baseUrl=(e.baseUrl??"http://localhost:3000").replace(/\/$/,""),this.client=E(e),this.memories=new L(this.client),this.context=new x(this.client),this.recall=new D(this.client),this.turns=new j(this.client),this.tensions=new H(this.client),this.selfModel=new R(this.client),this.stats=new O(this.client)}health(){return I(this.baseUrl)}}function Z(i){return new P(i)}async function Q(i,e,t={}){const s=await i.context.build({userMessage:e.userMessage,...t.sessionId===void 0?{}:{sessionId:t.sessionId}}),o=await e.run(s.text);if(t.learn===!1)return{context:s,learning:null,learningSkipped:"learning disabled for this turn"};let n=null;try{n=await i.turns.learn({userMessage:e.userMessage,assistantResponse:o,...t.sessionId===void 0?{}:{sessionId:t.sessionId}}),t.onLearn?.(n)}catch(r){return console.warn("[cognitive-memory] could not learn from this turn",r),{context:s,learning:null,learningSkipped:String(r)}}if(t.domain!==void 0)try{await i.selfModel.record({domain:t.domain,success:t.failurePattern===void 0,...t.failurePattern===void 0?{}:{failurePattern:t.failurePattern},...t.strategy===void 0?{}:{strategy:t.strategy}})}catch(r){console.warn("[cognitive-memory] could not record the domain outcome",r)}return{context:s,learning:n}}async function K(i,e,t={}){const s=await i.recall.search({query:e,...t.limit===void 0?{}:{limit:t.limit}});if(s.empty)return t.emptyMessage??`Nothing in memory matches "${e}". If you were not told, say so rather than guessing.`;const o=s.results.map(n=>{const r=n.memory.domains.length>0?` (${n.memory.domains.join(", ")})`:"";return`- ${n.memory.content}${r} [${n.memory.tier}, relevance ${n.score.toFixed(2)}]`});return`Remembered (${s.results.length} match${s.results.length===1?"":"es"}):
2
+ ${o.join(`
3
+ `)}`}async function V(i,e){const t=await i.memories.create({items:e.facts.map(s=>({content:s})),...e.sessionId===void 0?{}:{sessionId:e.sessionId}});return{stored:t.stored,merged:t.mergedInto,rejected:t.rejected}}const J=[/actually,?\s+(?:we|i)\s+(?:switched|changed|moved|migrated|replaced|use|want|have)/i,/that(?:'s|\s+is)\s+(?:wrong|incorrect|outdated|false|not\s+right|no\s+longer)/i,/no,?\s+(?:it(?:'s|\s+is)|we\s+use|we\s+switched|it\s+should\s+be|don(?:'t|\s+not)\s+use)/i,/stop\s+using\s+/i,/instead\s+of\s+/i,/disregard\s+(?:prior|previous|what\s+i\s+said)/i],X={auth:[/auth/i,/login/i,/session/i,/jwt/i,/oauth/i,/token/i,/password/i,/permission/i],database:[/postgres/i,/sqlite/i,/sql/i,/schema/i,/migration/i,/prisma/i,/drizzle/i,/mongo/i,/redis/i],frontend:[/css/i,/tailwind/i,/component/i,/jsx/i,/tsx/i,/layout/i,/ui/i,/render/i,/html/i],build:[/vite/i,/webpack/i,/turbo/i,/tsconfig/i,/pnpm/i,/package\.json/i,/bundle/i],api:[/rest/i,/graphql/i,/endpoint/i,/route/i,/fetch/i,/request/i,/response/i],git:[/branch/i,/commit/i,/merge/i,/rebase/i,/worktree/i,/conflict/i]},N=i=>{if(!i||i.trim().length===0)return{action:"proceed"};for(const e of J)if(e.test(i))return{action:"inject_caution",cautionNote:"User appears to be explicitly correcting a prior premise or configuration. Verify current facts before proceeding with assumptions.",detectedDomains:S(i)};return{action:"proceed",detectedDomains:S(i)}},S=i=>{const e=[];for(const[t,s]of Object.entries(X))s.some(o=>o.test(i))&&e.push(t);return e},Y=new Set(["the","and","for","this","that","with","from","you","are","was","has","have","what","which","when","were","will","your","our","its","not","but","all","any","can","did","does","how","into","out","use","used","using","one","two","get","new","now","then","than","them","they","his","her","she","him","been","being","there","here","also","just","like","make","made","need","want","about","after","tell","know","give","show","please","would","could","should","shall"]),ee=new Set(["this","that","these","those","there","here","with","from","into","must","should","always","never","under","over","about","after","before","when","where","which","what","your","their","them","they","then","than","also","just","only","each","every","some","such","very","more","most","same","file","files","name","names","project","repository","repo","note"]),g=i=>new Set(i.toLowerCase().split(/[^a-z0-9]+/).filter(e=>e.length>=3&&!Y.has(e))),y=(i,e)=>{if(i.size===0||e.size===0)return 0;let t=0;for(const s of i)e.has(s)&&(t+=1);return t/Math.min(i.size,e.size)},z=.3,U=.12,B=8,_=.8,p=i=>new Set(i.toLowerCase().replace(/['']/g,"").split(/[^a-z0-9]+/).filter(Boolean).filter(e=>/\d/.test(e)||e.length>=4).filter(e=>!ee.has(e))),v=(i,e)=>{const t=o=>new Set([...o].map(n=>n.length>=4&&n.endsWith("s")?n.slice(0,-1):n)),s=t(p(e));for(const o of t(p(i)))if(!s.has(o))return!0;return!1},te=/\b[a-z0-9][a-z0-9-]{1,}(?:\.[a-z0-9-]+)*\.[a-z]{2,}\b/gi,se=new Set(["eg","ie","etc","vs","approx","inc","ltd","corp","dept","est","fig","no","al"]),oe=i=>{const e=new Set;for(const t of i.match(/\bhttps?:\/\/[^\s<>()[\]"'`]+/g)??[])e.add(t);for(const t of i.match(te)??[])se.has(t.toLowerCase())||e.add(t);for(const t of i.match(/\b(?:\.{0,2}\/)?[\w-]+(?:\/[\w.-]+)+\/?/g)??[])t.length>3&&e.add(t);for(const t of i.match(/\b[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+\b/g)??[])e.add(t);for(const t of i.match(/\b[A-Z]{2,}[0-9][A-Z0-9-]*\b/g)??[])e.add(t);for(const t of i.match(/\b[a-z]+(?:[A-Z][a-z0-9]+){1,}\b/g)??[])e.add(t);for(const t of i.match(/\b[a-z]+(?:-[a-z0-9]+){2,}\b/g)??[])e.add(t);for(const t of i.match(/\b[0-9a-f]{6,}\b/gi)??[])e.add(t);return[...e]},ne=[/\b(?:do not|don'?t|never|no need to)\s+(?:verify|check|confirm|look\s?up|search|investigate|browse|resolve)\b/i,/\bjust\s+(?:remember|note|acknowledge|retain|treat)\b/i,/\b(?:held|noted|stored|remembered)\s+(?:in|for)\s+(?:this|the)\s+conversation\b/i,/\bnot\s+verified\b/i,/\bwithout\s+verifying\b/i,/\bfor\s+this\s+(?:conversation|session|turn|reply|response)\s+only\b/i,/^(?:ok|okay|noted|got it|sure|thanks)\b[.!]?$/i],C=i=>ne.some(e=>e.test(i)),F=(i,e)=>{const t=p(i),s=p(e);if(t.size===0||s.size===0)return 0;let o=0;for(const n of t)s.has(n)&&(o+=1);return o/Math.min(t.size,s.size)},ie=i=>i.trim().toLowerCase(),W=i=>Math.ceil(i.length/4),k=i=>{if(i.gist&&i.gist.trim().length>0)return i.gist.trim();const t=(i.content.split(/(?<=[.!?])\s/)[0]??i.content).trim();return t.length>90?`${t.slice(0,90)}…`:t},re=5;class ae{activeTensions=new Map;selfModel;activeTaskTrace="";l1HotCache=new Map;l2WarmStore=new Map;l3ColdArchive=new Map;maxL0Tokens;maxL1Tokens;maxTotalTokens;arbiter=null;autoExtractMemories;reconcile;extract;onPersist;stats={totalTurnsProcessed:0,predictionsHit:0,predictionsTotal:0,tensionsDetected:0};constructor(e={}){this.maxL0Tokens=e.maxL0Tokens??2e3,this.maxL1Tokens=e.maxL1Tokens??8e3,this.maxTotalTokens=e.maxTotalTokens??2e3,this.arbiter=e.arbiter??null,this.autoExtractMemories=e.autoExtractMemories??!0,this.extract=e.extract,this.reconcile=e.reconcile,this.onPersist=e.onPersist,this.selfModel={domains:e.initialSelfModel?.domains??{},calibrationFactor:e.initialSelfModel?.calibrationFactor??1,activeDomains:e.initialSelfModel?.activeDomains??[]}}planInjection(e={}){const t=new Set(e.forceFull??[]),s=[],o=[];let n=0,r=!1;const a=(c,d,m)=>{const f=k(c),A=m?c.content:void 0,M=c.metadata.domains.slice(0,3),q=M.length>0?` (${M.join(", ")})`:"",T=W(`${f}${q}${A??""}`);if(n+T>this.maxTotalTokens){r=!0;return}n+=T,o.push({id:c.id,tier:c.tier,reason:d,gist:f,body:A,tokens:T})};if(e.userMessage){const c=N(e.userMessage);c.action==="inject_caution"&&c.cautionNote&&s.push(`### ⚠️ Correction Detected In This Message
4
+ ${c.cautionNote}`)}const l=this.selfModel.activeDomains.map(c=>({d:c,capability:this.selfModel.domains[c]})).filter(c=>c.capability&&c.capability.reliabilityScore<.75);if(l.length>0){const c=l.map(({d,capability:m})=>{const f=m;return a({id:`guardrail-${d}`,content:`${d}: reliability ${Math.round(f.reliabilityScore*100)}% over ${f.sampleCount} tasks.${f.knownFailurePatterns.length>0?` Known pitfalls: ${f.knownFailurePatterns.join("; ")}`:""}${f.recommendedStrategies.length>0?` Approach: ${f.recommendedStrategies.join("; ")}`:""}`,tier:"L0",metadata:{domains:[d],createdAt:Date.now(),lastAccessedAt:Date.now(),accessCount:0}},"guardrail",!0),`- ${d} (${Math.round(f.reliabilityScore*100)}% reliable): ${f.knownFailurePatterns.join("; ")||"be careful"}`});s.push(`### Weak Domains — Under 75% Reliability
5
+ ${c.join(`
6
+ `)}`)}const h=[];for(const c of this.l1HotCache.values()){const d=c.metadata.domains.slice(0,3),m=d.length>0?` (${d.join(", ")})`:"";t.has(c.id)?(a(c,"trigger",!0),h.push(`- ${c.content}${m}`)):(a(c,"index",!1),h.push(`- ${k(c)}${m}`))}h.length>0&&s.push(["### Memory index — established earlier in this project","One line per remembered item. Use `recall` to pull a full item, then treat it as true.",...h].join(`
7
+ `));const u=[...this.activeTensions.values()].filter(c=>c.status==="active");if(u.length>0){const c=u.map(d=>(a({id:d.id,content:`${d.claimA.statement} vs ${d.claimB.statement} — ${d.actionableQuestion}`,bookmark:d.claimA.statement,tier:"L0",metadata:{domains:[],createdAt:d.claimA.timestamp,lastAccessedAt:Date.now(),accessCount:0}},"tension",!0),`- [${d.impact.toUpperCase()}] "${d.claimA.statement}" conflicts with "${d.claimB.statement}". Ask: ${d.actionableQuestion}`));s.push(`### Unresolved Contradictions
8
+ ${c.join(`
9
+ `)}`)}return{text:s.length>0?`
10
+ ## Cognitive Memory State
11
+ ${s.join(`
12
+
13
+ `)}
14
+ `:"",entries:o,totalTokens:n,truncated:r}}getPromptContext(e){return this.planInjection({userMessage:e}).text}search(e,t=8){const s=g(e);if(s.size===0)return[];const n=[...this.l1HotCache.values(),...this.l2WarmStore.values(),...this.l3ColdArchive.values()].map(l=>({item:l,score:y(s,g(`${l.content} ${l.metadata.domains.join(" ")}`))})).filter(l=>l.score>0).sort((l,h)=>h.score-l.score||l.item.content.length-h.item.content.length),r=[],a=[];for(const l of n)if(!r.some(h=>F(h,l.item.content)>=_)&&(r.push(l.item.content),a.push(l),a.length>=Math.max(1,t)))break;return a}async postTurnAsync(e){this.stats.totalTurnsProcessed+=1,e.detectedDomains&&e.detectedDomains.length>0&&(this.selfModel.activeDomains=Array.from(new Set([...this.selfModel.activeDomains,...e.detectedDomains])));const t=Array.from(this.l2WarmStore.values()).slice(0,20).map(n=>({id:n.id,bookmark:n.bookmark,domains:n.metadata.domains,hasTension:!1})),s=Array.from(this.l1HotCache.values()).map(n=>({id:n.id,bookmark:n.bookmark,domains:n.metadata.domains})),o=this.arbiter?await this.arbiter({turnText:e.userMessage,assistantReply:e.assistantResponse,l0Prompt:this.activeTaskTrace,l1Summaries:s,candidates:t}):this.runHeuristicArbiter(e,t);if(this.applyArbiterDecision(o),this.autoExtractMemories)if(this.extract)try{await this.applyExtraction(await this.extract({userMessage:e.userMessage,assistantResponse:e.assistantResponse}))}catch{this.autoExtractTurnMemory(e.userMessage,e.assistantResponse)}else e.assistantResponse.length>50&&this.autoExtractTurnMemory(e.userMessage,e.assistantResponse);if(this.enforceBudgets(),this.onPersist)try{await this.onPersist(this.getSnapshot())}catch{}}async applyExtraction(e){const t=[];for(const s of e.memories??[]){const o=s.content.trim();if(o.length<8||o.length>600||C(o))continue;let n=o;const r=this.recallSimilar(o);if(r.length>0){let h={action:"add"};if(this.reconcile?t.push({content:o,candidates:r}):r.some(u=>u.content.trim().toLowerCase()===o.trim().toLowerCase())&&(h={action:"merge"}),h.action==="reject"||h.action==="merge"&&r[0]&&this.mergeInto(r[0],h.content,{text:o,stored:!1}))continue;h.action==="replace"&&this.supersede(r.map(u=>u.content)),n=h.content?.trim()||o}const a=Date.now(),l=`mem-${a}-${Math.random().toString(36).slice(2,7)}`;this.addMemory({id:l,content:n,bookmark:n.slice(0,80),tier:"L1",metadata:{domains:s.domains??[],createdAt:a,lastAccessedAt:a,accessCount:1}},"L1")}if(t.length>0&&this.reconcile){let s=[];try{s=await this.reconcile({items:t.map(o=>({candidate:o.content,remember:o.candidates.map(n=>n.content)}))})}catch{s=[]}for(const[o,n]of t.entries()){const r=s[o];if(r)if(r.action==="reject")this.removeByContent(n.content);else if(r.action==="merge"){const a=n.candidates[0];if(a&&this.mergeInto(a,r.content,{text:n.content,stored:!0}))continue}else r.action==="replace"&&(this.supersede(n.candidates.map(a=>a.content)),r.content&&this.replaceByContent(n.content,r.content))}}for(const s of e.tensions??[]){const o=`${s.claimA}::${s.claimB}`.toLowerCase();this.activeTensions.has(o)||this.addTension({id:o,status:"active",claimA:{source:"user",statement:s.claimA,timestamp:Date.now()},claimB:{source:"conversation",statement:s.claimB,timestamp:Date.now()},impact:s.impact,taskRelevance:1,actionableQuestion:s.actionableQuestion})}}removeByContent(e){const t=e.trim().toLowerCase();for(const s of[this.l1HotCache,this.l2WarmStore,this.l3ColdArchive])for(const[o,n]of s)n.content.trim().toLowerCase()===t&&s.delete(o)}replaceByContent(e,t){const s=e.trim().toLowerCase();for(const o of[this.l1HotCache,this.l2WarmStore,this.l3ColdArchive])for(const n of o.values())n.content.trim().toLowerCase()===s&&!v(n.content,t)&&this.enrich(n,t)}enrich(e,t){e.content=t,e.bookmark=t.slice(0,80),e.metadata.lastAccessedAt=Date.now()}mergeInto(e,t,s){const o=t?.trim();return o&&(v(e.content,o)||v(s.text,o))?!1:(s.stored&&this.removeByContent(s.text),o&&this.enrich(e,o),!0)}supersede(e){const t=new Set(e.map(s=>s.trim().toLowerCase()));for(const s of[this.l1HotCache,this.l2WarmStore,this.l3ColdArchive])for(const[o,n]of s)t.has(n.content.trim().toLowerCase())&&s.delete(o)}recallSimilar(e){const t=p(e);return t.size===0?[]:[...this.l1HotCache.values(),...this.l2WarmStore.values(),...this.l3ColdArchive.values()].map(n=>{const r=p(n.content);let a=0;for(const l of t)r.has(l)&&(a+=1);return{item:n,exact:n.content.trim().toLowerCase()===e.trim().toLowerCase(),score:r.size?a/Math.min(t.size,r.size):0}}).filter(n=>n.exact||n.score>=z).sort((n,r)=>Number(r.exact)-Number(n.exact)||r.score-n.score).slice(0,B).map(n=>n.item)}enforceBudgets(){((t,s)=>{if(s<=0)return;let o=0;for(const r of t.values())o+=r.content.length/4;if(o<=s)return;const n=[...t.values()].sort((r,a)=>r.metadata.lastAccessedAt-a.metadata.lastAccessedAt);for(const r of n){if(o<=s)break;t.delete(r.id),o-=r.content.length/4,this.l2WarmStore.set(r.id,{...r,tier:"L2"})}})(this.l1HotCache,this.maxL1Tokens)}addTension(e){this.activeTensions.set(e.id,e),this.stats.tensionsDetected+=1}resolveTension(e,t){const s=this.activeTensions.get(e);return s?(s.status="resolved",s.resolution={resolvedAt:Date.now(),resolvedBy:t.resolvedBy,pattern:t.pattern},!0):!1}addMemory(e,t="L2"){e.tier=t,t==="L1"?this.l1HotCache.set(e.id,e):t==="L2"?this.l2WarmStore.set(e.id,e):t==="L3"&&this.l3ColdArchive.set(e.id,e)}removeMemory(e){return this.l1HotCache.delete(e)||this.l2WarmStore.delete(e)||this.l3ColdArchive.delete(e)}recordDomainOutcome(e,t,s){const o=this.selfModel.domains[e]??{reliabilityScore:.8,sampleCount:0,knownFailurePatterns:[],recommendedStrategies:[]},n=o.sampleCount+1,r=1/Math.min(n,10),a=t?1:0,l=o.reliabilityScore*(1-r)+a*r;!t&&s&&!o.knownFailurePatterns.includes(s)&&o.knownFailurePatterns.push(s),this.selfModel.domains[e]={reliabilityScore:Number(l.toFixed(3)),sampleCount:n,knownFailurePatterns:o.knownFailurePatterns,recommendedStrategies:o.recommendedStrategies}}getSnapshot(){return{l0:{tensions:Array.from(this.activeTensions.values()),selfModel:JSON.parse(JSON.stringify(this.selfModel)),activeTaskTrace:this.activeTaskTrace},l1:Array.from(this.l1HotCache.values()),l2:Array.from(this.l2WarmStore.values()),l3:Array.from(this.l3ColdArchive.values()),stats:{...this.stats}}}loadSnapshot(e){this.activeTensions.clear();for(const t of e.l0.tensions)this.activeTensions.set(t.id,t);this.selfModel=e.l0.selfModel,this.activeTaskTrace=e.l0.activeTaskTrace,this.l1HotCache.clear();for(const t of e.l1)this.l1HotCache.set(t.id,t);this.l2WarmStore.clear();for(const t of e.l2)this.l2WarmStore.set(t.id,t);this.l3ColdArchive.clear();for(const t of e.l3)this.l3ColdArchive.set(t.id,t);this.stats={...e.stats}}applyArbiterDecision(e){for(const t of e.promotions){const s=this.l2WarmStore.get(t.memoryId)??this.l3ColdArchive.get(t.memoryId);s&&(s.tier="L1",s.metadata.lastAccessedAt=Date.now(),s.metadata.accessCount+=1,this.l1HotCache.set(s.id,s),this.l2WarmStore.delete(s.id),this.l3ColdArchive.delete(s.id))}for(const t of e.demotions){const s=this.l1HotCache.get(t.memoryId);s&&(s.tier="L2",this.l2WarmStore.set(s.id,s),this.l1HotCache.delete(s.id))}for(const t of e.detectedTensions){const s=`tension-${Date.now()}-${Math.random().toString(36).slice(2,6)}`;this.addTension({id:s,status:"active",claimA:{source:"current conversation",statement:t.claimA,timestamp:Date.now()},claimB:{source:"known state / files",statement:t.claimB,timestamp:Date.now()},impact:t.impact,taskRelevance:1,actionableQuestion:t.actionableQuestion})}if(e.selfModelUpdate){const{domain:t,success:s,failurePatternObserved:o}=e.selfModelUpdate;s!==void 0&&this.recordDomainOutcome(t,s,o)}}runHeuristicArbiter(e,t){const s=[],o=[],n=g(`${e.userMessage} ${e.assistantResponse}`),r=t.map(a=>({candidate:a,score:y(n,g(`${a.bookmark} ${a.domains.join(" ")}`))})).filter(a=>a.score>U).sort((a,l)=>l.score-a.score).slice(0,3);for(const{candidate:a,score:l}of r)s.push({memoryId:a.id,targetTier:"L1",signalType:"anticipatory",urgency:Math.min(1,l)});for(const a of this.l1HotCache.values())!(y(n,g(`${a.bookmark} ${a.metadata.domains.join(" ")}`))>0)&&this.l1HotCache.size>re&&o.push({memoryId:a.id,targetTier:"L2",reason:"Not referenced in recent turns"});return process.env.NAH_MEMORY_DEBUG&&console.log(` [arbiter] scored=${JSON.stringify(r.map(a=>({id:a.candidate.id,score:Number(a.score.toFixed(2))})))} promotions=${s.length} demotions=${o.length}`),{promotions:s,demotions:o,pins:[],detectedTensions:[]}}autoExtractTurnMemory(e,t){const s=e.match(/(?:always|never|make sure to|remember to|use)\s+([^\.\n]+)/i);if(s&&s[1]){const o=`mem-pref-${Date.now()}`,n=s[1].trim();if(C(`User preference: ${n}`))return;this.addMemory({id:o,content:`User preference: ${n}`,bookmark:`User preference: ${n.slice(0,80)}`,tier:"L1",metadata:{domains:this.selfModel.activeDomains,createdAt:Date.now(),lastAccessedAt:Date.now(),accessCount:1}},"L1")}}}const ce=/\bhttps?:\/\/[^\s<>()[\]"'`]+/g,le=/\b(always|never|must|should|make sure to|remember to)\b[\s:]+([^.?!\n]{4,160})/gi,he=/\b([A-Za-z][\w ()-]{2,60}?)\s+(?:is|are)\s+([^\n?!]{3,200})/g,de=/[A-Z0-9_./:-]/,me=i=>{const e=i.trim();return e.length<3||e.length>200||/^(not|nothing|unclear|unknown|the same|that|this|it)\b/i.test(e)?!1:de.test(e)},ue=i=>{const e=/\.(?=\s+[A-Z(])/.exec(i);return e?i.slice(0,e.index):i},w=i=>ue(i).replace(/\s+/g," ").replace(/^(?:that|the|a|an|it|this)\s+/i,"").replace(/[,;:\s.。]+$/,"").trim(),fe=i=>{const e=[],t=o=>{const n=w(o);n.length<8||n.length>300||/^(yes|no|ok|okay|sure|thanks|thank you|got it|noted)\b/i.test(n)||e.some(r=>r.content.toLowerCase()===n.toLowerCase())||e.push({content:n,domains:[]})};for(const o of i.match(ce)??[])t(`User-provided URL: ${o}`);for(const o of i.matchAll(le)){const n=(o[1]??"").toLowerCase(),r=w(o[2]??"");r&&t(`User requirement (${n}): ${r}`)}for(const o of i.matchAll(he)){const n=w(o[1]??""),r=w(o[2]??"");!n||!me(r)||t(`${n} is ${r}`)}return e.filter((o,n)=>!e.some((r,a)=>a===n||r.content.length<=o.content.length?!1:pe(o.content,r.content))).slice(0,6)},pe=(i,e)=>{const t=new Set(e.toLowerCase().split(/[^a-z0-9]+/).filter(o=>o.length>=4)),s=i.toLowerCase().split(/[^a-z0-9]+/).filter(o=>o.length>=4);return s.length>0&&s.every(o=>t.has(o))};exports.CANDIDATE_FLOOR=z;exports.COLLAPSE_THRESHOLD=_;exports.Cogmem=P;exports.CognitiveMemory=ae;exports.CognitiveMemoryError=b;exports.ContextResource=x;exports.MAX_CANDIDATES=B;exports.MemoriesResource=L;exports.PROMOTE_THRESHOLD=U;exports.RecallResource=D;exports.SelfModelResource=R;exports.StatsResource=O;exports.TensionsResource=H;exports.TurnsResource=j;exports.createClient=Z;exports.createHttpClient=E;exports.distinctiveTokens=p;exports.estimateTokens=W;exports.extractDeterministic=fe;exports.extractDomains=S;exports.extractIdentifiers=oe;exports.fetchHealth=I;exports.gistOf=k;exports.isInteractionScoped=C;exports.isLossyRewrite=v;exports.normalise=ie;exports.overlapScore=y;exports.recallOrExplain=K;exports.relevanceTokens=g;exports.runFastGate=N;exports.runTurn=Q;exports.seedMemories=V;exports.similarity=F;
15
+ //# sourceMappingURL=cognitive-memory.cjs.map