@graphorin/memory 0.5.0 → 0.6.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 +102 -1
- package/README.md +54 -37
- package/dist/conflict/index.d.ts +3 -1
- package/dist/conflict/index.js +1 -1
- package/dist/conflict/locale-packs/en.d.ts +13 -0
- package/dist/conflict/locale-packs/en.d.ts.map +1 -0
- package/dist/conflict/locale-packs/en.js +1 -1
- package/dist/conflict/locale-packs/en.js.map +1 -1
- package/dist/conflict/pipeline.d.ts +2 -2
- package/dist/conflict/pipeline.js +3 -3
- package/dist/conflict/pipeline.js.map +1 -1
- package/dist/conflict/stages/helpers.js +1 -1
- package/dist/conflict/stages/helpers.js.map +1 -1
- package/dist/conflict/stages/stage1-exact-dedup.js.map +1 -1
- package/dist/conflict/stages/stage2-embedding-three-zone.js.map +1 -1
- package/dist/conflict/stages/stage3-heuristic-regex.js +1 -1
- package/dist/conflict/stages/stage3-heuristic-regex.js.map +1 -1
- package/dist/conflict/stages/stage4-subject-predicate.js.map +1 -1
- package/dist/conflict/stages/stage5-defer-to-deep.js.map +1 -1
- package/dist/conflict/types.d.ts +7 -7
- package/dist/conflict/types.js +1 -1
- package/dist/conflict/types.js.map +1 -1
- package/dist/consolidator/budget.js +16 -3
- package/dist/consolidator/budget.js.map +1 -1
- package/dist/consolidator/decay.d.ts +13 -2
- package/dist/consolidator/decay.js +17 -5
- package/dist/consolidator/decay.js.map +1 -1
- package/dist/consolidator/dlq.js +1 -1
- package/dist/consolidator/dlq.js.map +1 -1
- package/dist/consolidator/errors.js +2 -2
- package/dist/consolidator/errors.js.map +1 -1
- package/dist/consolidator/index.js +8 -6
- package/dist/consolidator/index.js.map +1 -1
- package/dist/consolidator/lock.js +1 -1
- package/dist/consolidator/lock.js.map +1 -1
- package/dist/consolidator/noise-filter.js.map +1 -1
- package/dist/consolidator/phases/deep.js +6 -2
- package/dist/consolidator/phases/deep.js.map +1 -1
- package/dist/consolidator/phases/induce.d.ts +10 -10
- package/dist/consolidator/phases/induce.js +6 -6
- package/dist/consolidator/phases/induce.js.map +1 -1
- package/dist/consolidator/phases/learned-context.js +129 -0
- package/dist/consolidator/phases/learned-context.js.map +1 -0
- package/dist/consolidator/phases/light.js +2 -1
- package/dist/consolidator/phases/light.js.map +1 -1
- package/dist/consolidator/phases/reflect.js +5 -4
- package/dist/consolidator/phases/reflect.js.map +1 -1
- package/dist/consolidator/phases/standard.js +37 -8
- package/dist/consolidator/phases/standard.js.map +1 -1
- package/dist/consolidator/reconcile.js +1 -1
- package/dist/consolidator/reconcile.js.map +1 -1
- package/dist/consolidator/runtime.d.ts +4 -4
- package/dist/consolidator/runtime.d.ts.map +1 -1
- package/dist/consolidator/runtime.js +73 -16
- package/dist/consolidator/runtime.js.map +1 -1
- package/dist/consolidator/scheduler.d.ts +5 -5
- package/dist/consolidator/scheduler.js +1 -1
- package/dist/consolidator/scheduler.js.map +1 -1
- package/dist/consolidator/triggers.js +7 -7
- package/dist/consolidator/triggers.js.map +1 -1
- package/dist/consolidator/types.d.ts +68 -20
- package/dist/consolidator/types.d.ts.map +1 -1
- package/dist/consolidator/types.js +16 -6
- package/dist/consolidator/types.js.map +1 -1
- package/dist/context-engine/annotations.d.ts +9 -9
- package/dist/context-engine/annotations.js +3 -3
- package/dist/context-engine/annotations.js.map +1 -1
- package/dist/context-engine/auto-recall.js.map +1 -1
- package/dist/context-engine/compaction/clear-tool-results.d.ts +18 -3
- package/dist/context-engine/compaction/clear-tool-results.d.ts.map +1 -1
- package/dist/context-engine/compaction/clear-tool-results.js +26 -5
- package/dist/context-engine/compaction/clear-tool-results.js.map +1 -1
- package/dist/context-engine/compaction/compactor.js +19 -6
- package/dist/context-engine/compaction/compactor.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-persona-block.js +4 -0
- package/dist/context-engine/compaction/hooks/reanchor-persona-block.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.js +1 -0
- package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-project-rules.js +2 -1
- package/dist/context-engine/compaction/hooks/reanchor-project-rules.js.map +1 -1
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.d.ts +28 -0
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.d.ts.map +1 -0
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.js +71 -0
- package/dist/context-engine/compaction/hooks/reanchor-recent-results.js.map +1 -0
- package/dist/context-engine/compaction/hooks/types.d.ts +15 -3
- package/dist/context-engine/compaction/hooks/types.d.ts.map +1 -1
- package/dist/context-engine/compaction/index.d.ts +1 -0
- package/dist/context-engine/compaction/index.js +2 -1
- package/dist/context-engine/compaction/templates/summary-9-section.d.ts +10 -3
- package/dist/context-engine/compaction/templates/summary-9-section.d.ts.map +1 -1
- package/dist/context-engine/compaction/templates/summary-9-section.js +42 -5
- package/dist/context-engine/compaction/templates/summary-9-section.js.map +1 -1
- package/dist/context-engine/compaction/thresholds.js.map +1 -1
- package/dist/context-engine/compaction/types.d.ts +47 -7
- package/dist/context-engine/compaction/types.d.ts.map +1 -1
- package/dist/context-engine/engine.d.ts +23 -4
- package/dist/context-engine/engine.d.ts.map +1 -1
- package/dist/context-engine/engine.js +69 -15
- package/dist/context-engine/engine.js.map +1 -1
- package/dist/context-engine/index.d.ts +1 -0
- package/dist/context-engine/index.d.ts.map +1 -1
- package/dist/context-engine/index.js +2 -1
- package/dist/context-engine/locale-packs/en.js +14 -13
- package/dist/context-engine/locale-packs/en.js.map +1 -1
- package/dist/context-engine/locale-packs/types.d.ts +10 -10
- package/dist/context-engine/locale-packs/types.d.ts.map +1 -1
- package/dist/context-engine/locale-packs/types.js.map +1 -1
- package/dist/context-engine/metadata.d.ts +1 -1
- package/dist/context-engine/metadata.js +2 -2
- package/dist/context-engine/metadata.js.map +1 -1
- package/dist/context-engine/preambles/inbound-en.d.ts +1 -1
- package/dist/context-engine/preambles/inbound-en.js +1 -1
- package/dist/context-engine/preambles/inbound-en.js.map +1 -1
- package/dist/context-engine/privacy-filter.d.ts +2 -2
- package/dist/context-engine/privacy-filter.js +1 -1
- package/dist/context-engine/privacy-filter.js.map +1 -1
- package/dist/context-engine/templates/base-en.d.ts +1 -1
- package/dist/context-engine/templates/base-en.js +1 -1
- package/dist/context-engine/templates/base-en.js.map +1 -1
- package/dist/context-engine/templates/composer.d.ts +1 -1
- package/dist/context-engine/templates/composer.js.map +1 -1
- package/dist/context-engine/token-budget.d.ts +1 -1
- package/dist/context-engine/token-budget.js +1 -1
- package/dist/context-engine/token-budget.js.map +1 -1
- package/dist/context-engine/token-counter.d.ts +16 -7
- package/dist/context-engine/token-counter.d.ts.map +1 -1
- package/dist/context-engine/token-counter.js +31 -9
- package/dist/context-engine/token-counter.js.map +1 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.js +4 -4
- package/dist/errors/index.js.map +1 -1
- package/dist/facade.d.ts +44 -15
- package/dist/facade.d.ts.map +1 -1
- package/dist/facade.js +16 -8
- package/dist/facade.js.map +1 -1
- package/dist/graph/entity-resolver.d.ts +2 -2
- package/dist/graph/entity-resolver.js +2 -2
- package/dist/graph/entity-resolver.js.map +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/internal/contextualize.js +2 -2
- package/dist/internal/contextualize.js.map +1 -1
- package/dist/internal/embedder-binding.js +1 -1
- package/dist/internal/embedder-binding.js.map +1 -1
- package/dist/internal/id.js +1 -1
- package/dist/internal/id.js.map +1 -1
- package/dist/internal/injection-heuristics.js +25 -2
- package/dist/internal/injection-heuristics.js.map +1 -1
- package/dist/internal/spans.js +1 -1
- package/dist/internal/spans.js.map +1 -1
- package/dist/internal/storage-adapter.d.ts +71 -22
- package/dist/internal/storage-adapter.d.ts.map +1 -1
- package/dist/migration/embedder-migration.d.ts +7 -7
- package/dist/migration/embedder-migration.js.map +1 -1
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/search/explain.d.ts +7 -4
- package/dist/search/explain.d.ts.map +1 -1
- package/dist/search/explain.js +1 -1
- package/dist/search/explain.js.map +1 -1
- package/dist/search/fit-weights.d.ts +48 -0
- package/dist/search/fit-weights.d.ts.map +1 -0
- package/dist/search/fit-weights.js +70 -0
- package/dist/search/fit-weights.js.map +1 -0
- package/dist/search/graph-ppr.d.ts +36 -0
- package/dist/search/graph-ppr.d.ts.map +1 -0
- package/dist/search/graph-ppr.js +38 -0
- package/dist/search/graph-ppr.js.map +1 -0
- package/dist/search/index.d.ts +4 -1
- package/dist/search/index.js +4 -1
- package/dist/search/iterative.d.ts +15 -8
- package/dist/search/iterative.d.ts.map +1 -1
- package/dist/search/iterative.js +10 -9
- package/dist/search/iterative.js.map +1 -1
- package/dist/search/query-transform.d.ts +6 -6
- package/dist/search/query-transform.js +6 -6
- package/dist/search/query-transform.js.map +1 -1
- package/dist/search/rrf.d.ts +4 -4
- package/dist/search/rrf.js +4 -4
- package/dist/search/rrf.js.map +1 -1
- package/dist/search/trust.d.ts +30 -0
- package/dist/search/trust.d.ts.map +1 -0
- package/dist/search/trust.js +50 -0
- package/dist/search/trust.js.map +1 -0
- package/dist/search/types.d.ts +1 -1
- package/dist/tiers/episodic-memory.d.ts +6 -4
- package/dist/tiers/episodic-memory.d.ts.map +1 -1
- package/dist/tiers/episodic-memory.js +3 -2
- package/dist/tiers/episodic-memory.js.map +1 -1
- package/dist/tiers/index.d.ts +1 -1
- package/dist/tiers/index.js +1 -1
- package/dist/tiers/insight-memory.d.ts +4 -4
- package/dist/tiers/insight-memory.js +3 -3
- package/dist/tiers/insight-memory.js.map +1 -1
- package/dist/tiers/procedural-memory.d.ts +29 -7
- package/dist/tiers/procedural-memory.d.ts.map +1 -1
- package/dist/tiers/procedural-memory.js +66 -6
- package/dist/tiers/procedural-memory.js.map +1 -1
- package/dist/tiers/semantic-memory.d.ts +111 -30
- package/dist/tiers/semantic-memory.d.ts.map +1 -1
- package/dist/tiers/semantic-memory.js +120 -27
- package/dist/tiers/semantic-memory.js.map +1 -1
- package/dist/tiers/session-memory.d.ts +7 -7
- package/dist/tiers/session-memory.js +7 -7
- package/dist/tiers/session-memory.js.map +1 -1
- package/dist/tiers/shared-memory.d.ts +1 -1
- package/dist/tiers/shared-memory.js +1 -1
- package/dist/tiers/shared-memory.js.map +1 -1
- package/dist/tiers/working-memory.d.ts +3 -3
- package/dist/tiers/working-memory.js +2 -2
- package/dist/tiers/working-memory.js.map +1 -1
- package/dist/tools/block-tools.d.ts +3 -3
- package/dist/tools/block-tools.js +3 -3
- package/dist/tools/block-tools.js.map +1 -1
- package/dist/tools/fact-tools.d.ts +48 -31
- package/dist/tools/fact-tools.d.ts.map +1 -1
- package/dist/tools/fact-tools.js +30 -18
- package/dist/tools/fact-tools.js.map +1 -1
- package/dist/tools/index.d.ts +9 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/recall-tools.d.ts +40 -20
- package/dist/tools/recall-tools.d.ts.map +1 -1
- package/dist/tools/recall-tools.js +29 -10
- package/dist/tools/recall-tools.js.map +1 -1
- package/dist/tools/runbook-tools.d.ts +76 -0
- package/dist/tools/runbook-tools.d.ts.map +1 -0
- package/dist/tools/runbook-tools.js +53 -0
- package/dist/tools/runbook-tools.js.map +1 -0
- package/dist/tools/taint.js +33 -0
- package/dist/tools/taint.js.map +1 -0
- package/dist/tools/types.d.ts +1 -1
- package/package.json +8 -8
|
@@ -24,7 +24,7 @@ interface BlockSpec {
|
|
|
24
24
|
* runs preserve any value already in storage.
|
|
25
25
|
*/
|
|
26
26
|
readonly defaultValue?: string;
|
|
27
|
-
/** Default `'truncate'`
|
|
27
|
+
/** Default `'truncate'` - `'reject'` opt-in for strict use cases. */
|
|
28
28
|
readonly overflowPolicy?: 'truncate' | 'reject';
|
|
29
29
|
/** Optional free-form labels surfaced through `tags`. */
|
|
30
30
|
readonly tags?: ReadonlyArray<string>;
|
|
@@ -56,7 +56,7 @@ interface BlockDefinition {
|
|
|
56
56
|
*/
|
|
57
57
|
declare function defineBlock(spec: BlockSpec): BlockDefinition;
|
|
58
58
|
/**
|
|
59
|
-
* `WorkingMemory`
|
|
59
|
+
* `WorkingMemory` - labeled, character-bounded blocks rendered into
|
|
60
60
|
* every system prompt. Operations:
|
|
61
61
|
*
|
|
62
62
|
* - `define(spec)`: idempotently registers a block definition; the
|
|
@@ -120,7 +120,7 @@ declare class WorkingMemory {
|
|
|
120
120
|
*
|
|
121
121
|
* The optional `agentId` argument is reserved for the per-agent
|
|
122
122
|
* filtering Phase 10d wires through. In Phase 10a the argument is
|
|
123
|
-
* accepted but ignored
|
|
123
|
+
* accepted but ignored - the rendering is scope-wide.
|
|
124
124
|
*/
|
|
125
125
|
compile(scope: SessionScope, agentId?: string): Promise<string>;
|
|
126
126
|
}
|
|
@@ -26,7 +26,7 @@ function defineBlock(spec) {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* `WorkingMemory`
|
|
29
|
+
* `WorkingMemory` - labeled, character-bounded blocks rendered into
|
|
30
30
|
* every system prompt. Operations:
|
|
31
31
|
*
|
|
32
32
|
* - `define(spec)`: idempotently registers a block definition; the
|
|
@@ -152,7 +152,7 @@ var WorkingMemory = class {
|
|
|
152
152
|
*
|
|
153
153
|
* The optional `agentId` argument is reserved for the per-agent
|
|
154
154
|
* filtering Phase 10d wires through. In Phase 10a the argument is
|
|
155
|
-
* accepted but ignored
|
|
155
|
+
* accepted but ignored - the rendering is scope-wide.
|
|
156
156
|
*/
|
|
157
157
|
async compile(scope, agentId) {
|
|
158
158
|
const blocks = await this.list(scope);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"working-memory.js","names":["#store","#tracer","#defs","#mutate","#requireDefinition","block: Block"],"sources":["../../src/tiers/working-memory.ts"],"sourcesContent":["import type { Block, Sensitivity, SessionScope, Tracer, ZodLikeSchema } from '@graphorin/core';\nimport {\n WorkingBlockOverflowError,\n WorkingBlockReadOnlyError,\n WorkingBlockReplaceMismatchError,\n} from '../errors/index.js';\nimport { newMemoryId } from '../internal/id.js';\nimport { withMemorySpan } from '../internal/spans.js';\nimport type { MemoryStoreAdapter } from '../internal/storage-adapter.js';\n\n/**\n * Author-time block specification accepted by\n * {@link defineBlock} and {@link WorkingMemory.define}.\n *\n * @stable\n */\nexport interface BlockSpec {\n readonly label: string;\n readonly description?: string;\n readonly schema?: ZodLikeSchema<unknown>;\n /** Maximum length of the rendered value in characters. */\n readonly charLimit: number;\n /** Default `'internal'`. */\n readonly sensitivity?: Sensitivity;\n /** Default `false`. */\n readonly readOnly?: boolean;\n /**\n * Per-block default value. Applied on first definition only; later\n * runs preserve any value already in storage.\n */\n readonly defaultValue?: string;\n /** Default `'truncate'` — `'reject'` opt-in for strict use cases. */\n readonly overflowPolicy?: 'truncate' | 'reject';\n /** Optional free-form labels surfaced through `tags`. */\n readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * Frozen block definition returned by {@link defineBlock}. Re-used by\n * the agent runtime / context engine to know which blocks should be\n * compiled into the system prompt every step.\n *\n * @stable\n */\nexport interface BlockDefinition {\n readonly label: string;\n readonly description?: string;\n readonly schema?: ZodLikeSchema<unknown>;\n readonly charLimit: number;\n readonly sensitivity: Sensitivity;\n readonly readOnly: boolean;\n readonly defaultValue?: string;\n readonly overflowPolicy: 'truncate' | 'reject';\n readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * Build a frozen {@link BlockDefinition}. Surfaced as `blocks.define(...)`\n * for ergonomic call-sites; the underlying object is the same shape\n * the {@link WorkingMemory.define} method accepts.\n *\n * @stable\n */\nexport function defineBlock(spec: BlockSpec): BlockDefinition {\n if (!spec.label || spec.label.length === 0) {\n throw new TypeError('[graphorin/memory] BlockSpec.label must be a non-empty string.');\n }\n if (!Number.isInteger(spec.charLimit) || spec.charLimit <= 0) {\n throw new TypeError(\n `[graphorin/memory] BlockSpec.charLimit must be a positive integer, got ${String(spec.charLimit)}.`,\n );\n }\n return Object.freeze({\n label: spec.label,\n ...(spec.description !== undefined ? { description: spec.description } : {}),\n ...(spec.schema !== undefined ? { schema: spec.schema } : {}),\n charLimit: spec.charLimit,\n sensitivity: spec.sensitivity ?? 'internal',\n readOnly: spec.readOnly ?? false,\n ...(spec.defaultValue !== undefined ? { defaultValue: spec.defaultValue } : {}),\n overflowPolicy: spec.overflowPolicy ?? 'truncate',\n ...(spec.tags !== undefined ? { tags: Object.freeze([...spec.tags]) } : {}),\n });\n}\n\n/**\n * `WorkingMemory` — labeled, character-bounded blocks rendered into\n * every system prompt. Operations:\n *\n * - `define(spec)`: idempotently registers a block definition; the\n * block's row is created in storage on the next `write` call so\n * operators can change `description` between runs without\n * triggering a write.\n * - `read(scope, label)` / `list(scope)`: surface the current block\n * contents.\n * - `write(scope, label, value)`: full replace.\n * - `append(scope, label, content)`: append-with-newline.\n * - `replace(scope, label, oldUnique, newText)`: targeted replace\n * with a uniqueness check.\n * - `compile(scope)`: render the active blocks for the context\n * engine (used by Phase 10d).\n *\n * @stable\n */\nexport class WorkingMemory {\n readonly #store: MemoryStoreAdapter;\n readonly #tracer: Tracer;\n readonly #defs: Map<string, BlockDefinition>;\n\n constructor(args: { store: MemoryStoreAdapter; tracer: Tracer }) {\n this.#store = args.store;\n this.#tracer = args.tracer;\n this.#defs = new Map();\n }\n\n /** Register a block definition. Returns the same definition object. */\n define(definition: BlockDefinition): BlockDefinition {\n this.#defs.set(definition.label, definition);\n return definition;\n }\n\n /** Snapshot of every registered definition. */\n definitions(): ReadonlyArray<BlockDefinition> {\n return Array.from(this.#defs.values());\n }\n\n /** Lookup a definition by label. */\n definitionFor(label: string): BlockDefinition | undefined {\n return this.#defs.get(label);\n }\n\n /** List active (non-deleted) blocks for the supplied scope. */\n async list(scope: SessionScope): Promise<ReadonlyArray<Block>> {\n return withMemorySpan(this.#tracer, 'memory.read.working', scope, {}, async (span) => {\n const out = await this.#store.working.list(scope);\n span.setAttributes({ 'memory.read.working.count': out.length });\n return out;\n });\n }\n\n /** Read a single block's value (or `null` when absent). */\n async read(scope: SessionScope, label: string): Promise<string | null> {\n return withMemorySpan(\n this.#tracer,\n 'memory.read.working',\n scope,\n { 'memory.block.label': label },\n async (span) => {\n const block = await this.#store.working.get(scope, label);\n span.setAttributes({ 'memory.read.working.found': block !== null });\n if (block !== null) return block.value;\n // MST-8: a defined-but-unwritten block answers with its declared\n // defaultValue (previously advertised, copied into the\n // definition, and then never read by anything).\n const definition = this.#defs.get(label);\n return definition?.defaultValue ?? null;\n },\n );\n }\n\n /** Replace a block's value entirely. Honours overflow policy. */\n async write(scope: SessionScope, label: string, value: string): Promise<Block> {\n return this.#mutate(scope, label, async () => value);\n }\n\n /** Append `content` to a block (with a newline separator). */\n async append(scope: SessionScope, label: string, content: string): Promise<Block> {\n return this.#mutate(scope, label, async (current) => {\n if (current === '' || current === undefined) return content;\n return `${current}\\n${content}`;\n });\n }\n\n /**\n * Replace the unique substring `oldUnique` inside the block's value\n * with `newText`. Throws `WorkingBlockReplaceMismatchError` when\n * the substring is missing or appears more than once.\n */\n async replace(\n scope: SessionScope,\n label: string,\n oldUnique: string,\n newText: string,\n ): Promise<Block> {\n return this.#mutate(scope, label, async (current) => {\n const haystack = current ?? '';\n const occurrences = countOccurrences(haystack, oldUnique);\n if (occurrences !== 1) {\n throw new WorkingBlockReplaceMismatchError(label, occurrences);\n }\n return haystack.replace(oldUnique, newText);\n });\n }\n\n /** Run `mutator(current) => next` and persist the result. */\n async rethink(\n scope: SessionScope,\n label: string,\n mutator: (current: string) => string | Promise<string>,\n ): Promise<Block> {\n return this.#mutate(scope, label, async (current) => mutator(current ?? ''));\n }\n\n /** Soft-delete a block. */\n async forget(scope: SessionScope, label: string, reason?: string): Promise<void> {\n await withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n { 'memory.block.label': label, 'memory.write.working.action': 'forget' },\n async () => {\n await this.#store.working.delete(scope, label, reason);\n },\n );\n }\n\n /**\n * Attach a working block to an additional agent. Backed by the\n * adapter's `shared.attach(...)` join table so multi-agent crews\n * can share the same block without duplicating storage.\n */\n async attach(scope: SessionScope, blockId: string, agentId: string): Promise<void> {\n await withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n {\n 'memory.write.working.action': 'attach',\n 'memory.block.id': blockId,\n 'memory.write.working.target_agent_id': agentId,\n },\n async () => {\n await this.#store.shared.attach(blockId, agentId);\n },\n );\n }\n\n /** Detach a working block from an agent. */\n async detach(scope: SessionScope, blockId: string, agentId: string): Promise<void> {\n await withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n {\n 'memory.write.working.action': 'detach',\n 'memory.block.id': blockId,\n 'memory.write.working.target_agent_id': agentId,\n },\n async () => {\n await this.#store.shared.detach(blockId, agentId);\n },\n );\n }\n\n /**\n * Render a deterministic `<memory_blocks>` XML fragment for the\n * supplied scope. The full layered system prompt (six layers) is\n * produced by Phase 10d's ContextEngine; this method ships the\n * minimum-viable rendering used by the smoke acceptance criteria.\n *\n * The optional `agentId` argument is reserved for the per-agent\n * filtering Phase 10d wires through. In Phase 10a the argument is\n * accepted but ignored — the rendering is scope-wide.\n */\n async compile(scope: SessionScope, agentId?: string): Promise<string> {\n void agentId;\n const blocks = await this.list(scope);\n if (blocks.length === 0) return '';\n const lines = ['<memory_blocks>'];\n for (const block of blocks) {\n const description =\n block.description !== undefined ? ` description=\"${escapeXml(block.description)}\"` : '';\n lines.push(` <block label=\"${escapeXml(block.label)}\"${description}>`);\n lines.push(` ${escapeXml(block.value)}`);\n lines.push(' </block>');\n }\n lines.push('</memory_blocks>');\n return lines.join('\\n');\n }\n\n async #mutate(\n scope: SessionScope,\n label: string,\n nextValueFn: (current: string | undefined) => Promise<string>,\n ): Promise<Block> {\n return withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n { 'memory.block.label': label },\n async (span) => {\n const definition = this.#requireDefinition(label);\n if (definition.readOnly === true) {\n // MRET-14: a dedicated kind — the old\n // WorkingBlockReplaceMismatchError(label, 0) read as \"substring\n // matched 0 times\" and misled replace-retry callers.\n throw new WorkingBlockReadOnlyError(label);\n }\n const existing = await this.#store.working.get(scope, label);\n // MST-8: first materialization starts from the declared default,\n // so an append/replace on an unwritten block composes with it.\n const candidate = await nextValueFn(existing?.value ?? definition.defaultValue);\n const enforcedValue = enforceCharLimit(candidate, definition);\n const now = new Date().toISOString();\n const id = existing?.id ?? newMemoryId('block');\n const block: Block = {\n id,\n kind: 'working',\n userId: scope.userId,\n ...(scope.sessionId !== undefined ? { sessionId: scope.sessionId } : {}),\n ...(scope.agentId !== undefined ? { agentId: scope.agentId } : {}),\n sensitivity: definition.sensitivity,\n label,\n ...(definition.description !== undefined ? { description: definition.description } : {}),\n value: enforcedValue,\n charLimit: definition.charLimit,\n readOnly: definition.readOnly,\n ...(definition.tags !== undefined ? { tags: definition.tags } : {}),\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n };\n await this.#store.working.upsert(scope, block);\n span.setAttributes({\n 'memory.write.working.action': existing === null ? 'create' : 'update',\n 'memory.write.working.length': enforcedValue.length,\n });\n return block;\n },\n );\n }\n\n #requireDefinition(label: string): BlockDefinition {\n const def = this.#defs.get(label);\n if (def !== undefined) return def;\n throw new TypeError(\n `[graphorin/memory] working block '${label}' was not defined. ` +\n 'Call memory.working.define(blocks.define({...})) before writing to it.',\n );\n }\n}\n\nfunction enforceCharLimit(value: string, definition: BlockDefinition): string {\n if (value.length <= definition.charLimit) return value;\n if (definition.overflowPolicy === 'reject') {\n throw new WorkingBlockOverflowError(definition.label, value.length, definition.charLimit);\n }\n return value.slice(0, definition.charLimit);\n}\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (needle.length === 0) return 0;\n let count = 0;\n let idx = 0;\n for (;;) {\n const next = haystack.indexOf(needle, idx);\n if (next === -1) return count;\n count += 1;\n idx = next + needle.length;\n }\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"working-memory.js","names":["#store","#tracer","#defs","#mutate","#requireDefinition","block: Block"],"sources":["../../src/tiers/working-memory.ts"],"sourcesContent":["import type { Block, Sensitivity, SessionScope, Tracer, ZodLikeSchema } from '@graphorin/core';\nimport {\n WorkingBlockOverflowError,\n WorkingBlockReadOnlyError,\n WorkingBlockReplaceMismatchError,\n} from '../errors/index.js';\nimport { newMemoryId } from '../internal/id.js';\nimport { withMemorySpan } from '../internal/spans.js';\nimport type { MemoryStoreAdapter } from '../internal/storage-adapter.js';\n\n/**\n * Author-time block specification accepted by\n * {@link defineBlock} and {@link WorkingMemory.define}.\n *\n * @stable\n */\nexport interface BlockSpec {\n readonly label: string;\n readonly description?: string;\n readonly schema?: ZodLikeSchema<unknown>;\n /** Maximum length of the rendered value in characters. */\n readonly charLimit: number;\n /** Default `'internal'`. */\n readonly sensitivity?: Sensitivity;\n /** Default `false`. */\n readonly readOnly?: boolean;\n /**\n * Per-block default value. Applied on first definition only; later\n * runs preserve any value already in storage.\n */\n readonly defaultValue?: string;\n /** Default `'truncate'` - `'reject'` opt-in for strict use cases. */\n readonly overflowPolicy?: 'truncate' | 'reject';\n /** Optional free-form labels surfaced through `tags`. */\n readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * Frozen block definition returned by {@link defineBlock}. Re-used by\n * the agent runtime / context engine to know which blocks should be\n * compiled into the system prompt every step.\n *\n * @stable\n */\nexport interface BlockDefinition {\n readonly label: string;\n readonly description?: string;\n readonly schema?: ZodLikeSchema<unknown>;\n readonly charLimit: number;\n readonly sensitivity: Sensitivity;\n readonly readOnly: boolean;\n readonly defaultValue?: string;\n readonly overflowPolicy: 'truncate' | 'reject';\n readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * Build a frozen {@link BlockDefinition}. Surfaced as `blocks.define(...)`\n * for ergonomic call-sites; the underlying object is the same shape\n * the {@link WorkingMemory.define} method accepts.\n *\n * @stable\n */\nexport function defineBlock(spec: BlockSpec): BlockDefinition {\n if (!spec.label || spec.label.length === 0) {\n throw new TypeError('[graphorin/memory] BlockSpec.label must be a non-empty string.');\n }\n if (!Number.isInteger(spec.charLimit) || spec.charLimit <= 0) {\n throw new TypeError(\n `[graphorin/memory] BlockSpec.charLimit must be a positive integer, got ${String(spec.charLimit)}.`,\n );\n }\n return Object.freeze({\n label: spec.label,\n ...(spec.description !== undefined ? { description: spec.description } : {}),\n ...(spec.schema !== undefined ? { schema: spec.schema } : {}),\n charLimit: spec.charLimit,\n sensitivity: spec.sensitivity ?? 'internal',\n readOnly: spec.readOnly ?? false,\n ...(spec.defaultValue !== undefined ? { defaultValue: spec.defaultValue } : {}),\n overflowPolicy: spec.overflowPolicy ?? 'truncate',\n ...(spec.tags !== undefined ? { tags: Object.freeze([...spec.tags]) } : {}),\n });\n}\n\n/**\n * `WorkingMemory` - labeled, character-bounded blocks rendered into\n * every system prompt. Operations:\n *\n * - `define(spec)`: idempotently registers a block definition; the\n * block's row is created in storage on the next `write` call so\n * operators can change `description` between runs without\n * triggering a write.\n * - `read(scope, label)` / `list(scope)`: surface the current block\n * contents.\n * - `write(scope, label, value)`: full replace.\n * - `append(scope, label, content)`: append-with-newline.\n * - `replace(scope, label, oldUnique, newText)`: targeted replace\n * with a uniqueness check.\n * - `compile(scope)`: render the active blocks for the context\n * engine (used by Phase 10d).\n *\n * @stable\n */\nexport class WorkingMemory {\n readonly #store: MemoryStoreAdapter;\n readonly #tracer: Tracer;\n readonly #defs: Map<string, BlockDefinition>;\n\n constructor(args: { store: MemoryStoreAdapter; tracer: Tracer }) {\n this.#store = args.store;\n this.#tracer = args.tracer;\n this.#defs = new Map();\n }\n\n /** Register a block definition. Returns the same definition object. */\n define(definition: BlockDefinition): BlockDefinition {\n this.#defs.set(definition.label, definition);\n return definition;\n }\n\n /** Snapshot of every registered definition. */\n definitions(): ReadonlyArray<BlockDefinition> {\n return Array.from(this.#defs.values());\n }\n\n /** Lookup a definition by label. */\n definitionFor(label: string): BlockDefinition | undefined {\n return this.#defs.get(label);\n }\n\n /** List active (non-deleted) blocks for the supplied scope. */\n async list(scope: SessionScope): Promise<ReadonlyArray<Block>> {\n return withMemorySpan(this.#tracer, 'memory.read.working', scope, {}, async (span) => {\n const out = await this.#store.working.list(scope);\n span.setAttributes({ 'memory.read.working.count': out.length });\n return out;\n });\n }\n\n /** Read a single block's value (or `null` when absent). */\n async read(scope: SessionScope, label: string): Promise<string | null> {\n return withMemorySpan(\n this.#tracer,\n 'memory.read.working',\n scope,\n { 'memory.block.label': label },\n async (span) => {\n const block = await this.#store.working.get(scope, label);\n span.setAttributes({ 'memory.read.working.found': block !== null });\n if (block !== null) return block.value;\n // MST-8: a defined-but-unwritten block answers with its declared\n // defaultValue (previously advertised, copied into the\n // definition, and then never read by anything).\n const definition = this.#defs.get(label);\n return definition?.defaultValue ?? null;\n },\n );\n }\n\n /** Replace a block's value entirely. Honours overflow policy. */\n async write(scope: SessionScope, label: string, value: string): Promise<Block> {\n return this.#mutate(scope, label, async () => value);\n }\n\n /** Append `content` to a block (with a newline separator). */\n async append(scope: SessionScope, label: string, content: string): Promise<Block> {\n return this.#mutate(scope, label, async (current) => {\n if (current === '' || current === undefined) return content;\n return `${current}\\n${content}`;\n });\n }\n\n /**\n * Replace the unique substring `oldUnique` inside the block's value\n * with `newText`. Throws `WorkingBlockReplaceMismatchError` when\n * the substring is missing or appears more than once.\n */\n async replace(\n scope: SessionScope,\n label: string,\n oldUnique: string,\n newText: string,\n ): Promise<Block> {\n return this.#mutate(scope, label, async (current) => {\n const haystack = current ?? '';\n const occurrences = countOccurrences(haystack, oldUnique);\n if (occurrences !== 1) {\n throw new WorkingBlockReplaceMismatchError(label, occurrences);\n }\n return haystack.replace(oldUnique, newText);\n });\n }\n\n /** Run `mutator(current) => next` and persist the result. */\n async rethink(\n scope: SessionScope,\n label: string,\n mutator: (current: string) => string | Promise<string>,\n ): Promise<Block> {\n return this.#mutate(scope, label, async (current) => mutator(current ?? ''));\n }\n\n /** Soft-delete a block. */\n async forget(scope: SessionScope, label: string, reason?: string): Promise<void> {\n await withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n { 'memory.block.label': label, 'memory.write.working.action': 'forget' },\n async () => {\n await this.#store.working.delete(scope, label, reason);\n },\n );\n }\n\n /**\n * Attach a working block to an additional agent. Backed by the\n * adapter's `shared.attach(...)` join table so multi-agent crews\n * can share the same block without duplicating storage.\n */\n async attach(scope: SessionScope, blockId: string, agentId: string): Promise<void> {\n await withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n {\n 'memory.write.working.action': 'attach',\n 'memory.block.id': blockId,\n 'memory.write.working.target_agent_id': agentId,\n },\n async () => {\n await this.#store.shared.attach(blockId, agentId);\n },\n );\n }\n\n /** Detach a working block from an agent. */\n async detach(scope: SessionScope, blockId: string, agentId: string): Promise<void> {\n await withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n {\n 'memory.write.working.action': 'detach',\n 'memory.block.id': blockId,\n 'memory.write.working.target_agent_id': agentId,\n },\n async () => {\n await this.#store.shared.detach(blockId, agentId);\n },\n );\n }\n\n /**\n * Render a deterministic `<memory_blocks>` XML fragment for the\n * supplied scope. The full layered system prompt (six layers) is\n * produced by Phase 10d's ContextEngine; this method ships the\n * minimum-viable rendering used by the smoke acceptance criteria.\n *\n * The optional `agentId` argument is reserved for the per-agent\n * filtering Phase 10d wires through. In Phase 10a the argument is\n * accepted but ignored - the rendering is scope-wide.\n */\n async compile(scope: SessionScope, agentId?: string): Promise<string> {\n void agentId;\n const blocks = await this.list(scope);\n if (blocks.length === 0) return '';\n const lines = ['<memory_blocks>'];\n for (const block of blocks) {\n const description =\n block.description !== undefined ? ` description=\"${escapeXml(block.description)}\"` : '';\n lines.push(` <block label=\"${escapeXml(block.label)}\"${description}>`);\n lines.push(` ${escapeXml(block.value)}`);\n lines.push(' </block>');\n }\n lines.push('</memory_blocks>');\n return lines.join('\\n');\n }\n\n async #mutate(\n scope: SessionScope,\n label: string,\n nextValueFn: (current: string | undefined) => Promise<string>,\n ): Promise<Block> {\n return withMemorySpan(\n this.#tracer,\n 'memory.write.working',\n scope,\n { 'memory.block.label': label },\n async (span) => {\n const definition = this.#requireDefinition(label);\n if (definition.readOnly === true) {\n // MRET-14: a dedicated kind - the old\n // WorkingBlockReplaceMismatchError(label, 0) read as \"substring\n // matched 0 times\" and misled replace-retry callers.\n throw new WorkingBlockReadOnlyError(label);\n }\n const existing = await this.#store.working.get(scope, label);\n // MST-8: first materialization starts from the declared default,\n // so an append/replace on an unwritten block composes with it.\n const candidate = await nextValueFn(existing?.value ?? definition.defaultValue);\n const enforcedValue = enforceCharLimit(candidate, definition);\n const now = new Date().toISOString();\n const id = existing?.id ?? newMemoryId('block');\n const block: Block = {\n id,\n kind: 'working',\n userId: scope.userId,\n ...(scope.sessionId !== undefined ? { sessionId: scope.sessionId } : {}),\n ...(scope.agentId !== undefined ? { agentId: scope.agentId } : {}),\n sensitivity: definition.sensitivity,\n label,\n ...(definition.description !== undefined ? { description: definition.description } : {}),\n value: enforcedValue,\n charLimit: definition.charLimit,\n readOnly: definition.readOnly,\n ...(definition.tags !== undefined ? { tags: definition.tags } : {}),\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n };\n await this.#store.working.upsert(scope, block);\n span.setAttributes({\n 'memory.write.working.action': existing === null ? 'create' : 'update',\n 'memory.write.working.length': enforcedValue.length,\n });\n return block;\n },\n );\n }\n\n #requireDefinition(label: string): BlockDefinition {\n const def = this.#defs.get(label);\n if (def !== undefined) return def;\n throw new TypeError(\n `[graphorin/memory] working block '${label}' was not defined. ` +\n 'Call memory.working.define(blocks.define({...})) before writing to it.',\n );\n }\n}\n\nfunction enforceCharLimit(value: string, definition: BlockDefinition): string {\n if (value.length <= definition.charLimit) return value;\n if (definition.overflowPolicy === 'reject') {\n throw new WorkingBlockOverflowError(definition.label, value.length, definition.charLimit);\n }\n return value.slice(0, definition.charLimit);\n}\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (needle.length === 0) return 0;\n let count = 0;\n let idx = 0;\n for (;;) {\n const next = haystack.indexOf(needle, idx);\n if (next === -1) return count;\n count += 1;\n idx = next + needle.length;\n }\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n"],"mappings":"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"}
|
|
@@ -73,14 +73,14 @@ declare const blockRethinkOutputSchema: z.ZodObject<{
|
|
|
73
73
|
type BlockRethinkInput = z.infer<typeof blockRethinkInputSchema>;
|
|
74
74
|
type BlockRethinkOutput = z.infer<typeof blockRethinkOutputSchema>;
|
|
75
75
|
/**
|
|
76
|
-
* `block_append`
|
|
76
|
+
* `block_append` - append text (with a newline separator) to a working
|
|
77
77
|
* memory block.
|
|
78
78
|
*
|
|
79
79
|
* @stable
|
|
80
80
|
*/
|
|
81
81
|
declare function createBlockAppendTool(deps: MemoryToolDeps): Tool<BlockAppendInput, BlockAppendOutput>;
|
|
82
82
|
/**
|
|
83
|
-
* `block_replace`
|
|
83
|
+
* `block_replace` - replace a unique substring inside a working
|
|
84
84
|
* memory block. Throws when the substring is missing or appears more
|
|
85
85
|
* than once.
|
|
86
86
|
*
|
|
@@ -88,7 +88,7 @@ declare function createBlockAppendTool(deps: MemoryToolDeps): Tool<BlockAppendIn
|
|
|
88
88
|
*/
|
|
89
89
|
declare function createBlockReplaceTool(deps: MemoryToolDeps): Tool<BlockReplaceInput, BlockReplaceOutput>;
|
|
90
90
|
/**
|
|
91
|
-
* `block_rethink`
|
|
91
|
+
* `block_rethink` - rewrite a working memory block from scratch.
|
|
92
92
|
*
|
|
93
93
|
* @stable
|
|
94
94
|
*/
|
|
@@ -28,7 +28,7 @@ const blockRethinkOutputSchema = z.object({
|
|
|
28
28
|
length: z.number()
|
|
29
29
|
});
|
|
30
30
|
/**
|
|
31
|
-
* `block_append`
|
|
31
|
+
* `block_append` - append text (with a newline separator) to a working
|
|
32
32
|
* memory block.
|
|
33
33
|
*
|
|
34
34
|
* @stable
|
|
@@ -55,7 +55,7 @@ function createBlockAppendTool(deps) {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
* `block_replace`
|
|
58
|
+
* `block_replace` - replace a unique substring inside a working
|
|
59
59
|
* memory block. Throws when the substring is missing or appears more
|
|
60
60
|
* than once.
|
|
61
61
|
*
|
|
@@ -83,7 +83,7 @@ function createBlockReplaceTool(deps) {
|
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
|
-
* `block_rethink`
|
|
86
|
+
* `block_rethink` - rewrite a working memory block from scratch.
|
|
87
87
|
*
|
|
88
88
|
* @stable
|
|
89
89
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-tools.js","names":[],"sources":["../../src/tools/block-tools.ts"],"sourcesContent":["import type { Tool } from '@graphorin/core';\nimport { tool } from '@graphorin/tools';\nimport { z } from 'zod';\nimport type { MemoryToolDeps } from './types.js';\n\nconst blockAppendInputSchema = z.object({\n label: z.string().min(1).max(128),\n content: z.string().min(1),\n});\nconst blockAppendOutputSchema = z.object({\n label: z.string(),\n length: z.number(),\n});\n\ntype BlockAppendInput = z.infer<typeof blockAppendInputSchema>;\ntype BlockAppendOutput = z.infer<typeof blockAppendOutputSchema>;\n\nconst blockReplaceInputSchema = z.object({\n label: z.string().min(1).max(128),\n oldUnique: z.string().min(1),\n newText: z.string(),\n});\nconst blockReplaceOutputSchema = z.object({\n label: z.string(),\n length: z.number(),\n});\n\ntype BlockReplaceInput = z.infer<typeof blockReplaceInputSchema>;\ntype BlockReplaceOutput = z.infer<typeof blockReplaceOutputSchema>;\n\nconst blockRethinkInputSchema = z.object({\n label: z.string().min(1).max(128),\n newValue: z.string(),\n});\nconst blockRethinkOutputSchema = z.object({\n label: z.string(),\n length: z.number(),\n});\n\ntype BlockRethinkInput = z.infer<typeof blockRethinkInputSchema>;\ntype BlockRethinkOutput = z.infer<typeof blockRethinkOutputSchema>;\n\n/**\n * `block_append`
|
|
1
|
+
{"version":3,"file":"block-tools.js","names":[],"sources":["../../src/tools/block-tools.ts"],"sourcesContent":["import type { Tool } from '@graphorin/core';\nimport { tool } from '@graphorin/tools';\nimport { z } from 'zod';\nimport type { MemoryToolDeps } from './types.js';\n\nconst blockAppendInputSchema = z.object({\n label: z.string().min(1).max(128),\n content: z.string().min(1),\n});\nconst blockAppendOutputSchema = z.object({\n label: z.string(),\n length: z.number(),\n});\n\ntype BlockAppendInput = z.infer<typeof blockAppendInputSchema>;\ntype BlockAppendOutput = z.infer<typeof blockAppendOutputSchema>;\n\nconst blockReplaceInputSchema = z.object({\n label: z.string().min(1).max(128),\n oldUnique: z.string().min(1),\n newText: z.string(),\n});\nconst blockReplaceOutputSchema = z.object({\n label: z.string(),\n length: z.number(),\n});\n\ntype BlockReplaceInput = z.infer<typeof blockReplaceInputSchema>;\ntype BlockReplaceOutput = z.infer<typeof blockReplaceOutputSchema>;\n\nconst blockRethinkInputSchema = z.object({\n label: z.string().min(1).max(128),\n newValue: z.string(),\n});\nconst blockRethinkOutputSchema = z.object({\n label: z.string(),\n length: z.number(),\n});\n\ntype BlockRethinkInput = z.infer<typeof blockRethinkInputSchema>;\ntype BlockRethinkOutput = z.infer<typeof blockRethinkOutputSchema>;\n\n/**\n * `block_append` - append text (with a newline separator) to a working\n * memory block.\n *\n * @stable\n */\nexport function createBlockAppendTool(\n deps: MemoryToolDeps,\n): Tool<BlockAppendInput, BlockAppendOutput> {\n return tool<BlockAppendInput, BlockAppendOutput>({\n name: 'block_append',\n description:\n 'Append text to a working memory block. The block is identified by its label (registered via memory.working.define(...)). Use this when accumulating notes, observations, or reasoning steps that should persist across turns.',\n inputSchema: blockAppendInputSchema,\n outputSchema: blockAppendOutputSchema,\n sideEffectClass: 'side-effecting',\n sandboxPolicy: 'none',\n sensitivity: 'internal',\n memoryGuardTier: 'memory-aware',\n tags: ['memory', 'working'],\n async execute(input, ctx) {\n const scope = await deps.resolveScope(ctx);\n const block = await deps.working.append(scope, input.label, input.content);\n return { label: block.label, length: block.value.length };\n },\n });\n}\n\n/**\n * `block_replace` - replace a unique substring inside a working\n * memory block. Throws when the substring is missing or appears more\n * than once.\n *\n * @stable\n */\nexport function createBlockReplaceTool(\n deps: MemoryToolDeps,\n): Tool<BlockReplaceInput, BlockReplaceOutput> {\n return tool<BlockReplaceInput, BlockReplaceOutput>({\n name: 'block_replace',\n description:\n 'Replace a UNIQUE substring inside a working memory block. The substring must appear exactly once; the call fails fast if missing or non-unique. Use block_rethink for full rewrites.',\n inputSchema: blockReplaceInputSchema,\n outputSchema: blockReplaceOutputSchema,\n sideEffectClass: 'side-effecting',\n sandboxPolicy: 'none',\n sensitivity: 'internal',\n memoryGuardTier: 'memory-aware',\n tags: ['memory', 'working'],\n async execute(input, ctx) {\n const scope = await deps.resolveScope(ctx);\n const block = await deps.working.replace(scope, input.label, input.oldUnique, input.newText);\n return { label: block.label, length: block.value.length };\n },\n });\n}\n\n/**\n * `block_rethink` - rewrite a working memory block from scratch.\n *\n * @stable\n */\nexport function createBlockRethinkTool(\n deps: MemoryToolDeps,\n): Tool<BlockRethinkInput, BlockRethinkOutput> {\n return tool<BlockRethinkInput, BlockRethinkOutput>({\n name: 'block_rethink',\n description:\n \"Replace a working memory block's value entirely. Use this when restructuring or summarising the block's contents. For surgical edits, prefer block_replace.\",\n inputSchema: blockRethinkInputSchema,\n outputSchema: blockRethinkOutputSchema,\n sideEffectClass: 'side-effecting',\n sandboxPolicy: 'none',\n sensitivity: 'internal',\n memoryGuardTier: 'memory-aware',\n tags: ['memory', 'working'],\n async execute(input, ctx) {\n const scope = await deps.resolveScope(ctx);\n const block = await deps.working.rethink(scope, input.label, () => input.newValue);\n return { label: block.label, length: block.value.length };\n },\n });\n}\n"],"mappings":";;;;AAKA,MAAM,yBAAyB,EAAE,OAAO;CACtC,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CACjC,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC3B,CAAC;AACF,MAAM,0BAA0B,EAAE,OAAO;CACvC,OAAO,EAAE,QAAQ;CACjB,QAAQ,EAAE,QAAQ;CACnB,CAAC;AAKF,MAAM,0BAA0B,EAAE,OAAO;CACvC,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CACjC,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC5B,SAAS,EAAE,QAAQ;CACpB,CAAC;AACF,MAAM,2BAA2B,EAAE,OAAO;CACxC,OAAO,EAAE,QAAQ;CACjB,QAAQ,EAAE,QAAQ;CACnB,CAAC;AAKF,MAAM,0BAA0B,EAAE,OAAO;CACvC,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CACjC,UAAU,EAAE,QAAQ;CACrB,CAAC;AACF,MAAM,2BAA2B,EAAE,OAAO;CACxC,OAAO,EAAE,QAAQ;CACjB,QAAQ,EAAE,QAAQ;CACnB,CAAC;;;;;;;AAWF,SAAgB,sBACd,MAC2C;AAC3C,QAAO,KAA0C;EAC/C,MAAM;EACN,aACE;EACF,aAAa;EACb,cAAc;EACd,iBAAiB;EACjB,eAAe;EACf,aAAa;EACb,iBAAiB;EACjB,MAAM,CAAC,UAAU,UAAU;EAC3B,MAAM,QAAQ,OAAO,KAAK;GACxB,MAAM,QAAQ,MAAM,KAAK,aAAa,IAAI;GAC1C,MAAM,QAAQ,MAAM,KAAK,QAAQ,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ;AAC1E,UAAO;IAAE,OAAO,MAAM;IAAO,QAAQ,MAAM,MAAM;IAAQ;;EAE5D,CAAC;;;;;;;;;AAUJ,SAAgB,uBACd,MAC6C;AAC7C,QAAO,KAA4C;EACjD,MAAM;EACN,aACE;EACF,aAAa;EACb,cAAc;EACd,iBAAiB;EACjB,eAAe;EACf,aAAa;EACb,iBAAiB;EACjB,MAAM,CAAC,UAAU,UAAU;EAC3B,MAAM,QAAQ,OAAO,KAAK;GACxB,MAAM,QAAQ,MAAM,KAAK,aAAa,IAAI;GAC1C,MAAM,QAAQ,MAAM,KAAK,QAAQ,QAAQ,OAAO,MAAM,OAAO,MAAM,WAAW,MAAM,QAAQ;AAC5F,UAAO;IAAE,OAAO,MAAM;IAAO,QAAQ,MAAM,MAAM;IAAQ;;EAE5D,CAAC;;;;;;;AAQJ,SAAgB,uBACd,MAC6C;AAC7C,QAAO,KAA4C;EACjD,MAAM;EACN,aACE;EACF,aAAa;EACb,cAAc;EACd,iBAAiB;EACjB,eAAe;EACf,aAAa;EACb,iBAAiB;EACjB,MAAM,CAAC,UAAU,UAAU;EAC3B,MAAM,QAAQ,OAAO,KAAK;GACxB,MAAM,QAAQ,MAAM,KAAK,aAAa,IAAI;GAC1C,MAAM,QAAQ,MAAM,KAAK,QAAQ,QAAQ,OAAO,MAAM,aAAa,MAAM,SAAS;AAClF,UAAO;IAAE,OAAO,MAAM;IAAO,QAAQ,MAAM,MAAM;IAAQ;;EAE5D,CAAC"}
|
|
@@ -12,16 +12,16 @@ declare const factRememberInputSchema: z.ZodObject<{
|
|
|
12
12
|
validTo: z.ZodOptional<z.ZodString>;
|
|
13
13
|
}, "strip", z.ZodTypeAny, {
|
|
14
14
|
text: string;
|
|
15
|
-
sensitivity?: "public" | "internal" | "secret" | undefined;
|
|
16
15
|
tags?: string[] | undefined;
|
|
17
16
|
confidence?: number | undefined;
|
|
17
|
+
sensitivity?: "public" | "internal" | "secret" | undefined;
|
|
18
18
|
validFrom?: string | undefined;
|
|
19
19
|
validTo?: string | undefined;
|
|
20
20
|
}, {
|
|
21
21
|
text: string;
|
|
22
|
-
sensitivity?: "public" | "internal" | "secret" | undefined;
|
|
23
22
|
tags?: string[] | undefined;
|
|
24
23
|
confidence?: number | undefined;
|
|
24
|
+
sensitivity?: "public" | "internal" | "secret" | undefined;
|
|
25
25
|
validFrom?: string | undefined;
|
|
26
26
|
validTo?: string | undefined;
|
|
27
27
|
}>;
|
|
@@ -54,13 +54,13 @@ declare const factSearchInputSchema: z.ZodObject<{
|
|
|
54
54
|
}, "strip", z.ZodTypeAny, {
|
|
55
55
|
query: string;
|
|
56
56
|
topK?: number | undefined;
|
|
57
|
-
asOf?: string | undefined;
|
|
58
57
|
tags?: string[] | undefined;
|
|
58
|
+
asOf?: string | undefined;
|
|
59
59
|
}, {
|
|
60
60
|
query: string;
|
|
61
61
|
topK?: number | undefined;
|
|
62
|
-
asOf?: string | undefined;
|
|
63
62
|
tags?: string[] | undefined;
|
|
63
|
+
asOf?: string | undefined;
|
|
64
64
|
}>;
|
|
65
65
|
declare const factSearchOutputSchema: z.ZodObject<{
|
|
66
66
|
hits: z.ZodArray<z.ZodObject<{
|
|
@@ -69,34 +69,50 @@ declare const factSearchOutputSchema: z.ZodObject<{
|
|
|
69
69
|
score: z.ZodNumber;
|
|
70
70
|
sensitivity: z.ZodEnum<["public", "internal", "secret"]>;
|
|
71
71
|
provenance: z.ZodOptional<z.ZodEnum<["user", "tool", "extraction", "reflection", "induction", "imported"]>>;
|
|
72
|
+
/**
|
|
73
|
+
* Set when the fact's validity interval was closed (superseded /
|
|
74
|
+
* expired). Only present on `asOf` reads - default reads exclude
|
|
75
|
+
* such facts entirely (memory-retrieval-01).
|
|
76
|
+
*/
|
|
77
|
+
validTo: z.ZodOptional<z.ZodString>;
|
|
78
|
+
/** Id of the fact that superseded this one, when any. */
|
|
79
|
+
supersededBy: z.ZodOptional<z.ZodString>;
|
|
72
80
|
}, "strip", z.ZodTypeAny, {
|
|
73
|
-
score: number;
|
|
74
|
-
factId: string;
|
|
75
81
|
text: string;
|
|
82
|
+
score: number;
|
|
76
83
|
sensitivity: "public" | "internal" | "secret";
|
|
84
|
+
factId: string;
|
|
85
|
+
validTo?: string | undefined;
|
|
77
86
|
provenance?: "user" | "tool" | "extraction" | "reflection" | "induction" | "imported" | undefined;
|
|
87
|
+
supersededBy?: string | undefined;
|
|
78
88
|
}, {
|
|
79
|
-
score: number;
|
|
80
|
-
factId: string;
|
|
81
89
|
text: string;
|
|
90
|
+
score: number;
|
|
82
91
|
sensitivity: "public" | "internal" | "secret";
|
|
92
|
+
factId: string;
|
|
93
|
+
validTo?: string | undefined;
|
|
83
94
|
provenance?: "user" | "tool" | "extraction" | "reflection" | "induction" | "imported" | undefined;
|
|
95
|
+
supersededBy?: string | undefined;
|
|
84
96
|
}>, "many">;
|
|
85
97
|
}, "strip", z.ZodTypeAny, {
|
|
86
98
|
hits: {
|
|
87
|
-
score: number;
|
|
88
|
-
factId: string;
|
|
89
99
|
text: string;
|
|
100
|
+
score: number;
|
|
90
101
|
sensitivity: "public" | "internal" | "secret";
|
|
102
|
+
factId: string;
|
|
103
|
+
validTo?: string | undefined;
|
|
91
104
|
provenance?: "user" | "tool" | "extraction" | "reflection" | "induction" | "imported" | undefined;
|
|
105
|
+
supersededBy?: string | undefined;
|
|
92
106
|
}[];
|
|
93
107
|
}, {
|
|
94
108
|
hits: {
|
|
95
|
-
score: number;
|
|
96
|
-
factId: string;
|
|
97
109
|
text: string;
|
|
110
|
+
score: number;
|
|
98
111
|
sensitivity: "public" | "internal" | "secret";
|
|
112
|
+
factId: string;
|
|
113
|
+
validTo?: string | undefined;
|
|
99
114
|
provenance?: "user" | "tool" | "extraction" | "reflection" | "induction" | "imported" | undefined;
|
|
115
|
+
supersededBy?: string | undefined;
|
|
100
116
|
}[];
|
|
101
117
|
}>;
|
|
102
118
|
type FactSearchInput = z.infer<typeof factSearchInputSchema>;
|
|
@@ -165,41 +181,41 @@ declare const factHistoryOutputSchema: z.ZodObject<{
|
|
|
165
181
|
supersededBy: z.ZodOptional<z.ZodString>;
|
|
166
182
|
sensitivity: z.ZodEnum<["public", "internal", "secret"]>;
|
|
167
183
|
}, "strip", z.ZodTypeAny, {
|
|
168
|
-
factId: string;
|
|
169
184
|
text: string;
|
|
170
185
|
sensitivity: "public" | "internal" | "secret";
|
|
186
|
+
factId: string;
|
|
171
187
|
validFrom?: string | undefined;
|
|
172
188
|
validTo?: string | undefined;
|
|
173
|
-
supersedes?: string | undefined;
|
|
174
189
|
supersededBy?: string | undefined;
|
|
190
|
+
supersedes?: string | undefined;
|
|
175
191
|
}, {
|
|
176
|
-
factId: string;
|
|
177
192
|
text: string;
|
|
178
193
|
sensitivity: "public" | "internal" | "secret";
|
|
194
|
+
factId: string;
|
|
179
195
|
validFrom?: string | undefined;
|
|
180
196
|
validTo?: string | undefined;
|
|
181
|
-
supersedes?: string | undefined;
|
|
182
197
|
supersededBy?: string | undefined;
|
|
198
|
+
supersedes?: string | undefined;
|
|
183
199
|
}>, "many">;
|
|
184
200
|
}, "strip", z.ZodTypeAny, {
|
|
185
201
|
chain: {
|
|
186
|
-
factId: string;
|
|
187
202
|
text: string;
|
|
188
203
|
sensitivity: "public" | "internal" | "secret";
|
|
204
|
+
factId: string;
|
|
189
205
|
validFrom?: string | undefined;
|
|
190
206
|
validTo?: string | undefined;
|
|
191
|
-
supersedes?: string | undefined;
|
|
192
207
|
supersededBy?: string | undefined;
|
|
208
|
+
supersedes?: string | undefined;
|
|
193
209
|
}[];
|
|
194
210
|
}, {
|
|
195
211
|
chain: {
|
|
196
|
-
factId: string;
|
|
197
212
|
text: string;
|
|
198
213
|
sensitivity: "public" | "internal" | "secret";
|
|
214
|
+
factId: string;
|
|
199
215
|
validFrom?: string | undefined;
|
|
200
216
|
validTo?: string | undefined;
|
|
201
|
-
supersedes?: string | undefined;
|
|
202
217
|
supersededBy?: string | undefined;
|
|
218
|
+
supersedes?: string | undefined;
|
|
203
219
|
}[];
|
|
204
220
|
}>;
|
|
205
221
|
type FactHistoryInput = z.infer<typeof factHistoryInputSchema>;
|
|
@@ -227,7 +243,7 @@ declare const factValidateOutputSchema: z.ZodObject<{
|
|
|
227
243
|
type FactValidateInput = z.infer<typeof factValidateInputSchema>;
|
|
228
244
|
type FactValidateOutput = z.infer<typeof factValidateOutputSchema>;
|
|
229
245
|
/**
|
|
230
|
-
* `fact_remember`
|
|
246
|
+
* `fact_remember` - persist a single semantic fact. The minimum-viable
|
|
231
247
|
* pipeline writes the fact straight through with MD5 deduplication;
|
|
232
248
|
* Phase 10b extends the body with the multi-stage conflict resolution.
|
|
233
249
|
*
|
|
@@ -235,29 +251,30 @@ type FactValidateOutput = z.infer<typeof factValidateOutputSchema>;
|
|
|
235
251
|
*/
|
|
236
252
|
declare function createFactRememberTool(deps: MemoryToolDeps): Tool<FactRememberInput, FactRememberOutput>;
|
|
237
253
|
/**
|
|
238
|
-
* `fact_search`
|
|
254
|
+
* `fact_search` - hybrid (vector + FTS5) search over the user's
|
|
239
255
|
* semantic memory. Results merged through the configured reranker.
|
|
240
256
|
*
|
|
241
257
|
* @stable
|
|
242
258
|
*/
|
|
243
259
|
declare function createFactSearchTool(deps: MemoryToolDeps): Tool<FactSearchInput, FactSearchOutput>;
|
|
244
260
|
/**
|
|
245
|
-
* `fact_supersede`
|
|
246
|
-
* that replaces it. The old fact is kept for replay but
|
|
247
|
-
*
|
|
261
|
+
* `fact_supersede` - soft-supersede an old fact by storing a new one
|
|
262
|
+
* that replaces it. The old fact is kept for replay but no longer
|
|
263
|
+
* surfaced by default reads (they evaluate validity at NOW); it stays
|
|
264
|
+
* reachable via `asOf` / inspector paths.
|
|
248
265
|
*
|
|
249
266
|
* @stable
|
|
250
267
|
*/
|
|
251
268
|
declare function createFactSupersedeTool(deps: MemoryToolDeps): Tool<FactSupersedeInput, FactSupersedeOutput>;
|
|
252
269
|
/**
|
|
253
|
-
* `fact_forget`
|
|
270
|
+
* `fact_forget` - soft-delete a fact (kept for replay; never hard-
|
|
254
271
|
* deleted at this layer).
|
|
255
272
|
*
|
|
256
273
|
* @stable
|
|
257
274
|
*/
|
|
258
275
|
declare function createFactForgetTool(deps: MemoryToolDeps): Tool<FactForgetInput, FactForgetOutput>;
|
|
259
276
|
/**
|
|
260
|
-
* `fact_history`
|
|
277
|
+
* `fact_history` - trace how a fact changed over time. Returns the
|
|
261
278
|
* full bi-temporal supersede chain the given fact belongs to, oldest →
|
|
262
279
|
* newest, including superseded entries, so the agent can answer "what
|
|
263
280
|
* did the user say before" / "how did this change". Read-only. P0-2.
|
|
@@ -266,20 +283,20 @@ declare function createFactForgetTool(deps: MemoryToolDeps): Tool<FactForgetInpu
|
|
|
266
283
|
*/
|
|
267
284
|
declare function createFactHistoryTool(deps: MemoryToolDeps): Tool<FactHistoryInput, FactHistoryOutput>;
|
|
268
285
|
/**
|
|
269
|
-
* `fact_validate`
|
|
286
|
+
* `fact_validate` - promote a quarantined fact to active (P1-4). The
|
|
270
287
|
* validation path that admits a synthesized (consolidator / reflection)
|
|
271
288
|
* memory into action-driving recall once it has been reviewed; the
|
|
272
289
|
* promotion is audited in `memory_history`.
|
|
273
290
|
*
|
|
274
|
-
* MRET-3 / MST-1
|
|
291
|
+
* MRET-3 / MST-1 - two gates close the one-turn memory-poisoning chain
|
|
275
292
|
* (`fact_remember(poison)` → `fact_validate(id)` → active recall):
|
|
276
293
|
*
|
|
277
|
-
* 1. `needsApproval: true`
|
|
294
|
+
* 1. `needsApproval: true` - the run suspends for a human decision
|
|
278
295
|
* before this tool ever executes, so the agent cannot silently
|
|
279
296
|
* promote any quarantined fact.
|
|
280
297
|
* 2. The underlying `SemanticMemory.validate(...)` re-checks the fact's
|
|
281
298
|
* text against the injection heuristics and **refuses** (no `force`
|
|
282
|
-
* is passed here)
|
|
299
|
+
* is passed here) - an injection-flagged memory cannot be promoted by
|
|
283
300
|
* the agent at all. Only an operator, via the programmatic API with
|
|
284
301
|
* `{ force: true }`, can override after review.
|
|
285
302
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fact-tools.d.ts","names":[],"sources":["../../src/tools/fact-tools.ts"],"sourcesContent":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"fact-tools.d.ts","names":[],"sources":["../../src/tools/fact-tools.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/tools/fact-tools.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { recallTaint } from "./taint.js";
|
|
1
2
|
import { tool } from "@graphorin/tools";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
|
|
@@ -39,7 +40,9 @@ const factSearchOutputSchema = z.object({ hits: z.array(z.object({
|
|
|
39
40
|
text: z.string(),
|
|
40
41
|
score: z.number(),
|
|
41
42
|
sensitivity: sensitivityEnum,
|
|
42
|
-
provenance: provenanceEnum.optional()
|
|
43
|
+
provenance: provenanceEnum.optional(),
|
|
44
|
+
validTo: z.string().optional(),
|
|
45
|
+
supersededBy: z.string().optional()
|
|
43
46
|
})) });
|
|
44
47
|
const factSupersedeInputSchema = z.object({
|
|
45
48
|
oldId: z.string().min(1),
|
|
@@ -77,7 +80,7 @@ const factValidateOutputSchema = z.object({
|
|
|
77
80
|
validated: z.boolean()
|
|
78
81
|
});
|
|
79
82
|
/**
|
|
80
|
-
* `fact_remember`
|
|
83
|
+
* `fact_remember` - persist a single semantic fact. The minimum-viable
|
|
81
84
|
* pipeline writes the fact straight through with MD5 deduplication;
|
|
82
85
|
* Phase 10b extends the body with the multi-stage conflict resolution.
|
|
83
86
|
*
|
|
@@ -113,7 +116,7 @@ function createFactRememberTool(deps) {
|
|
|
113
116
|
});
|
|
114
117
|
}
|
|
115
118
|
/**
|
|
116
|
-
* `fact_search`
|
|
119
|
+
* `fact_search` - hybrid (vector + FTS5) search over the user's
|
|
117
120
|
* semantic memory. Results merged through the configured reranker.
|
|
118
121
|
*
|
|
119
122
|
* @stable
|
|
@@ -121,7 +124,7 @@ function createFactRememberTool(deps) {
|
|
|
121
124
|
function createFactSearchTool(deps) {
|
|
122
125
|
return tool({
|
|
123
126
|
name: "fact_search",
|
|
124
|
-
description: "Search the user's long-term factual memory by natural-language query. Returns up to `topK` matched facts with their score and sensitivity. Use this BEFORE asking the user a question they may have answered earlier. Pass `asOf` (ISO-8601) to read memory as it was at a past instant
|
|
127
|
+
description: "Search the user's long-term factual memory by natural-language query. Returns up to `topK` matched facts with their score and sensitivity. Use this BEFORE asking the user a question they may have answered earlier. Pass `asOf` (ISO-8601) to read memory as it was at a past instant - point-in-time / 'what was true on date X' - instead of the current state.",
|
|
125
128
|
inputSchema: factSearchInputSchema,
|
|
126
129
|
outputSchema: factSearchOutputSchema,
|
|
127
130
|
sideEffectClass: "read-only",
|
|
@@ -131,32 +134,41 @@ function createFactSearchTool(deps) {
|
|
|
131
134
|
tags: ["memory", "semantic"],
|
|
132
135
|
async execute(input, ctx) {
|
|
133
136
|
const scope = await deps.resolveScope(ctx);
|
|
134
|
-
|
|
137
|
+
const hits = await deps.semantic.search(scope, input.query, {
|
|
135
138
|
...input.topK !== void 0 ? { topK: input.topK } : {},
|
|
136
139
|
...input.tags !== void 0 && input.tags.length > 0 ? { tags: input.tags } : {},
|
|
137
140
|
...input.asOf !== void 0 ? { asOf: input.asOf } : {},
|
|
138
141
|
signal: ctx.signal
|
|
139
|
-
})
|
|
142
|
+
});
|
|
143
|
+
const output = { hits: hits.map((hit) => ({
|
|
140
144
|
factId: hit.record.id,
|
|
141
145
|
text: hit.record.text,
|
|
142
146
|
score: hit.score,
|
|
143
147
|
sensitivity: hit.record.sensitivity,
|
|
144
|
-
...hit.record.provenance !== void 0 ? { provenance: hit.record.provenance } : {}
|
|
148
|
+
...hit.record.provenance !== void 0 ? { provenance: hit.record.provenance } : {},
|
|
149
|
+
...hit.record.validTo !== void 0 ? { validTo: hit.record.validTo } : {},
|
|
150
|
+
...hit.record.supersededBy !== void 0 ? { supersededBy: hit.record.supersededBy } : {}
|
|
145
151
|
})) };
|
|
152
|
+
const taint = recallTaint(hits.map((h) => h.record));
|
|
153
|
+
return taint === void 0 ? output : {
|
|
154
|
+
output,
|
|
155
|
+
taint
|
|
156
|
+
};
|
|
146
157
|
}
|
|
147
158
|
});
|
|
148
159
|
}
|
|
149
160
|
/**
|
|
150
|
-
* `fact_supersede`
|
|
151
|
-
* that replaces it. The old fact is kept for replay but
|
|
152
|
-
*
|
|
161
|
+
* `fact_supersede` - soft-supersede an old fact by storing a new one
|
|
162
|
+
* that replaces it. The old fact is kept for replay but no longer
|
|
163
|
+
* surfaced by default reads (they evaluate validity at NOW); it stays
|
|
164
|
+
* reachable via `asOf` / inspector paths.
|
|
153
165
|
*
|
|
154
166
|
* @stable
|
|
155
167
|
*/
|
|
156
168
|
function createFactSupersedeTool(deps) {
|
|
157
169
|
return tool({
|
|
158
170
|
name: "fact_supersede",
|
|
159
|
-
description: "Mark an old fact superseded by a new one. Use this when the user's situation changed (moved cities, updated a goal, switched a preference)
|
|
171
|
+
description: "Mark an old fact superseded by a new one. Use this when the user's situation changed (moved cities, updated a goal, switched a preference) - the old fact is preserved for replay but no longer surfaced as current.",
|
|
160
172
|
inputSchema: factSupersedeInputSchema,
|
|
161
173
|
outputSchema: factSupersedeOutputSchema,
|
|
162
174
|
sideEffectClass: "side-effecting",
|
|
@@ -175,7 +187,7 @@ function createFactSupersedeTool(deps) {
|
|
|
175
187
|
});
|
|
176
188
|
}
|
|
177
189
|
/**
|
|
178
|
-
* `fact_forget`
|
|
190
|
+
* `fact_forget` - soft-delete a fact (kept for replay; never hard-
|
|
179
191
|
* deleted at this layer).
|
|
180
192
|
*
|
|
181
193
|
* @stable
|
|
@@ -202,7 +214,7 @@ function createFactForgetTool(deps) {
|
|
|
202
214
|
});
|
|
203
215
|
}
|
|
204
216
|
/**
|
|
205
|
-
* `fact_history`
|
|
217
|
+
* `fact_history` - trace how a fact changed over time. Returns the
|
|
206
218
|
* full bi-temporal supersede chain the given fact belongs to, oldest →
|
|
207
219
|
* newest, including superseded entries, so the agent can answer "what
|
|
208
220
|
* did the user say before" / "how did this change". Read-only. P0-2.
|
|
@@ -239,20 +251,20 @@ function createFactHistoryTool(deps) {
|
|
|
239
251
|
});
|
|
240
252
|
}
|
|
241
253
|
/**
|
|
242
|
-
* `fact_validate`
|
|
254
|
+
* `fact_validate` - promote a quarantined fact to active (P1-4). The
|
|
243
255
|
* validation path that admits a synthesized (consolidator / reflection)
|
|
244
256
|
* memory into action-driving recall once it has been reviewed; the
|
|
245
257
|
* promotion is audited in `memory_history`.
|
|
246
258
|
*
|
|
247
|
-
* MRET-3 / MST-1
|
|
259
|
+
* MRET-3 / MST-1 - two gates close the one-turn memory-poisoning chain
|
|
248
260
|
* (`fact_remember(poison)` → `fact_validate(id)` → active recall):
|
|
249
261
|
*
|
|
250
|
-
* 1. `needsApproval: true`
|
|
262
|
+
* 1. `needsApproval: true` - the run suspends for a human decision
|
|
251
263
|
* before this tool ever executes, so the agent cannot silently
|
|
252
264
|
* promote any quarantined fact.
|
|
253
265
|
* 2. The underlying `SemanticMemory.validate(...)` re-checks the fact's
|
|
254
266
|
* text against the injection heuristics and **refuses** (no `force`
|
|
255
|
-
* is passed here)
|
|
267
|
+
* is passed here) - an injection-flagged memory cannot be promoted by
|
|
256
268
|
* the agent at all. Only an operator, via the programmatic API with
|
|
257
269
|
* `{ force: true }`, can override after review.
|
|
258
270
|
*
|
|
@@ -264,7 +276,7 @@ function createFactHistoryTool(deps) {
|
|
|
264
276
|
function createFactValidateTool(deps) {
|
|
265
277
|
return tool({
|
|
266
278
|
name: "fact_validate",
|
|
267
|
-
description: "Promote a quarantined fact to active so it becomes eligible for normal recall. Quarantined facts are memories the system synthesized or flagged as risky; validating one is a deliberate, human-approved admission and never a routine step. This action requires approval, and facts flagged as prompt-injection cannot be promoted here
|
|
279
|
+
description: "Promote a quarantined fact to active so it becomes eligible for normal recall. Quarantined facts are memories the system synthesized or flagged as risky; validating one is a deliberate, human-approved admission and never a routine step. This action requires approval, and facts flagged as prompt-injection cannot be promoted here - they are an operator-only decision.",
|
|
268
280
|
inputSchema: factValidateInputSchema,
|
|
269
281
|
outputSchema: factValidateOutputSchema,
|
|
270
282
|
needsApproval: true,
|