@caupulican/pi-adaptative 0.94.0 → 0.94.1
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/CHANGELOG.md +16 -0
- package/dist/core/agent-paths.d.ts +2 -0
- package/dist/core/agent-paths.d.ts.map +1 -1
- package/dist/core/agent-paths.js +7 -0
- package/dist/core/agent-paths.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +5 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +8 -0
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +75 -5
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/background-tool-task-controller.d.ts +15 -0
- package/dist/core/background-tool-task-controller.d.ts.map +1 -1
- package/dist/core/background-tool-task-controller.js +122 -15
- package/dist/core/background-tool-task-controller.js.map +1 -1
- package/dist/core/context/long-term-memory-trigger.d.ts +3 -1
- package/dist/core/context/long-term-memory-trigger.d.ts.map +1 -1
- package/dist/core/context/long-term-memory-trigger.js +1 -1
- package/dist/core/context/long-term-memory-trigger.js.map +1 -1
- package/dist/core/context/okf-memory-provider.d.ts +3 -0
- package/dist/core/context/okf-memory-provider.d.ts.map +1 -1
- package/dist/core/context/okf-memory-provider.js +66 -31
- package/dist/core/context/okf-memory-provider.js.map +1 -1
- package/dist/core/context/okf-memory.d.ts +18 -1
- package/dist/core/context/okf-memory.d.ts.map +1 -1
- package/dist/core/context/okf-memory.js +48 -0
- package/dist/core/context/okf-memory.js.map +1 -1
- package/dist/core/delegation/worker-agent-control.d.ts +4 -0
- package/dist/core/delegation/worker-agent-control.d.ts.map +1 -1
- package/dist/core/delegation/worker-agent-control.js.map +1 -1
- package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -1
- package/dist/core/delegation/worker-execution-policy.js +1 -1
- package/dist/core/delegation/worker-execution-policy.js.map +1 -1
- package/dist/core/delegation/worker-notification-coordinator.d.ts +10 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-notification-coordinator.js +69 -3
- package/dist/core/delegation/worker-notification-coordinator.js.map +1 -1
- package/dist/core/foreground-terminal-handoff-controller.d.ts +17 -0
- package/dist/core/foreground-terminal-handoff-controller.d.ts.map +1 -1
- package/dist/core/foreground-terminal-handoff-controller.js +78 -10
- package/dist/core/foreground-terminal-handoff-controller.js.map +1 -1
- package/dist/core/learning/learning-audit.d.ts +5 -1
- package/dist/core/learning/learning-audit.d.ts.map +1 -1
- package/dist/core/learning/learning-audit.js +32 -1
- package/dist/core/learning/learning-audit.js.map +1 -1
- package/dist/core/learning/reflection-engine.d.ts +20 -0
- package/dist/core/learning/reflection-engine.d.ts.map +1 -1
- package/dist/core/learning/reflection-engine.js +58 -0
- package/dist/core/learning/reflection-engine.js.map +1 -1
- package/dist/core/memory/okf-project-memory-store.d.ts +28 -0
- package/dist/core/memory/okf-project-memory-store.d.ts.map +1 -0
- package/dist/core/memory/okf-project-memory-store.js +111 -0
- package/dist/core/memory/okf-project-memory-store.js.map +1 -0
- package/dist/core/memory/providers/file-store.d.ts +42 -1
- package/dist/core/memory/providers/file-store.d.ts.map +1 -1
- package/dist/core/memory/providers/file-store.js +274 -13
- package/dist/core/memory/providers/file-store.js.map +1 -1
- package/dist/core/memory-controller.d.ts +10 -1
- package/dist/core/memory-controller.d.ts.map +1 -1
- package/dist/core/memory-controller.js +72 -8
- package/dist/core/memory-controller.js.map +1 -1
- package/dist/core/provider-prompt-contracts.d.ts.map +1 -1
- package/dist/core/provider-prompt-contracts.js +9 -19
- package/dist/core/provider-prompt-contracts.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +7 -0
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +94 -15
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/tools/delegate-status.d.ts +2 -0
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +4 -0
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +2 -0
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +83 -21
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/tool-task.d.ts +1 -0
- package/dist/core/tools/tool-task.d.ts.map +1 -1
- package/dist/core/tools/tool-task.js +13 -8
- package/dist/core/tools/tool-task.js.map +1 -1
- package/dist/core/util/atomic-file.d.ts +2 -0
- package/dist/core/util/atomic-file.d.ts.map +1 -1
- package/dist/core/util/atomic-file.js +4 -0
- package/dist/core/util/atomic-file.js.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.js +2 -0
- package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
- package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -1
- package/dist/modes/interactive/components/activity-lane.js +12 -23
- package/dist/modes/interactive/components/activity-lane.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +125 -1
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okf-project-memory-store.js","sourceRoot":"","sources":["../../../src/core/memory/okf-project-memory-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { okfMemoryDir, okfProjectMemoryDir } from \"../agent-paths.ts\";\nimport { isPathWithinScope, safeRealpathSync } from \"../autonomy/path-scope.ts\";\nimport {\n\tformatOkfMemoryDocument,\n\ttype OkfMemoryDocumentInput,\n\ttype PiOkfType,\n\tvalidateOkfMemoryDocumentInput,\n} from \"../context/okf-memory.ts\";\nimport { loadOkfMemoryBundle } from \"../context/okf-memory-provider.ts\";\nimport { getDirectoryResourceProfileInfo } from \"../settings-manager.ts\";\nimport { isMissingFileError, withFileLock, writeFileAtomic } from \"../util/atomic-file.ts\";\nimport { readBoundedTextFile } from \"../util/bounded-file.ts\";\n\nconst MAX_OKF_DOCUMENT_BYTES = 16_384;\n\nfunction digest(content: string): string {\n\treturn createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n\nexport interface OkfProjectMemoryPutResult {\n\tcreated: boolean;\n\tdigest: string;\n\tpath: string;\n}\n\nexport interface OkfProjectMemoryRemoveResult {\n\tremoved: boolean;\n}\n\n/**\n * Durable storage owner for model-authored project OKF records. It owns project identity, bounds,\n * conflict policy, symlink containment, per-record locking, and atomic replacement. Existing\n * different content is never overwritten by an `add`; reflection must confront it explicitly.\n */\nexport class OkfProjectMemoryStore {\n\treadonly projectId: string;\n\treadonly projectRoot: string;\n\tprivate readonly agentDir: string;\n\tprivate readonly rootDir: string;\n\tprivate readonly projectDir: string;\n\n\tconstructor(agentDir: string, cwd: string) {\n\t\tconst identity = getDirectoryResourceProfileInfo(cwd, agentDir);\n\t\tthis.agentDir = agentDir;\n\t\tthis.rootDir = okfMemoryDir(agentDir);\n\t\tthis.projectId = identity.hash;\n\t\tthis.projectRoot = identity.root;\n\t\tthis.projectDir = okfProjectMemoryDir(agentDir, identity.hash);\n\t}\n\n\tprivate recordPath(type: PiOkfType, title: string): string {\n\t\tconst path = join(this.projectDir, `${digest(`${type}\\0${title}`)}.okf.md`);\n\t\tif (!isPathWithinScope(path, this.projectDir)) throw new Error(\"OKF record escaped its project root.\");\n\t\treturn path;\n\t}\n\n\tprivate assertContained(path: string): void {\n\t\tconst canonicalAgentDir = safeRealpathSync(this.agentDir);\n\t\tconst canonicalRootDir = safeRealpathSync(this.rootDir);\n\t\tconst canonicalProjectDir = safeRealpathSync(this.projectDir);\n\t\tconst canonicalPath = safeRealpathSync(path);\n\t\tif (!isPathWithinScope(canonicalRootDir, canonicalAgentDir)) {\n\t\t\tthrow new Error(\"OKF memory root escapes the agent directory.\");\n\t\t}\n\t\tif (!isPathWithinScope(canonicalProjectDir, canonicalRootDir)) {\n\t\t\tthrow new Error(\"OKF project root escapes the OKF memory root.\");\n\t\t}\n\t\tif (!isPathWithinScope(canonicalPath, canonicalProjectDir)) {\n\t\t\tthrow new Error(\"OKF record escapes its project root.\");\n\t\t}\n\t}\n\n\tasync put(input: Omit<OkfMemoryDocumentInput, \"projectId\">): Promise<OkfProjectMemoryPutResult> {\n\t\tconst errors = validateOkfMemoryDocumentInput(input, { projectOnly: true, requireEvidence: true });\n\t\tif (errors.length > 0) throw new Error(`Invalid OKF record: ${errors.join(\"; \")}`);\n\t\tconst document = formatOkfMemoryDocument({ ...input, projectId: this.projectId });\n\t\tconst documentDigest = digest(document);\n\t\tconst path = this.recordPath(input.type, input.title);\n\t\tthis.assertContained(path);\n\t\treturn withFileLock(path, async () => {\n\t\t\tthis.assertContained(path);\n\t\t\ttry {\n\t\t\t\tconst existing = await readBoundedTextFile(path, MAX_OKF_DOCUMENT_BYTES, \"OKF project record\");\n\t\t\t\tif (existing === document) return { created: false, digest: documentDigest, path };\n\t\t\t\tthrow new Error(\"A different structured record already exists for this type and title.\");\n\t\t\t} catch (error) {\n\t\t\t\tif (!isMissingFileError(error)) throw error;\n\t\t\t}\n\t\t\tawait writeFileAtomic(path, document, { mode: 0o600 });\n\t\t\treturn { created: true, digest: documentDigest, path };\n\t\t});\n\t}\n\n\tasync remove(type: PiOkfType, title: string, expectedDigest?: string): Promise<OkfProjectMemoryRemoveResult> {\n\t\tconst path = this.recordPath(type, title);\n\t\tthis.assertContained(path);\n\t\treturn withFileLock(path, async () => {\n\t\t\tthis.assertContained(path);\n\t\t\tlet existing: string;\n\t\t\ttry {\n\t\t\t\texisting = await readBoundedTextFile(path, MAX_OKF_DOCUMENT_BYTES, \"OKF project record\");\n\t\t\t} catch (error) {\n\t\t\t\tif (isMissingFileError(error)) return { removed: false };\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (expectedDigest !== undefined && digest(existing) !== expectedDigest) {\n\t\t\t\tthrow new Error(\"OKF record changed after the audited write; refusing removal.\");\n\t\t\t}\n\t\t\tawait fs.unlink(path);\n\t\t\treturn { removed: true };\n\t\t});\n\t}\n\n\tlist(maxDocuments = 64): string {\n\t\treturn loadOkfMemoryBundle({\n\t\t\trootDir: this.rootDir,\n\t\t\tprojectId: this.projectId,\n\t\t\tprojectRoot: this.projectRoot,\n\t\t\tmaxDocuments,\n\t\t})\n\t\t\t.entries.map(({ relativePath, parsed }) => {\n\t\t\t\tconst item = parsed.item;\n\t\t\t\treturn item === undefined ? \"\" : `${relativePath}: ${item.title ?? \"Untitled\"} — ${item.summary}`;\n\t\t\t})\n\t\t\t.filter((entry) => entry.length > 0)\n\t\t\t.join(\"\\n\")\n\t\t\t.slice(0, 8_000);\n\t}\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MemoryPromptBudget } from "../../context/memory-prompt-budget.ts";
|
|
2
|
+
import { type PiOkfType } from "../../context/okf-memory.ts";
|
|
2
3
|
import type { ToolDefinition } from "../../extensions/types.ts";
|
|
3
4
|
import type { MemoryLifecycleContext, MemoryProvider } from "../memory-provider.ts";
|
|
4
5
|
/**
|
|
@@ -9,8 +10,42 @@ import type { MemoryLifecycleContext, MemoryProvider } from "../memory-provider.
|
|
|
9
10
|
export declare function supersedeNearDuplicateLine(existing: string, content: string): string | null;
|
|
10
11
|
export interface FileStoreProviderOptions {
|
|
11
12
|
onDurableMemoryChanged?: () => void;
|
|
13
|
+
/** Test seam between loss-safe OKF creation and exact hot-memory removal. */
|
|
14
|
+
beforeOrganizeHotRemoval?: () => void | Promise<void>;
|
|
12
15
|
}
|
|
13
|
-
export
|
|
16
|
+
export type StructuredReflectionWrite = {
|
|
17
|
+
kind: "okf_add";
|
|
18
|
+
type: PiOkfType;
|
|
19
|
+
title: string;
|
|
20
|
+
description: string;
|
|
21
|
+
text: string;
|
|
22
|
+
tags?: string[];
|
|
23
|
+
evidenceRefs: string[];
|
|
24
|
+
} | {
|
|
25
|
+
kind: "okf_organize";
|
|
26
|
+
type: PiOkfType;
|
|
27
|
+
title: string;
|
|
28
|
+
description: string;
|
|
29
|
+
text: string;
|
|
30
|
+
sourceText: string;
|
|
31
|
+
tags?: string[];
|
|
32
|
+
evidenceRefs: string[];
|
|
33
|
+
};
|
|
34
|
+
export interface StructuredReflectionApplyResult {
|
|
35
|
+
applied: boolean;
|
|
36
|
+
created: boolean;
|
|
37
|
+
digest?: string;
|
|
38
|
+
sourceRemoved?: boolean;
|
|
39
|
+
error?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface StructuredReflectionRollback {
|
|
42
|
+
type: PiOkfType;
|
|
43
|
+
title: string;
|
|
44
|
+
expectedDigest?: string;
|
|
45
|
+
sourceText?: string;
|
|
46
|
+
removeRecord: boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare const FILE_STORE_MEMORY_SYSTEM_NOTE = "[System Note: Below is a snapshot of persistent memory. Proactively record verified reusable project facts and user preferences with the 'memory' tool. Keep MEMORY.md for compact hot facts, USER.md for preferences, and use target 'okf' for durable project decisions, architecture, rules, findings, and references. Never store transient noise.]";
|
|
14
49
|
export declare class FileStoreProvider implements MemoryProvider {
|
|
15
50
|
readonly name = "file-store";
|
|
16
51
|
readonly egress = "local";
|
|
@@ -22,6 +57,7 @@ export declare class FileStoreProvider implements MemoryProvider {
|
|
|
22
57
|
private lastWrittenMemory;
|
|
23
58
|
private lastWrittenUser;
|
|
24
59
|
private userArchive?;
|
|
60
|
+
private okfStore?;
|
|
25
61
|
private readonly options;
|
|
26
62
|
private static readonly BUDGET_MEMORY;
|
|
27
63
|
private static readonly BUDGET_USER;
|
|
@@ -35,6 +71,11 @@ export declare class FileStoreProvider implements MemoryProvider {
|
|
|
35
71
|
systemPromptBlock(budget?: MemoryPromptBudget): string;
|
|
36
72
|
prefetch(_query: string): Promise<string>;
|
|
37
73
|
shutdown(): Promise<void>;
|
|
74
|
+
private executeMemoryCommand;
|
|
75
|
+
/** Reflection-owned structured write. Organization is OKF-first, then exact hot-memory removal. */
|
|
76
|
+
applyStructuredReflectionWrite(write: StructuredReflectionWrite, signal?: AbortSignal): Promise<StructuredReflectionApplyResult>;
|
|
77
|
+
/** Restore hot memory first, then conditionally remove the exact audited OKF bytes. */
|
|
78
|
+
rollbackStructuredReflectionWrite(rollback: StructuredReflectionRollback, signal?: AbortSignal): Promise<boolean>;
|
|
38
79
|
getContextMarkers(): string[];
|
|
39
80
|
getToolDefinitions(): ToolDefinition[];
|
|
40
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../../../src/core/memory/providers/file-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAQhE,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../../../src/core/memory/providers/file-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,11 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { promises as fs } from "node:fs";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
4
|
import { configFile, managedMemoryStateFile } from "../../agent-paths.js";
|
|
5
|
+
import { OKF_MEMORY_LIMITS, PI_OKF_TYPES, validateOkfMemoryDocumentInput, } from "../../context/okf-memory.js";
|
|
5
6
|
import { hasInvisibleUnicode, scanContextFileThreats, stripInvisibleUnicode, } from "../../security/context-threat-scanner.js";
|
|
6
7
|
import { jaccard, tokenize } from "../../tools/skill-audit.js";
|
|
7
|
-
import { withFileLock, writeFileAtomic } from "../../util/atomic-file.js";
|
|
8
|
+
import { isMissingFileError, withFileLock, writeFileAtomic } from "../../util/atomic-file.js";
|
|
9
|
+
import { OkfProjectMemoryStore } from "../okf-project-memory-store.js";
|
|
8
10
|
import { UserMemoryArchive } from "./user-memory-archive.js";
|
|
9
11
|
/**
|
|
10
12
|
* Confront-before-write (anti append-rot): if `content` is a near-duplicate of an existing
|
|
@@ -39,22 +41,48 @@ export function supersedeNearDuplicateLine(existing, content) {
|
|
|
39
41
|
return lines.join("\n");
|
|
40
42
|
}
|
|
41
43
|
const memorySchema = Type.Object({
|
|
42
|
-
action: Type.Union([Type.Literal("add"), Type.Literal("replace"), Type.Literal("remove")], {
|
|
44
|
+
action: Type.Union([Type.Literal("add"), Type.Literal("replace"), Type.Literal("remove"), Type.Literal("list")], {
|
|
43
45
|
description: "Action to perform: add new content, replace existing content, or remove content",
|
|
44
46
|
}),
|
|
45
|
-
target: Type.Union([Type.Literal("memory"), Type.Literal("user")], {
|
|
46
|
-
description: "Target
|
|
47
|
+
target: Type.Union([Type.Literal("memory"), Type.Literal("user"), Type.Literal("okf")], {
|
|
48
|
+
description: "Target: 'memory' for MEMORY.md, 'user' for USER.md, or 'okf' for structured project memory",
|
|
47
49
|
}),
|
|
48
|
-
content: Type.Optional(Type.String({
|
|
50
|
+
content: Type.Optional(Type.String({
|
|
51
|
+
maxLength: OKF_MEMORY_LIMITS.bodyChars,
|
|
52
|
+
description: "Content to write (required for add/replace)",
|
|
53
|
+
})),
|
|
54
|
+
title: Type.Optional(Type.String({
|
|
55
|
+
minLength: 1,
|
|
56
|
+
maxLength: OKF_MEMORY_LIMITS.titleChars,
|
|
57
|
+
description: "Structured OKF title (required when target is 'okf')",
|
|
58
|
+
})),
|
|
49
59
|
oldContent: Type.Optional(Type.String({ description: "Exact substring to replace or remove (required for 'replace' or 'remove')" })),
|
|
60
|
+
type: Type.Optional(Type.Union(PI_OKF_TYPES.map((value) => Type.Literal(value)), {
|
|
61
|
+
description: "Structured OKF type (required when target is 'okf')",
|
|
62
|
+
})),
|
|
63
|
+
description: Type.Optional(Type.String({
|
|
64
|
+
minLength: 1,
|
|
65
|
+
maxLength: OKF_MEMORY_LIMITS.descriptionChars,
|
|
66
|
+
description: "Structured OKF summary (required when target is 'okf')",
|
|
67
|
+
})),
|
|
68
|
+
scope: Type.Optional(Type.Literal("project", { description: "Structured OKF records are project-scoped" })),
|
|
69
|
+
tags: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: OKF_MEMORY_LIMITS.tagChars }), {
|
|
70
|
+
maxItems: OKF_MEMORY_LIMITS.tagCount,
|
|
71
|
+
uniqueItems: true,
|
|
72
|
+
description: "Structured OKF tags",
|
|
73
|
+
})),
|
|
74
|
+
evidenceRefs: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: OKF_MEMORY_LIMITS.evidenceRefChars }), {
|
|
75
|
+
minItems: 1,
|
|
76
|
+
maxItems: OKF_MEMORY_LIMITS.evidenceRefCount,
|
|
77
|
+
uniqueItems: true,
|
|
78
|
+
description: "Evidence references for structured OKF",
|
|
79
|
+
})),
|
|
80
|
+
expectedDigest: Type.Optional(Type.String({ pattern: "^[a-f0-9]{64}$", description: "Optional conflict guard for structured removal" })),
|
|
50
81
|
});
|
|
51
|
-
export const FILE_STORE_MEMORY_SYSTEM_NOTE = "[System Note: Below is a snapshot of persistent memory. Proactively record verified reusable project facts and user preferences with the 'memory' tool
|
|
82
|
+
export const FILE_STORE_MEMORY_SYSTEM_NOTE = "[System Note: Below is a snapshot of persistent memory. Proactively record verified reusable project facts and user preferences with the 'memory' tool. Keep MEMORY.md for compact hot facts, USER.md for preferences, and use target 'okf' for durable project decisions, architecture, rules, findings, and references. Never store transient noise.]";
|
|
52
83
|
function contentDigest(content) {
|
|
53
84
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
54
85
|
}
|
|
55
|
-
function isMissingFileError(error) {
|
|
56
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
57
|
-
}
|
|
58
86
|
function parseManagedMemoryState(raw) {
|
|
59
87
|
let parsed;
|
|
60
88
|
try {
|
|
@@ -177,6 +205,7 @@ export class FileStoreProvider {
|
|
|
177
205
|
this.userStatePath = managedMemoryStateFile(ctx.agentDir, "USER.md");
|
|
178
206
|
this.userArchive = new UserMemoryArchive(ctx.agentDir);
|
|
179
207
|
await fs.mkdir(ctx.agentDir, { recursive: true });
|
|
208
|
+
this.okfStore = new OkfProjectMemoryStore(ctx.agentDir, ctx.cwd);
|
|
180
209
|
[this.lastWrittenMemory, this.lastWrittenUser] = await Promise.all([
|
|
181
210
|
this.initializeManagedFile(this.memoryFilePath, this.memoryStatePath),
|
|
182
211
|
this.initializeManagedFile(this.userFilePath, this.userStatePath),
|
|
@@ -256,6 +285,70 @@ export class FileStoreProvider {
|
|
|
256
285
|
async shutdown() {
|
|
257
286
|
// no-op
|
|
258
287
|
}
|
|
288
|
+
async executeMemoryCommand(params, signal) {
|
|
289
|
+
const tool = this.getToolDefinitions()[0];
|
|
290
|
+
if (tool === undefined)
|
|
291
|
+
return { details: { success: false, error: "Memory tool unavailable" } };
|
|
292
|
+
const result = await tool.execute("reflection-memory", params, signal, undefined, undefined);
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
/** Reflection-owned structured write. Organization is OKF-first, then exact hot-memory removal. */
|
|
296
|
+
async applyStructuredReflectionWrite(write, signal) {
|
|
297
|
+
const added = await this.executeMemoryCommand({
|
|
298
|
+
action: "add",
|
|
299
|
+
target: "okf",
|
|
300
|
+
type: write.type,
|
|
301
|
+
title: write.title,
|
|
302
|
+
description: write.description,
|
|
303
|
+
scope: "project",
|
|
304
|
+
content: write.text,
|
|
305
|
+
tags: write.tags,
|
|
306
|
+
evidenceRefs: write.evidenceRefs,
|
|
307
|
+
}, signal);
|
|
308
|
+
if (added.details?.success !== true) {
|
|
309
|
+
return { applied: false, created: false, error: added.details?.error ?? "OKF write failed" };
|
|
310
|
+
}
|
|
311
|
+
const created = added.details.created === true;
|
|
312
|
+
const storedDigest = added.details.digest;
|
|
313
|
+
if (write.kind === "okf_add") {
|
|
314
|
+
return {
|
|
315
|
+
applied: created,
|
|
316
|
+
created,
|
|
317
|
+
...(storedDigest ? { digest: storedDigest } : {}),
|
|
318
|
+
...(!created ? { error: "Exact OKF record already exists" } : {}),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
await this.options.beforeOrganizeHotRemoval?.();
|
|
322
|
+
const removed = await this.executeMemoryCommand({ action: "remove", target: "memory", oldContent: write.sourceText }, signal);
|
|
323
|
+
const sourceRemoved = removed.details?.success === true;
|
|
324
|
+
return {
|
|
325
|
+
// A newly-created OKF record is a real durable change even if exact hot cleanup was
|
|
326
|
+
// interrupted. This records a reversible partial apply instead of hiding landed data.
|
|
327
|
+
applied: created || sourceRemoved,
|
|
328
|
+
created,
|
|
329
|
+
...(storedDigest ? { digest: storedDigest } : {}),
|
|
330
|
+
sourceRemoved,
|
|
331
|
+
...(!sourceRemoved ? { error: removed.details?.error ?? "Hot-memory removal failed" } : {}),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
/** Restore hot memory first, then conditionally remove the exact audited OKF bytes. */
|
|
335
|
+
async rollbackStructuredReflectionWrite(rollback, signal) {
|
|
336
|
+
if (rollback.sourceText !== undefined) {
|
|
337
|
+
const restored = await this.executeMemoryCommand({ action: "add", target: "memory", content: rollback.sourceText }, signal);
|
|
338
|
+
if (restored.details?.success !== true)
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
if (!rollback.removeRecord)
|
|
342
|
+
return true;
|
|
343
|
+
const removed = await this.executeMemoryCommand({
|
|
344
|
+
action: "remove",
|
|
345
|
+
target: "okf",
|
|
346
|
+
type: rollback.type,
|
|
347
|
+
title: rollback.title,
|
|
348
|
+
expectedDigest: rollback.expectedDigest,
|
|
349
|
+
}, signal);
|
|
350
|
+
return removed.details?.success === true;
|
|
351
|
+
}
|
|
259
352
|
getContextMarkers() {
|
|
260
353
|
return [];
|
|
261
354
|
}
|
|
@@ -264,10 +357,11 @@ export class FileStoreProvider {
|
|
|
264
357
|
{
|
|
265
358
|
name: "memory",
|
|
266
359
|
label: "Persistent Memory Manager",
|
|
267
|
-
description: "Add, replace, or remove durable
|
|
268
|
-
promptSnippet: "Persist verified project
|
|
360
|
+
description: "Add, replace, or remove durable facts and preferences. Use target 'okf' with structured metadata for durable project decisions, architecture, rules, debugging findings, and references; USER.md overflow is migrated into indexed OKF shards.",
|
|
361
|
+
promptSnippet: "Persist verified facts; route durable project knowledge to structured OKF records.",
|
|
269
362
|
promptGuidelines: [
|
|
270
|
-
"
|
|
363
|
+
"OKF=project decisions/rules/findings with type,title,summary,body,evidenceRefs; MEMORY=hot facts; USER=preferences.",
|
|
364
|
+
"Workers gather evidence read-only; only the parent or its reflection writes memory. Repeatable procedures become skills via skillify.",
|
|
271
365
|
],
|
|
272
366
|
parameters: memorySchema,
|
|
273
367
|
execute: async (_toolCallId, params, _signal, _onUpdate, _execCtx) => {
|
|
@@ -282,7 +376,7 @@ export class FileStoreProvider {
|
|
|
282
376
|
details: { success: false, error: "Child session write-gated" },
|
|
283
377
|
};
|
|
284
378
|
}
|
|
285
|
-
const { action, target, content, oldContent } = params;
|
|
379
|
+
const { action, target, content, oldContent, title, type, description, scope, tags, evidenceRefs, expectedDigest, } = params;
|
|
286
380
|
// Strict-scope injection guard on the high-privilege WRITE path (agy #31): a poisoned
|
|
287
381
|
// memory entry persists across sessions and is injected into every future system prompt,
|
|
288
382
|
// so block outright rather than strip. Hidden/bidi-control chars have no legitimate place
|
|
@@ -312,6 +406,173 @@ export class FileStoreProvider {
|
|
|
312
406
|
};
|
|
313
407
|
}
|
|
314
408
|
}
|
|
409
|
+
if (target === "okf") {
|
|
410
|
+
if (action === "list") {
|
|
411
|
+
if (this.okfStore === undefined) {
|
|
412
|
+
return {
|
|
413
|
+
content: [{ type: "text", text: "Error: Memory provider is not initialized." }],
|
|
414
|
+
details: { success: false },
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
const catalog = this.okfStore.list();
|
|
418
|
+
return {
|
|
419
|
+
content: [{ type: "text", text: catalog || "No structured OKF memory records found." }],
|
|
420
|
+
details: { success: true },
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
if (action !== "add" && action !== "remove") {
|
|
424
|
+
return {
|
|
425
|
+
content: [
|
|
426
|
+
{
|
|
427
|
+
type: "text",
|
|
428
|
+
text: "Error: structured OKF memory only supports action 'add' or 'remove'.",
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
details: { success: false, error: "Unsupported OKF action" },
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
if (action === "remove") {
|
|
435
|
+
if (this.okfStore === undefined ||
|
|
436
|
+
type === undefined ||
|
|
437
|
+
title === undefined ||
|
|
438
|
+
!PI_OKF_TYPES.includes(type)) {
|
|
439
|
+
return {
|
|
440
|
+
content: [{ type: "text", text: "Error: OKF removal requires a valid type and title." }],
|
|
441
|
+
details: { success: false, error: "Incomplete OKF removal" },
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
try {
|
|
445
|
+
const removed = await this.okfStore.remove(type, title, expectedDigest);
|
|
446
|
+
if (removed.removed)
|
|
447
|
+
this.options.onDurableMemoryChanged?.();
|
|
448
|
+
return {
|
|
449
|
+
content: [
|
|
450
|
+
{
|
|
451
|
+
type: "text",
|
|
452
|
+
text: removed.removed
|
|
453
|
+
? "Successfully removed structured OKF project memory."
|
|
454
|
+
: "Structured OKF project memory was already absent.",
|
|
455
|
+
},
|
|
456
|
+
],
|
|
457
|
+
details: { success: true, removed: removed.removed },
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
catch (err) {
|
|
461
|
+
const error = String(err);
|
|
462
|
+
return {
|
|
463
|
+
content: [{ type: "text", text: `Error: Failed to remove structured OKF memory: ${error}` }],
|
|
464
|
+
details: { success: false, error: /ENOENT/.test(error) ? "not found" : error },
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (type === undefined ||
|
|
469
|
+
title === undefined ||
|
|
470
|
+
description === undefined ||
|
|
471
|
+
scope !== "project" ||
|
|
472
|
+
content === undefined ||
|
|
473
|
+
evidenceRefs === undefined ||
|
|
474
|
+
evidenceRefs.length === 0) {
|
|
475
|
+
return {
|
|
476
|
+
content: [
|
|
477
|
+
{
|
|
478
|
+
type: "text",
|
|
479
|
+
text: "Error: structured OKF memory requires type, title, description, scope, content, and evidenceRefs.",
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
details: { success: false, error: "Incomplete OKF memory" },
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
if (!PI_OKF_TYPES.includes(type)) {
|
|
486
|
+
return {
|
|
487
|
+
content: [{ type: "text", text: `Error: unsupported OKF type '${type}'.` }],
|
|
488
|
+
details: { success: false, error: "Unsupported OKF type" },
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
const validationErrors = validateOkfMemoryDocumentInput({
|
|
492
|
+
type: type,
|
|
493
|
+
title,
|
|
494
|
+
description,
|
|
495
|
+
scope,
|
|
496
|
+
body: content,
|
|
497
|
+
tags,
|
|
498
|
+
evidenceRefs,
|
|
499
|
+
}, { projectOnly: true, requireEvidence: true });
|
|
500
|
+
if (validationErrors.length > 0) {
|
|
501
|
+
return {
|
|
502
|
+
content: [
|
|
503
|
+
{
|
|
504
|
+
type: "text",
|
|
505
|
+
text: `Error: Invalid structured OKF memory: ${validationErrors.join("; ")}`,
|
|
506
|
+
},
|
|
507
|
+
],
|
|
508
|
+
details: { success: false, error: "Invalid OKF memory" },
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
const okfText = [type, title, description, scope, content, ...(tags ?? []), ...evidenceRefs].join("\n");
|
|
512
|
+
if (hasInvisibleUnicode(okfText)) {
|
|
513
|
+
return {
|
|
514
|
+
content: [
|
|
515
|
+
{
|
|
516
|
+
type: "text",
|
|
517
|
+
text: "Error: OKF write rejected — contains hidden/bidirectional control characters.",
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
details: { success: false, error: "Invisible unicode in OKF write" },
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
const threats = scanContextFileThreats(okfText, "strict");
|
|
524
|
+
if (threats.length > 0) {
|
|
525
|
+
return {
|
|
526
|
+
content: [
|
|
527
|
+
{
|
|
528
|
+
type: "text",
|
|
529
|
+
text: `Error: OKF write rejected — potential injection/exfiltration detected (${threats.join(", ")}).`,
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
details: { success: false, error: "Threat in OKF write" },
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
if (this.okfStore === undefined)
|
|
537
|
+
throw new Error("Memory provider is not initialized.");
|
|
538
|
+
const stored = await this.okfStore.put({
|
|
539
|
+
type: type,
|
|
540
|
+
title,
|
|
541
|
+
description,
|
|
542
|
+
scope,
|
|
543
|
+
body: content,
|
|
544
|
+
tags,
|
|
545
|
+
evidenceRefs,
|
|
546
|
+
});
|
|
547
|
+
if (stored.created)
|
|
548
|
+
this.options.onDurableMemoryChanged?.();
|
|
549
|
+
return {
|
|
550
|
+
content: [
|
|
551
|
+
{
|
|
552
|
+
type: "text",
|
|
553
|
+
text: stored.created
|
|
554
|
+
? "Successfully added structured OKF project memory."
|
|
555
|
+
: "Structured OKF project memory already contained this exact record.",
|
|
556
|
+
},
|
|
557
|
+
],
|
|
558
|
+
details: { success: true, created: stored.created, digest: stored.digest },
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
catch (err) {
|
|
562
|
+
return {
|
|
563
|
+
content: [
|
|
564
|
+
{ type: "text", text: `Error: Failed to write structured OKF memory: ${String(err)}` },
|
|
565
|
+
],
|
|
566
|
+
details: { success: false, error: String(err) },
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (action === "list") {
|
|
571
|
+
return {
|
|
572
|
+
content: [{ type: "text", text: "Error: action 'list' is only supported for target 'okf'." }],
|
|
573
|
+
details: { success: false, error: "Unsupported list target" },
|
|
574
|
+
};
|
|
575
|
+
}
|
|
315
576
|
const filePath = target === "memory" ? this.memoryFilePath : this.userFilePath;
|
|
316
577
|
const statePath = target === "memory" ? this.memoryStatePath : this.userStatePath;
|
|
317
578
|
const budget = target === "memory" ? FileStoreProvider.BUDGET_MEMORY : FileStoreProvider.BUDGET_USER;
|