audrey 0.21.0 → 1.0.0
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 +238 -0
- package/LICENSE +21 -21
- package/README.md +281 -33
- package/SECURITY.md +30 -0
- package/benchmarks/adapter-kit.mjs +20 -0
- package/benchmarks/adapter-self-test.mjs +166 -0
- package/benchmarks/adapters/example-allow.mjs +28 -0
- package/benchmarks/adapters/mem0-platform.mjs +267 -0
- package/benchmarks/adapters/registry.json +51 -0
- package/benchmarks/adapters/zep-cloud.mjs +280 -0
- package/benchmarks/baselines.js +169 -0
- package/benchmarks/build-leaderboard.mjs +170 -0
- package/benchmarks/cases.js +537 -0
- package/benchmarks/create-conformance-card.mjs +139 -0
- package/benchmarks/create-submission-bundle.mjs +176 -0
- package/benchmarks/dry-run-external-adapters.mjs +165 -0
- package/benchmarks/guardbench.js +1035 -0
- package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/guardbench-manifest.json +414 -0
- package/benchmarks/output/guardbench-raw.json +1171 -0
- package/benchmarks/output/guardbench-summary.json +1981 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/submission-bundle/guardbench-manifest.json +414 -0
- package/benchmarks/output/submission-bundle/guardbench-raw.json +1171 -0
- package/benchmarks/output/submission-bundle/guardbench-summary.json +1981 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-raw.schema.json +164 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-summary.schema.json +228 -0
- package/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/benchmarks/output/summary.json +2354 -0
- package/benchmarks/perf-snapshot.js +304 -0
- package/benchmarks/perf.bench.js +161 -0
- package/benchmarks/public-paths.mjs +78 -0
- package/benchmarks/reference-results.js +70 -0
- package/benchmarks/report.js +259 -0
- package/benchmarks/run-external-guardbench.mjs +281 -0
- package/benchmarks/run.js +682 -0
- package/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/schemas/guardbench-raw.schema.json +164 -0
- package/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/schemas/guardbench-summary.schema.json +228 -0
- package/benchmarks/snapshots/perf-0.22.2.json +123 -0
- package/benchmarks/snapshots/perf-0.23.0.json +123 -0
- package/benchmarks/validate-adapter-module.mjs +104 -0
- package/benchmarks/validate-adapter-registry.mjs +134 -0
- package/benchmarks/validate-adapter-self-test.mjs +96 -0
- package/benchmarks/validate-guardbench-artifacts.mjs +343 -0
- package/benchmarks/verify-external-evidence.mjs +296 -0
- package/benchmarks/verify-publication-artifacts.mjs +286 -0
- package/benchmarks/verify-submission-bundle.mjs +167 -0
- package/dist/mcp-server/config.d.ts +5 -4
- package/dist/mcp-server/config.d.ts.map +1 -1
- package/dist/mcp-server/config.js +6 -8
- package/dist/mcp-server/config.js.map +1 -1
- package/dist/mcp-server/index.d.ts +281 -23
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/index.js +1186 -82
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/src/action-key.d.ts +9 -0
- package/dist/src/action-key.d.ts.map +1 -0
- package/dist/src/action-key.js +49 -0
- package/dist/src/action-key.js.map +1 -0
- package/dist/src/adaptive.d.ts.map +1 -1
- package/dist/src/adaptive.js +8 -6
- package/dist/src/adaptive.js.map +1 -1
- package/dist/src/affect.d.ts +4 -1
- package/dist/src/affect.d.ts.map +1 -1
- package/dist/src/affect.js +14 -12
- package/dist/src/affect.js.map +1 -1
- package/dist/src/audrey.d.ts +57 -4
- package/dist/src/audrey.d.ts.map +1 -1
- package/dist/src/audrey.js +512 -65
- package/dist/src/audrey.js.map +1 -1
- package/dist/src/capsule.d.ts +2 -1
- package/dist/src/capsule.d.ts.map +1 -1
- package/dist/src/capsule.js +18 -8
- package/dist/src/capsule.js.map +1 -1
- package/dist/src/causal.d.ts.map +1 -1
- package/dist/src/causal.js +23 -5
- package/dist/src/causal.js.map +1 -1
- package/dist/src/confidence.d.ts.map +1 -1
- package/dist/src/confidence.js +3 -0
- package/dist/src/confidence.js.map +1 -1
- package/dist/src/consolidate.d.ts +1 -0
- package/dist/src/consolidate.d.ts.map +1 -1
- package/dist/src/consolidate.js +70 -54
- package/dist/src/consolidate.js.map +1 -1
- package/dist/src/controller.d.ts +94 -0
- package/dist/src/controller.d.ts.map +1 -0
- package/dist/src/controller.js +350 -0
- package/dist/src/controller.js.map +1 -0
- package/dist/src/db.d.ts.map +1 -1
- package/dist/src/db.js +181 -169
- package/dist/src/db.js.map +1 -1
- package/dist/src/decay.d.ts.map +1 -1
- package/dist/src/decay.js +62 -55
- package/dist/src/decay.js.map +1 -1
- package/dist/src/embedding.d.ts +2 -1
- package/dist/src/embedding.d.ts.map +1 -1
- package/dist/src/embedding.js +60 -22
- package/dist/src/embedding.js.map +1 -1
- package/dist/src/encode.d.ts +9 -2
- package/dist/src/encode.d.ts.map +1 -1
- package/dist/src/encode.js +25 -12
- package/dist/src/encode.js.map +1 -1
- package/dist/src/export.d.ts.map +1 -1
- package/dist/src/export.js +5 -3
- package/dist/src/export.js.map +1 -1
- package/dist/src/feedback.d.ts +35 -0
- package/dist/src/feedback.d.ts.map +1 -0
- package/dist/src/feedback.js +129 -0
- package/dist/src/feedback.js.map +1 -0
- package/dist/src/forget.d.ts.map +1 -1
- package/dist/src/forget.js +68 -60
- package/dist/src/forget.js.map +1 -1
- package/dist/src/fts.js +1 -1
- package/dist/src/fts.js.map +1 -1
- package/dist/src/hybrid-recall.d.ts +2 -1
- package/dist/src/hybrid-recall.d.ts.map +1 -1
- package/dist/src/hybrid-recall.js +41 -32
- package/dist/src/hybrid-recall.js.map +1 -1
- package/dist/src/impact.d.ts +47 -0
- package/dist/src/impact.d.ts.map +1 -0
- package/dist/src/impact.js +146 -0
- package/dist/src/impact.js.map +1 -0
- package/dist/src/import.d.ts +177 -1
- package/dist/src/import.d.ts.map +1 -1
- package/dist/src/import.js +235 -46
- package/dist/src/import.js.map +1 -1
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/interference.d.ts +5 -2
- package/dist/src/interference.d.ts.map +1 -1
- package/dist/src/interference.js +39 -32
- package/dist/src/interference.js.map +1 -1
- package/dist/src/introspect.js +18 -18
- package/dist/src/llm.d.ts.map +1 -1
- package/dist/src/llm.js +1 -0
- package/dist/src/llm.js.map +1 -1
- package/dist/src/migrate.d.ts.map +1 -1
- package/dist/src/migrate.js +21 -9
- package/dist/src/migrate.js.map +1 -1
- package/dist/src/preflight.d.ts +2 -1
- package/dist/src/preflight.d.ts.map +1 -1
- package/dist/src/preflight.js +66 -5
- package/dist/src/preflight.js.map +1 -1
- package/dist/src/profile.d.ts +23 -0
- package/dist/src/profile.d.ts.map +1 -0
- package/dist/src/profile.js +51 -0
- package/dist/src/profile.js.map +1 -0
- package/dist/src/promote.d.ts.map +1 -1
- package/dist/src/promote.js +8 -9
- package/dist/src/promote.js.map +1 -1
- package/dist/src/prompts.d.ts.map +1 -1
- package/dist/src/prompts.js +165 -136
- package/dist/src/prompts.js.map +1 -1
- package/dist/src/recall.d.ts +9 -6
- package/dist/src/recall.d.ts.map +1 -1
- package/dist/src/recall.js +204 -62
- package/dist/src/recall.js.map +1 -1
- package/dist/src/redact.d.ts +7 -1
- package/dist/src/redact.d.ts.map +1 -1
- package/dist/src/redact.js +94 -11
- package/dist/src/redact.js.map +1 -1
- package/dist/src/reflexes.d.ts +1 -0
- package/dist/src/reflexes.d.ts.map +1 -1
- package/dist/src/reflexes.js +3 -0
- package/dist/src/reflexes.js.map +1 -1
- package/dist/src/rollback.d.ts.map +1 -1
- package/dist/src/rollback.js +13 -8
- package/dist/src/rollback.js.map +1 -1
- package/dist/src/routes.d.ts +1 -0
- package/dist/src/routes.d.ts.map +1 -1
- package/dist/src/routes.js +251 -6
- package/dist/src/routes.js.map +1 -1
- package/dist/src/rules-compiler.d.ts.map +1 -1
- package/dist/src/rules-compiler.js +36 -6
- package/dist/src/rules-compiler.js.map +1 -1
- package/dist/src/server.d.ts +2 -1
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +42 -4
- package/dist/src/server.js.map +1 -1
- package/dist/src/tool-trace.d.ts.map +1 -1
- package/dist/src/tool-trace.js +42 -29
- package/dist/src/tool-trace.js.map +1 -1
- package/dist/src/types.d.ts +28 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/ulid.d.ts.map +1 -1
- package/dist/src/ulid.js +52 -2
- package/dist/src/ulid.js.map +1 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +8 -1
- package/dist/src/utils.js.map +1 -1
- package/dist/src/validate.d.ts +2 -0
- package/dist/src/validate.d.ts.map +1 -1
- package/dist/src/validate.js +77 -46
- package/dist/src/validate.js.map +1 -1
- package/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/MEMORY_BENCHMARKING.md +59 -0
- package/docs/PRODUCTION_BACKLOG.md +304 -0
- package/docs/paper/00-master.md +48 -0
- package/docs/paper/01-introduction.md +27 -0
- package/docs/paper/02-related-work.md +47 -0
- package/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/04-design.md +164 -0
- package/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/06-implementation.md +113 -0
- package/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/claim-register.json +138 -0
- package/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/LICENSE +21 -0
- package/docs/paper/output/submission-bundle/README.md +533 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-manifest.json +414 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +1171 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +1981 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +2354 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-raw.schema.json +164 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-summary.schema.json +228 -0
- package/docs/paper/output/submission-bundle/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/paper/output/submission-bundle/docs/paper/00-master.md +48 -0
- package/docs/paper/output/submission-bundle/docs/paper/01-introduction.md +27 -0
- package/docs/paper/output/submission-bundle/docs/paper/02-related-work.md +47 -0
- package/docs/paper/output/submission-bundle/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/output/submission-bundle/docs/paper/04-design.md +164 -0
- package/docs/paper/output/submission-bundle/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/output/submission-bundle/docs/paper/06-implementation.md +113 -0
- package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/output/submission-bundle/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/output/submission-bundle/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/output/submission-bundle/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.json +138 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/output/submission-bundle/docs/paper/references.bib +222 -0
- package/docs/paper/output/submission-bundle/package.json +212 -0
- package/docs/paper/output/submission-bundle/paper-submission-manifest.json +379 -0
- package/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/publication-pack.json +81 -0
- package/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/references.bib +222 -0
- package/package.json +103 -26
- package/scripts/audit-release-completion.mjs +362 -0
- package/scripts/create-arxiv-source.mjs +362 -0
- package/scripts/create-paper-submission-bundle.mjs +210 -0
- package/scripts/finalize-release.mjs +526 -0
- package/scripts/prepare-release-cut.mjs +269 -0
- package/scripts/publish-release-bundle.mjs +209 -0
- package/scripts/publish-release-github-api.mjs +429 -0
- package/scripts/run-vitest.mjs +34 -0
- package/scripts/smoke-cli.js +72 -0
- package/scripts/sync-paper-artifacts.mjs +109 -0
- package/scripts/verify-arxiv-compile.mjs +440 -0
- package/scripts/verify-arxiv-source.mjs +194 -0
- package/scripts/verify-browser-launch-plan.mjs +237 -0
- package/scripts/verify-browser-launch-results.mjs +285 -0
- package/scripts/verify-paper-artifacts.mjs +338 -0
- package/scripts/verify-paper-claims.mjs +226 -0
- package/scripts/verify-paper-submission-bundle.mjs +207 -0
- package/scripts/verify-publication-pack.mjs +196 -0
- package/scripts/verify-python-package.py +201 -0
- package/scripts/verify-release-readiness.mjs +741 -0
- package/docs/assets/benchmarks/local-benchmark.svg +0 -45
- package/docs/assets/benchmarks/operations-benchmark.svg +0 -45
- package/docs/assets/benchmarks/published-memory-standards.svg +0 -50
- package/docs/audrey-for-dummies.md +0 -670
- package/docs/benchmarking.md +0 -151
- package/docs/future-of-llm-memory.md +0 -452
- package/docs/mcp-hosts.md +0 -206
- package/docs/ollama-local-agents.md +0 -128
- package/docs/production-readiness.md +0 -128
package/dist/src/audrey.js
CHANGED
|
@@ -9,6 +9,8 @@ import { runConsolidation } from './consolidate.js';
|
|
|
9
9
|
import { applyDecay } from './decay.js';
|
|
10
10
|
import { rollbackConsolidation, getConsolidationHistory } from './rollback.js';
|
|
11
11
|
import { forgetMemory, forgetByQuery as forgetByQueryFn, purgeMemories } from './forget.js';
|
|
12
|
+
import { applyFeedback } from './feedback.js';
|
|
13
|
+
import { buildImpactReport } from './impact.js';
|
|
12
14
|
import { introspect as introspectFn } from './introspect.js';
|
|
13
15
|
import { buildContextResolutionPrompt, buildReflectionPrompt } from './prompts.js';
|
|
14
16
|
import { exportMemories } from './export.js';
|
|
@@ -22,11 +24,100 @@ import { listEvents, countEvents, recentFailures, } from './events.js';
|
|
|
22
24
|
import { buildCapsule } from './capsule.js';
|
|
23
25
|
import { buildPreflight } from './preflight.js';
|
|
24
26
|
import { buildReflexReport } from './reflexes.js';
|
|
27
|
+
import { beforeAction as guardBeforeAction, afterAction as guardAfterAction, } from './controller.js';
|
|
25
28
|
import { findPromotionCandidates, } from './promote.js';
|
|
26
29
|
import { renderAllRules } from './rules-compiler.js';
|
|
27
30
|
import { insertEvent } from './events.js';
|
|
28
31
|
import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
|
|
29
|
-
import { dirname, join, resolve as pathResolve } from 'node:path';
|
|
32
|
+
import { dirname, join, resolve as pathResolve, relative, isAbsolute as pathIsAbsolute } from 'node:path';
|
|
33
|
+
import { ProfileRecorder } from './profile.js';
|
|
34
|
+
import { performance } from 'node:perf_hooks';
|
|
35
|
+
function roundMs(value) {
|
|
36
|
+
return Math.round(value * 1000) / 1000;
|
|
37
|
+
}
|
|
38
|
+
function validateEncodeParams(params) {
|
|
39
|
+
if (!params.content || typeof params.content !== 'string') {
|
|
40
|
+
throw new Error('content must be a non-empty string');
|
|
41
|
+
}
|
|
42
|
+
if (params.salience !== undefined && (params.salience < 0 || params.salience > 1)) {
|
|
43
|
+
throw new Error('salience must be between 0 and 1');
|
|
44
|
+
}
|
|
45
|
+
if (params.tags !== undefined && !Array.isArray(params.tags)) {
|
|
46
|
+
throw new Error('tags must be an array');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const REFLECTION_SOURCES = new Set([
|
|
50
|
+
'direct-observation',
|
|
51
|
+
'told-by-user',
|
|
52
|
+
'inference',
|
|
53
|
+
]);
|
|
54
|
+
function boundedString(value, maxLength) {
|
|
55
|
+
if (typeof value !== 'string')
|
|
56
|
+
return undefined;
|
|
57
|
+
const trimmed = value.trim();
|
|
58
|
+
if (!trimmed)
|
|
59
|
+
return undefined;
|
|
60
|
+
return trimmed.slice(0, maxLength);
|
|
61
|
+
}
|
|
62
|
+
function boundedNumber(value, min, max) {
|
|
63
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
64
|
+
return undefined;
|
|
65
|
+
return Math.max(min, Math.min(max, value));
|
|
66
|
+
}
|
|
67
|
+
function normalizeReflectionAffect(raw) {
|
|
68
|
+
if (!raw || typeof raw !== 'object')
|
|
69
|
+
return undefined;
|
|
70
|
+
const record = raw;
|
|
71
|
+
const valence = boundedNumber(record.valence, -1, 1);
|
|
72
|
+
const arousal = boundedNumber(record.arousal, 0, 1);
|
|
73
|
+
if (valence === undefined && arousal === undefined)
|
|
74
|
+
return undefined;
|
|
75
|
+
const affect = {};
|
|
76
|
+
if (valence !== undefined)
|
|
77
|
+
affect.valence = valence;
|
|
78
|
+
if (arousal !== undefined)
|
|
79
|
+
affect.arousal = arousal;
|
|
80
|
+
const label = boundedString(record.label, 64);
|
|
81
|
+
if (label)
|
|
82
|
+
affect.label = label;
|
|
83
|
+
return affect;
|
|
84
|
+
}
|
|
85
|
+
function normalizeReflectionMemory(raw) {
|
|
86
|
+
if (!raw || typeof raw !== 'object')
|
|
87
|
+
return null;
|
|
88
|
+
const record = raw;
|
|
89
|
+
const content = boundedString(record.content, 5000);
|
|
90
|
+
if (!content)
|
|
91
|
+
return null;
|
|
92
|
+
const source = record.source;
|
|
93
|
+
if (typeof source !== 'string' || !REFLECTION_SOURCES.has(source)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const memory = {
|
|
97
|
+
content,
|
|
98
|
+
source: source,
|
|
99
|
+
};
|
|
100
|
+
const salience = boundedNumber(record.salience, 0, 1);
|
|
101
|
+
if (salience !== undefined)
|
|
102
|
+
memory.salience = salience;
|
|
103
|
+
if (Array.isArray(record.tags)) {
|
|
104
|
+
const tags = record.tags
|
|
105
|
+
.map(tag => boundedString(tag, 64))
|
|
106
|
+
.filter((tag) => Boolean(tag))
|
|
107
|
+
.slice(0, 20);
|
|
108
|
+
if (tags.length > 0)
|
|
109
|
+
memory.tags = tags;
|
|
110
|
+
}
|
|
111
|
+
if (typeof record.private === 'boolean')
|
|
112
|
+
memory.private = record.private;
|
|
113
|
+
const affect = normalizeReflectionAffect(record.affect);
|
|
114
|
+
if (affect)
|
|
115
|
+
memory.affect = affect;
|
|
116
|
+
return memory;
|
|
117
|
+
}
|
|
118
|
+
function messagesToLegacyPrompt(messages) {
|
|
119
|
+
return messages.map(message => `${message.role.toUpperCase()}:\n${message.content}`).join('\n\n');
|
|
120
|
+
}
|
|
30
121
|
export class Audrey extends EventEmitter {
|
|
31
122
|
agent;
|
|
32
123
|
dataDir;
|
|
@@ -39,10 +130,18 @@ export class Audrey extends EventEmitter {
|
|
|
39
130
|
interferenceConfig;
|
|
40
131
|
contextConfig;
|
|
41
132
|
affectConfig;
|
|
133
|
+
defaultRetrievalMode;
|
|
42
134
|
autoReflect;
|
|
43
135
|
_migrationPending;
|
|
44
136
|
_autoConsolidateTimer;
|
|
45
137
|
_closed;
|
|
138
|
+
_postEncodeQueue;
|
|
139
|
+
_pendingPostEncodeIds;
|
|
140
|
+
_embeddingWarm;
|
|
141
|
+
_embeddingWarmupPromise;
|
|
142
|
+
_warmupDurationMs;
|
|
143
|
+
_lastRecallCheckAt;
|
|
144
|
+
_lastRecallErrors;
|
|
46
145
|
constructor({ dataDir = './audrey-data', agent = 'default', embedding = { provider: 'mock', dimensions: 64 }, llm, confidence = {}, consolidation = {}, decay = {}, interference = {}, context = {}, affect = {}, autoReflect = false, } = {}) {
|
|
47
146
|
super();
|
|
48
147
|
const dormantThreshold = decay.dormantThreshold ?? 0.1;
|
|
@@ -69,9 +168,9 @@ export class Audrey extends EventEmitter {
|
|
|
69
168
|
affectWeight: affect.weight ?? 0.2,
|
|
70
169
|
};
|
|
71
170
|
this.consolidationConfig = {
|
|
72
|
-
minEpisodes
|
|
171
|
+
minEpisodes,
|
|
73
172
|
};
|
|
74
|
-
this.decayConfig = { dormantThreshold
|
|
173
|
+
this.decayConfig = { dormantThreshold };
|
|
75
174
|
this._autoConsolidateTimer = null;
|
|
76
175
|
this._closed = false;
|
|
77
176
|
this.interferenceConfig = {
|
|
@@ -95,7 +194,15 @@ export class Audrey extends EventEmitter {
|
|
|
95
194
|
affectThreshold: affect.resonance?.affectThreshold ?? 0.6,
|
|
96
195
|
},
|
|
97
196
|
};
|
|
197
|
+
this.defaultRetrievalMode = 'hybrid';
|
|
98
198
|
this.autoReflect = autoReflect;
|
|
199
|
+
this._postEncodeQueue = Promise.resolve();
|
|
200
|
+
this._pendingPostEncodeIds = new Set();
|
|
201
|
+
this._embeddingWarm = false;
|
|
202
|
+
this._embeddingWarmupPromise = null;
|
|
203
|
+
this._warmupDurationMs = null;
|
|
204
|
+
this._lastRecallCheckAt = null;
|
|
205
|
+
this._lastRecallErrors = [];
|
|
99
206
|
}
|
|
100
207
|
async _ensureMigrated() {
|
|
101
208
|
if (!this._migrationPending)
|
|
@@ -104,54 +211,207 @@ export class Audrey extends EventEmitter {
|
|
|
104
211
|
this._migrationPending = false;
|
|
105
212
|
this.emit('migration', counts);
|
|
106
213
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
214
|
+
startEmbeddingWarmup(text = 'warmup') {
|
|
215
|
+
if (this._embeddingWarm)
|
|
216
|
+
return Promise.resolve();
|
|
217
|
+
if (this._embeddingWarmupPromise)
|
|
218
|
+
return this._embeddingWarmupPromise;
|
|
219
|
+
const startedAt = performance.now();
|
|
220
|
+
this._embeddingWarmupPromise = (async () => {
|
|
221
|
+
if (typeof this.embeddingProvider.ready === 'function') {
|
|
222
|
+
await this.embeddingProvider.ready();
|
|
223
|
+
}
|
|
224
|
+
await this.embeddingProvider.embed(text);
|
|
225
|
+
this._embeddingWarm = true;
|
|
226
|
+
})()
|
|
227
|
+
.catch(err => {
|
|
228
|
+
this._emitQueueError(err);
|
|
229
|
+
throw err;
|
|
110
230
|
})
|
|
111
|
-
.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
231
|
+
.finally(() => {
|
|
232
|
+
this._warmupDurationMs = roundMs(performance.now() - startedAt);
|
|
233
|
+
});
|
|
234
|
+
return this._embeddingWarmupPromise;
|
|
235
|
+
}
|
|
236
|
+
async _waitForEmbeddingWarmup(profile, spanName = 'embedding.wait_for_warmup') {
|
|
237
|
+
if (!this._embeddingWarmupPromise || this._embeddingWarm)
|
|
238
|
+
return;
|
|
239
|
+
const wait = async () => {
|
|
240
|
+
try {
|
|
241
|
+
await this._embeddingWarmupPromise;
|
|
118
242
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
contradictionId: validation.contradictionId,
|
|
123
|
-
semanticId: validation.semanticId,
|
|
124
|
-
similarity: validation.similarity,
|
|
125
|
-
resolution: validation.resolution,
|
|
126
|
-
});
|
|
243
|
+
catch {
|
|
244
|
+
// Warmup failure should not poison the foreground call; the foreground
|
|
245
|
+
// embed path will surface provider errors if the provider is truly broken.
|
|
127
246
|
}
|
|
128
|
-
}
|
|
129
|
-
|
|
247
|
+
};
|
|
248
|
+
if (profile)
|
|
249
|
+
await profile.measure(spanName, wait);
|
|
250
|
+
else
|
|
251
|
+
await wait();
|
|
130
252
|
}
|
|
131
|
-
async
|
|
132
|
-
await this.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
253
|
+
async _validateEncodedMemory(id, params, embedding) {
|
|
254
|
+
const validation = await validateMemory(this.db, this.embeddingProvider, { id, ...params }, {
|
|
255
|
+
llmProvider: this.llmProvider,
|
|
256
|
+
embeddingVector: embedding?.vector,
|
|
257
|
+
embeddingBuffer: embedding?.buffer,
|
|
258
|
+
});
|
|
259
|
+
if (validation.action === 'reinforced') {
|
|
260
|
+
this.emit('reinforcement', {
|
|
261
|
+
episodeId: id,
|
|
262
|
+
targetId: validation.semanticId,
|
|
263
|
+
similarity: validation.similarity,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
else if (validation.action === 'contradiction') {
|
|
267
|
+
this.emit('contradiction', {
|
|
268
|
+
episodeId: id,
|
|
269
|
+
contradictionId: validation.contradictionId,
|
|
270
|
+
semanticId: validation.semanticId,
|
|
271
|
+
similarity: validation.similarity,
|
|
272
|
+
resolution: validation.resolution,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async _runPostEncodeStage(name, run) {
|
|
277
|
+
try {
|
|
278
|
+
await run();
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
this._emitQueueError(Object.assign(err instanceof Error ? err : new Error(String(err)), {
|
|
282
|
+
stage: name,
|
|
283
|
+
}));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async _runPostEncode(id, params, embedding) {
|
|
136
287
|
if (this.interferenceConfig.enabled) {
|
|
137
|
-
|
|
138
|
-
|
|
288
|
+
await this._runPostEncodeStage('interference', async () => {
|
|
289
|
+
const affected = await applyInterference(this.db, this.embeddingProvider, id, params, this.interferenceConfig, embedding);
|
|
139
290
|
if (affected.length > 0) {
|
|
140
291
|
this.emit('interference', { episodeId: id, affected });
|
|
141
292
|
}
|
|
142
|
-
})
|
|
143
|
-
.catch(err => this.emit('error', err));
|
|
293
|
+
});
|
|
144
294
|
}
|
|
145
295
|
if (this.affectConfig.enabled && this.affectConfig.resonance.enabled && params.affect?.valence !== undefined) {
|
|
146
|
-
|
|
147
|
-
|
|
296
|
+
await this._runPostEncodeStage('resonance', async () => {
|
|
297
|
+
const echoes = await detectResonance(this.db, this.embeddingProvider, id, params, this.affectConfig.resonance, embedding);
|
|
148
298
|
if (echoes.length > 0) {
|
|
149
299
|
this.emit('resonance', { episodeId: id, affect: params.affect, echoes });
|
|
150
300
|
}
|
|
151
|
-
})
|
|
152
|
-
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
await this._runPostEncodeStage('validation', async () => {
|
|
304
|
+
await this._validateEncodedMemory(id, params, embedding);
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
_enqueuePostEncode(id, params, embedding) {
|
|
308
|
+
const enqueuedAt = performance.now();
|
|
309
|
+
this._pendingPostEncodeIds.add(id);
|
|
310
|
+
const run = async () => {
|
|
311
|
+
const startedAt = performance.now();
|
|
312
|
+
try {
|
|
313
|
+
if (!this._closed) {
|
|
314
|
+
await this._runPostEncode(id, params, embedding);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
finally {
|
|
318
|
+
const finishedAt = performance.now();
|
|
319
|
+
this._pendingPostEncodeIds.delete(id);
|
|
320
|
+
this.emit('post-encode-complete', {
|
|
321
|
+
episodeId: id,
|
|
322
|
+
queued_ms: roundMs(startedAt - enqueuedAt),
|
|
323
|
+
processing_ms: roundMs(finishedAt - startedAt),
|
|
324
|
+
total_ms: roundMs(finishedAt - enqueuedAt),
|
|
325
|
+
pending_consolidation_count: this._pendingPostEncodeIds.size,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const task = this._postEncodeQueue.then(run, run);
|
|
330
|
+
this._postEncodeQueue = task.catch(err => {
|
|
331
|
+
this._emitQueueError(err);
|
|
332
|
+
});
|
|
333
|
+
return task;
|
|
334
|
+
}
|
|
335
|
+
_emitQueueError(err) {
|
|
336
|
+
if (this.listenerCount('error') > 0) {
|
|
337
|
+
// Caller has opted into error handling; let them route logging.
|
|
338
|
+
this.emit('error', err);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// Standard EventEmitter idiom: log only when nobody is listening, so we
|
|
342
|
+
// surface failures by default but don't double-log for apps with structured
|
|
343
|
+
// error pipelines. The MCP server registers a logger listener at startup.
|
|
344
|
+
const stage = err?.stage;
|
|
345
|
+
const prefix = stage ? `[audrey:post-encode:${stage}]` : '[audrey:post-encode]';
|
|
346
|
+
const message = err instanceof Error ? (err.stack ?? err.message) : String(err);
|
|
347
|
+
console.error(`${prefix} ${message}`);
|
|
348
|
+
}
|
|
349
|
+
pendingConsolidationIds() {
|
|
350
|
+
return [...this._pendingPostEncodeIds];
|
|
351
|
+
}
|
|
352
|
+
async drainPostEncodeQueue(timeoutMs = 5000) {
|
|
353
|
+
if (this._pendingPostEncodeIds.size === 0) {
|
|
354
|
+
return { drained: true, pendingIds: [] };
|
|
355
|
+
}
|
|
356
|
+
let timeout;
|
|
357
|
+
const timedOut = Symbol('timed-out');
|
|
358
|
+
const timeoutPromise = new Promise(resolve => {
|
|
359
|
+
timeout = setTimeout(() => resolve(timedOut), timeoutMs);
|
|
360
|
+
});
|
|
361
|
+
const result = await Promise.race([
|
|
362
|
+
this._postEncodeQueue.then(() => true),
|
|
363
|
+
timeoutPromise,
|
|
364
|
+
]);
|
|
365
|
+
if (timeout)
|
|
366
|
+
clearTimeout(timeout);
|
|
367
|
+
const drained = result === true && this._pendingPostEncodeIds.size === 0;
|
|
368
|
+
return {
|
|
369
|
+
drained,
|
|
370
|
+
pendingIds: this.pendingConsolidationIds(),
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
async encode(params) {
|
|
374
|
+
return this._encodeInternal(params);
|
|
375
|
+
}
|
|
376
|
+
async encodeWithDiagnostics(params) {
|
|
377
|
+
const profile = new ProfileRecorder('memory_encode');
|
|
378
|
+
const id = await this._encodeInternal(params, profile);
|
|
379
|
+
return { id, diagnostics: profile.finish() };
|
|
380
|
+
}
|
|
381
|
+
async _encodeInternal(params, profile) {
|
|
382
|
+
await this._waitForEmbeddingWarmup(profile, 'encode.wait_for_warmup');
|
|
383
|
+
if (profile)
|
|
384
|
+
await profile.measure('encode.ensure_migrated', () => this._ensureMigrated());
|
|
385
|
+
else
|
|
386
|
+
await this._ensureMigrated();
|
|
387
|
+
const encodeParams = { ...params, agent: params.agent ?? this.agent, arousalWeight: this.affectConfig.arousalWeight };
|
|
388
|
+
let encodedVector;
|
|
389
|
+
let encodedBuffer;
|
|
390
|
+
const id = profile
|
|
391
|
+
? await profile.measure('encode.episode', () => encodeEpisode(this.db, this.embeddingProvider, encodeParams, {
|
|
392
|
+
profile,
|
|
393
|
+
onVector: (vector, buffer) => {
|
|
394
|
+
encodedVector = vector;
|
|
395
|
+
encodedBuffer = buffer;
|
|
396
|
+
},
|
|
397
|
+
}))
|
|
398
|
+
: await encodeEpisode(this.db, this.embeddingProvider, encodeParams, {
|
|
399
|
+
onVector: (vector, buffer) => {
|
|
400
|
+
encodedVector = vector;
|
|
401
|
+
encodedBuffer = buffer;
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
const encodedEmbedding = { vector: encodedVector, buffer: encodedBuffer };
|
|
405
|
+
this.emit('encode', { id, ...params });
|
|
406
|
+
const postEncodeTask = profile
|
|
407
|
+
? profile.measureSync('encode.enqueue_background', () => this._enqueuePostEncode(id, params, encodedEmbedding))
|
|
408
|
+
: this._enqueuePostEncode(id, params, encodedEmbedding);
|
|
409
|
+
if (params.waitForConsolidation) {
|
|
410
|
+
if (profile)
|
|
411
|
+
await profile.measure('encode.wait_for_consolidation', () => postEncodeTask);
|
|
412
|
+
else
|
|
413
|
+
await postEncodeTask;
|
|
153
414
|
}
|
|
154
|
-
this._emitValidation(id, params);
|
|
155
415
|
return id;
|
|
156
416
|
}
|
|
157
417
|
async reflect(turns) {
|
|
@@ -160,7 +420,15 @@ export class Audrey extends EventEmitter {
|
|
|
160
420
|
const prompt = buildReflectionPrompt(turns);
|
|
161
421
|
let raw;
|
|
162
422
|
try {
|
|
163
|
-
|
|
423
|
+
if (typeof this.llmProvider.complete === 'function') {
|
|
424
|
+
raw = (await this.llmProvider.complete(prompt)).content;
|
|
425
|
+
}
|
|
426
|
+
else if (typeof this.llmProvider.chat === 'function') {
|
|
427
|
+
raw = await this.llmProvider.chat(messagesToLegacyPrompt(prompt));
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
return { encoded: 0, memories: [], skipped: 'llm provider missing completion method' };
|
|
431
|
+
}
|
|
164
432
|
}
|
|
165
433
|
catch (err) {
|
|
166
434
|
this.emit('error', err);
|
|
@@ -173,11 +441,11 @@ export class Audrey extends EventEmitter {
|
|
|
173
441
|
catch {
|
|
174
442
|
return { encoded: 0, memories: [], skipped: 'invalid llm response' };
|
|
175
443
|
}
|
|
176
|
-
const memories = parsed.memories
|
|
444
|
+
const memories = Array.isArray(parsed.memories)
|
|
445
|
+
? parsed.memories.map(normalizeReflectionMemory).filter((mem) => mem !== null).slice(0, 50)
|
|
446
|
+
: [];
|
|
177
447
|
let encoded = 0;
|
|
178
448
|
for (const mem of memories) {
|
|
179
|
-
if (!mem.content || !mem.source)
|
|
180
|
-
continue;
|
|
181
449
|
try {
|
|
182
450
|
await this.encode({
|
|
183
451
|
content: mem.content,
|
|
@@ -193,32 +461,80 @@ export class Audrey extends EventEmitter {
|
|
|
193
461
|
this.emit('error', err);
|
|
194
462
|
}
|
|
195
463
|
}
|
|
196
|
-
return { encoded, memories
|
|
464
|
+
return { encoded, memories };
|
|
197
465
|
}
|
|
198
466
|
async encodeBatch(paramsList) {
|
|
467
|
+
await this._waitForEmbeddingWarmup();
|
|
199
468
|
await this._ensureMigrated();
|
|
200
|
-
|
|
469
|
+
if (paramsList.length === 0)
|
|
470
|
+
return [];
|
|
201
471
|
for (const params of paramsList) {
|
|
202
|
-
|
|
472
|
+
validateEncodeParams(params);
|
|
473
|
+
}
|
|
474
|
+
const normalized = paramsList.map(params => ({
|
|
475
|
+
...params,
|
|
476
|
+
agent: params.agent ?? this.agent,
|
|
477
|
+
arousalWeight: this.affectConfig.arousalWeight,
|
|
478
|
+
}));
|
|
479
|
+
const vectors = await this.embeddingProvider.embedBatch(normalized.map(params => params.content));
|
|
480
|
+
if (vectors.length !== normalized.length) {
|
|
481
|
+
throw new Error(`embedBatch returned ${vectors.length} vectors for ${normalized.length} inputs`);
|
|
482
|
+
}
|
|
483
|
+
const ids = [];
|
|
484
|
+
const tasks = [];
|
|
485
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
486
|
+
const encodeParams = normalized[i];
|
|
487
|
+
let encodedVector;
|
|
488
|
+
let encodedBuffer;
|
|
489
|
+
const id = await encodeEpisode(this.db, this.embeddingProvider, encodeParams, {
|
|
490
|
+
vector: vectors[i],
|
|
491
|
+
onVector: (vector, buffer) => {
|
|
492
|
+
encodedVector = vector;
|
|
493
|
+
encodedBuffer = buffer;
|
|
494
|
+
},
|
|
495
|
+
});
|
|
203
496
|
ids.push(id);
|
|
204
|
-
this.emit('encode', { id, ...
|
|
497
|
+
this.emit('encode', { id, ...paramsList[i] });
|
|
498
|
+
const encodedEmbedding = { vector: encodedVector, buffer: encodedBuffer };
|
|
499
|
+
tasks.push(this._enqueuePostEncode(id, paramsList[i], encodedEmbedding));
|
|
205
500
|
}
|
|
206
|
-
|
|
207
|
-
|
|
501
|
+
if (paramsList.some(p => p.waitForConsolidation)) {
|
|
502
|
+
await Promise.all(tasks);
|
|
208
503
|
}
|
|
209
504
|
return ids;
|
|
210
505
|
}
|
|
211
506
|
async recall(query, options = {}) {
|
|
212
|
-
|
|
213
|
-
|
|
507
|
+
return this._recallInternal(query, options);
|
|
508
|
+
}
|
|
509
|
+
async recallWithDiagnostics(query, options = {}) {
|
|
510
|
+
const profile = new ProfileRecorder('memory_recall');
|
|
511
|
+
const results = await this._recallInternal(query, options, profile);
|
|
512
|
+
return { results, diagnostics: profile.finish() };
|
|
513
|
+
}
|
|
514
|
+
async _recallInternal(query, options = {}, profile) {
|
|
515
|
+
await this._waitForEmbeddingWarmup(profile, 'recall.wait_for_warmup');
|
|
516
|
+
if (profile)
|
|
517
|
+
await profile.measure('recall.ensure_migrated', () => this._ensureMigrated());
|
|
518
|
+
else
|
|
519
|
+
await this._ensureMigrated();
|
|
520
|
+
const results = await recallFn(this.db, this.embeddingProvider, query, {
|
|
214
521
|
...options,
|
|
522
|
+
agent: options.agent ?? this.agent,
|
|
523
|
+
retrieval: options.retrieval ?? this.defaultRetrievalMode,
|
|
215
524
|
confidenceConfig: this._recallConfig(options),
|
|
525
|
+
profile,
|
|
216
526
|
});
|
|
527
|
+
this._lastRecallCheckAt = new Date().toISOString();
|
|
528
|
+
this._lastRecallErrors = results.errors ?? [];
|
|
529
|
+
return results;
|
|
217
530
|
}
|
|
218
531
|
async *recallStream(query, options = {}) {
|
|
532
|
+
await this._waitForEmbeddingWarmup();
|
|
219
533
|
await this._ensureMigrated();
|
|
220
534
|
yield* recallStreamFn(this.db, this.embeddingProvider, query, {
|
|
221
535
|
...options,
|
|
536
|
+
agent: options.agent ?? this.agent,
|
|
537
|
+
retrieval: options.retrieval ?? this.defaultRetrievalMode,
|
|
222
538
|
confidenceConfig: this._recallConfig(options),
|
|
223
539
|
});
|
|
224
540
|
}
|
|
@@ -234,20 +550,22 @@ export class Audrey extends EventEmitter {
|
|
|
234
550
|
}
|
|
235
551
|
async consolidate(options = {}) {
|
|
236
552
|
await this._ensureMigrated();
|
|
553
|
+
// Use ?? throughout so 0 / '' are not silently replaced with the default.
|
|
237
554
|
const result = await runConsolidation(this.db, this.embeddingProvider, {
|
|
238
|
-
minClusterSize: options.minClusterSize
|
|
239
|
-
similarityThreshold: options.similarityThreshold
|
|
555
|
+
minClusterSize: options.minClusterSize ?? this.consolidationConfig.minEpisodes,
|
|
556
|
+
similarityThreshold: options.similarityThreshold ?? 0.80,
|
|
557
|
+
agent: options.agent ?? this.agent,
|
|
240
558
|
extractPrinciple: options.extractPrinciple,
|
|
241
|
-
llmProvider: options.llmProvider
|
|
559
|
+
llmProvider: options.llmProvider ?? this.llmProvider ?? undefined,
|
|
242
560
|
});
|
|
243
561
|
const run = db_prepare_get_status(this.db, result.runId);
|
|
244
|
-
const output = { ...result, status: run?.status
|
|
562
|
+
const output = { ...result, status: run?.status ?? 'completed' };
|
|
245
563
|
this.emit('consolidation', output);
|
|
246
564
|
return output;
|
|
247
565
|
}
|
|
248
566
|
decay(options = {}) {
|
|
249
567
|
const result = applyDecay(this.db, {
|
|
250
|
-
dormantThreshold: options.dormantThreshold
|
|
568
|
+
dormantThreshold: options.dormantThreshold ?? this.decayConfig.dormantThreshold,
|
|
251
569
|
halfLives: options.halfLives ?? this.confidenceConfig.halfLives,
|
|
252
570
|
});
|
|
253
571
|
this.emit('decay', result);
|
|
@@ -271,9 +589,9 @@ export class Audrey extends EventEmitter {
|
|
|
271
589
|
const result = await this.llmProvider.json(messages);
|
|
272
590
|
const now = new Date().toISOString();
|
|
273
591
|
const newState = result.resolution === 'context_dependent' ? 'context_dependent' : 'resolved';
|
|
274
|
-
this.db.prepare(`
|
|
275
|
-
UPDATE contradictions SET state = ?, resolution = ?, resolved_at = ?
|
|
276
|
-
WHERE id = ?
|
|
592
|
+
this.db.prepare(`
|
|
593
|
+
UPDATE contradictions SET state = ?, resolution = ?, resolved_at = ?
|
|
594
|
+
WHERE id = ?
|
|
277
595
|
`).run(newState, JSON.stringify(result), now, contradictionId);
|
|
278
596
|
if (result.resolution === 'a_wins' && contradiction.claim_a_type === 'semantic') {
|
|
279
597
|
this.db.prepare("UPDATE semantics SET state = 'active' WHERE id = ?").run(contradiction.claim_a_id);
|
|
@@ -354,14 +672,23 @@ export class Audrey extends EventEmitter {
|
|
|
354
672
|
device: device ?? null,
|
|
355
673
|
healthy,
|
|
356
674
|
reembed_recommended: reembedRecommended,
|
|
675
|
+
pending_consolidation_count: this._pendingPostEncodeIds.size,
|
|
676
|
+
embedding_warm: this._embeddingWarm,
|
|
677
|
+
warmup_duration_ms: this._warmupDurationMs,
|
|
678
|
+
default_retrieval_mode: this.defaultRetrievalMode,
|
|
679
|
+
recall_degraded: this._lastRecallErrors.length > 0,
|
|
680
|
+
last_recall_check_at: this._lastRecallCheckAt,
|
|
681
|
+
last_recall_errors: this._lastRecallErrors,
|
|
357
682
|
};
|
|
358
683
|
}
|
|
359
|
-
async greeting({ context, recentLimit = 10, principleLimit = 5, identityLimit = 5 } = {}) {
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
const
|
|
363
|
-
const
|
|
364
|
-
const
|
|
684
|
+
async greeting({ context, recentLimit = 10, principleLimit = 5, identityLimit = 5, scope = 'agent' } = {}) {
|
|
685
|
+
const agentClause = scope === 'agent' ? 'AND agent = ?' : '';
|
|
686
|
+
const agentParam = scope === 'agent' ? [this.agent] : [];
|
|
687
|
+
const recent = this.db.prepare(`SELECT id, content, source, tags, salience, created_at FROM episodes WHERE "private" = 0 ${agentClause} ORDER BY created_at DESC LIMIT ?`).all(...agentParam, recentLimit);
|
|
688
|
+
const principles = this.db.prepare(`SELECT id, content, salience, created_at FROM semantics WHERE state = ? ${agentClause} ORDER BY salience DESC LIMIT ?`).all('active', ...agentParam, principleLimit);
|
|
689
|
+
const identity = this.db.prepare(`SELECT id, content, tags, salience, created_at FROM episodes WHERE "private" = 1 ${agentClause} ORDER BY created_at DESC LIMIT ?`).all(...agentParam, identityLimit);
|
|
690
|
+
const unresolved = this.db.prepare(`SELECT id, content, tags, salience, created_at FROM episodes WHERE tags LIKE '%unresolved%' AND salience > 0.3 ${agentClause} ORDER BY created_at DESC LIMIT 10`).all(...agentParam);
|
|
691
|
+
const rawAffectRows = this.db.prepare(`SELECT affect FROM episodes WHERE affect IS NOT NULL AND affect != '{}' ${agentClause} ORDER BY created_at DESC LIMIT 20`).all(...agentParam);
|
|
365
692
|
const affectParsed = rawAffectRows
|
|
366
693
|
.map(r => { try {
|
|
367
694
|
return JSON.parse(r.affect);
|
|
@@ -385,7 +712,7 @@ export class Audrey extends EventEmitter {
|
|
|
385
712
|
}
|
|
386
713
|
const result = { recent, principles, mood, unresolved, identity };
|
|
387
714
|
if (context) {
|
|
388
|
-
result.contextual = await this.recall(context, { limit: 5, includePrivate: true });
|
|
715
|
+
result.contextual = await this.recall(context, { limit: 5, includePrivate: true, scope });
|
|
389
716
|
}
|
|
390
717
|
return result;
|
|
391
718
|
}
|
|
@@ -436,6 +763,76 @@ export class Audrey extends EventEmitter {
|
|
|
436
763
|
suggestConsolidationParams() {
|
|
437
764
|
return suggestParamsFn(this.db);
|
|
438
765
|
}
|
|
766
|
+
validate(input) {
|
|
767
|
+
let preflightMetadata = null;
|
|
768
|
+
if (input.preflightEventId) {
|
|
769
|
+
const preflightEvent = this.db.prepare("SELECT event_type, metadata FROM memory_events WHERE id = ?").get(input.preflightEventId);
|
|
770
|
+
if (!preflightEvent) {
|
|
771
|
+
throw new Error(`preflight_event_id ${input.preflightEventId} was not found`);
|
|
772
|
+
}
|
|
773
|
+
if (preflightEvent.event_type !== 'PreToolUse') {
|
|
774
|
+
throw new Error(`preflight_event_id ${input.preflightEventId} is not a PreToolUse event`);
|
|
775
|
+
}
|
|
776
|
+
if (preflightEvent.metadata) {
|
|
777
|
+
try {
|
|
778
|
+
preflightMetadata = JSON.parse(preflightEvent.metadata);
|
|
779
|
+
}
|
|
780
|
+
catch {
|
|
781
|
+
preflightMetadata = null;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const preflightEvidenceIds = Array.isArray(preflightMetadata?.preflight_evidence_ids)
|
|
785
|
+
? preflightMetadata.preflight_evidence_ids.filter((id) => typeof id === 'string')
|
|
786
|
+
: [];
|
|
787
|
+
if (preflightEvidenceIds.length > 0 && !preflightEvidenceIds.includes(input.id)) {
|
|
788
|
+
throw new Error(`memory id ${input.id} was not evidence for preflight_event_id ${input.preflightEventId}`);
|
|
789
|
+
}
|
|
790
|
+
const preflightActionKey = typeof preflightMetadata?.audrey_guard_action_key === 'string'
|
|
791
|
+
? preflightMetadata.audrey_guard_action_key
|
|
792
|
+
: undefined;
|
|
793
|
+
if (input.actionKey && preflightActionKey && input.actionKey !== preflightActionKey) {
|
|
794
|
+
throw new Error('action_key does not match the preflight event action key');
|
|
795
|
+
}
|
|
796
|
+
if (!input.actionKey && preflightActionKey) {
|
|
797
|
+
input = { ...input, actionKey: preflightActionKey };
|
|
798
|
+
}
|
|
799
|
+
if (!input.evidenceIds && preflightEvidenceIds.length > 0) {
|
|
800
|
+
input = { ...input, evidenceIds: preflightEvidenceIds };
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const result = applyFeedback(this.db, input);
|
|
804
|
+
if (result) {
|
|
805
|
+
// Audit row in memory_events so audrey impact can show
|
|
806
|
+
// helpful-vs-wrong breakdown over a window. Outcome is mapped onto the
|
|
807
|
+
// events-table enum: helpful → succeeded, wrong → failed, used → unknown.
|
|
808
|
+
// The original outcome string is preserved in metadata.
|
|
809
|
+
const eventOutcome = input.outcome === 'helpful' ? 'succeeded'
|
|
810
|
+
: input.outcome === 'wrong' ? 'failed'
|
|
811
|
+
: 'unknown';
|
|
812
|
+
insertEvent(this.db, {
|
|
813
|
+
eventType: 'Validate',
|
|
814
|
+
source: 'memory_validate',
|
|
815
|
+
actorAgent: this.agent,
|
|
816
|
+
outcome: eventOutcome,
|
|
817
|
+
redactionState: 'clean',
|
|
818
|
+
metadata: {
|
|
819
|
+
memory_id: result.id,
|
|
820
|
+
memory_type: result.type,
|
|
821
|
+
outcome: input.outcome,
|
|
822
|
+
salience_after: result.salience,
|
|
823
|
+
usage_count_after: result.usageCount,
|
|
824
|
+
...(input.preflightEventId ? { preflight_event_id: input.preflightEventId } : {}),
|
|
825
|
+
...(input.actionKey ? { audrey_guard_action_key: input.actionKey } : {}),
|
|
826
|
+
...(input.evidenceIds ? { preflight_evidence_ids: input.evidenceIds } : {}),
|
|
827
|
+
},
|
|
828
|
+
});
|
|
829
|
+
this.emit('validate', result);
|
|
830
|
+
}
|
|
831
|
+
return result;
|
|
832
|
+
}
|
|
833
|
+
impact(options = {}) {
|
|
834
|
+
return buildImpactReport(this.db, options.windowDays ?? 7, options.limit ?? 5);
|
|
835
|
+
}
|
|
439
836
|
forget(id, options = {}) {
|
|
440
837
|
const result = forgetMemory(this.db, id, options);
|
|
441
838
|
this.emit('forget', result);
|
|
@@ -458,10 +855,28 @@ export class Audrey extends EventEmitter {
|
|
|
458
855
|
return;
|
|
459
856
|
this._closed = true;
|
|
460
857
|
this.stopAutoConsolidate();
|
|
858
|
+
if (this._pendingPostEncodeIds.size > 0) {
|
|
859
|
+
// Sync close() can't await; emit a clear signal so callers can spot data loss.
|
|
860
|
+
// Use closeAsync() (preferred) or call drainPostEncodeQueue() before close() to avoid this.
|
|
861
|
+
console.error(`[audrey] close() called with ${this._pendingPostEncodeIds.size} pending post-encode tasks ` +
|
|
862
|
+
`(use closeAsync() or await drainPostEncodeQueue() first to avoid losing consolidation work)`);
|
|
863
|
+
}
|
|
461
864
|
closeDatabase(this.db);
|
|
462
865
|
}
|
|
866
|
+
async closeAsync(timeoutMs = 5000) {
|
|
867
|
+
if (this._closed)
|
|
868
|
+
return undefined;
|
|
869
|
+
let result;
|
|
870
|
+
if (this._pendingPostEncodeIds.size > 0) {
|
|
871
|
+
result = await this.drainPostEncodeQueue(timeoutMs);
|
|
872
|
+
}
|
|
873
|
+
this._closed = true;
|
|
874
|
+
this.stopAutoConsolidate();
|
|
875
|
+
closeDatabase(this.db);
|
|
876
|
+
return result;
|
|
877
|
+
}
|
|
463
878
|
async waitForIdle() {
|
|
464
|
-
|
|
879
|
+
await this._postEncodeQueue;
|
|
465
880
|
}
|
|
466
881
|
observeTool(input) {
|
|
467
882
|
const result = observeTool(this.db, {
|
|
@@ -490,6 +905,16 @@ export class Audrey extends EventEmitter {
|
|
|
490
905
|
this.emit('preflight', preflight);
|
|
491
906
|
return preflight;
|
|
492
907
|
}
|
|
908
|
+
async beforeAction(action, options = {}) {
|
|
909
|
+
const decision = await guardBeforeAction(this, action, options);
|
|
910
|
+
this.emit('guard-before', decision);
|
|
911
|
+
return decision;
|
|
912
|
+
}
|
|
913
|
+
afterAction(input) {
|
|
914
|
+
const outcome = guardAfterAction(this, input);
|
|
915
|
+
this.emit('guard-after', outcome);
|
|
916
|
+
return outcome;
|
|
917
|
+
}
|
|
493
918
|
async reflexes(action, options = {}) {
|
|
494
919
|
const report = await buildReflexReport(this, action, options);
|
|
495
920
|
this.emit('reflexes', report);
|
|
@@ -511,6 +936,28 @@ export class Audrey extends EventEmitter {
|
|
|
511
936
|
});
|
|
512
937
|
const dryRun = options.dryRun ?? !options.yes;
|
|
513
938
|
const projectDir = pathResolve(options.projectDir ?? process.cwd());
|
|
939
|
+
// Guard against malicious project_dir from MCP/HTTP callers writing
|
|
940
|
+
// .claude/rules/*.md to arbitrary locations — those files are read by
|
|
941
|
+
// Claude Code on the next session, making this a persistent
|
|
942
|
+
// prompt-injection vector. By default the path must be under cwd or one
|
|
943
|
+
// of the explicit AUDREY_PROMOTE_ROOTS entries.
|
|
944
|
+
if (!dryRun) {
|
|
945
|
+
const allowedRoots = [pathResolve(process.cwd())];
|
|
946
|
+
const extra = process.env.AUDREY_PROMOTE_ROOTS;
|
|
947
|
+
if (extra) {
|
|
948
|
+
for (const root of extra.split(/[:;]/).map(s => s.trim()).filter(Boolean)) {
|
|
949
|
+
allowedRoots.push(pathResolve(root));
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
const isUnderAllowedRoot = allowedRoots.some(root => {
|
|
953
|
+
const rel = relative(root, projectDir);
|
|
954
|
+
return rel === '' || (!rel.startsWith('..') && !pathIsAbsolute(rel));
|
|
955
|
+
});
|
|
956
|
+
if (!isUnderAllowedRoot) {
|
|
957
|
+
throw new Error(`promote: refusing to write to ${projectDir} — path is outside cwd and AUDREY_PROMOTE_ROOTS. ` +
|
|
958
|
+
`Set AUDREY_PROMOTE_ROOTS=<path1>:<path2> to allow additional locations.`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
514
961
|
const promotedAt = new Date().toISOString();
|
|
515
962
|
const docs = renderAllRules(candidates, promotedAt);
|
|
516
963
|
const applied = [];
|