audrey 1.0.1 → 1.0.3
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 +57 -0
- package/README.md +13 -3
- package/benchmarks/adapter-self-test.mjs +6 -2
- package/benchmarks/adapters/example-allow.mjs +5 -2
- package/benchmarks/adapters/mem0-platform.mjs +19 -12
- package/benchmarks/adapters/zep-cloud.mjs +51 -27
- package/benchmarks/baselines.js +11 -6
- package/benchmarks/build-leaderboard.mjs +36 -23
- package/benchmarks/cases.js +24 -12
- package/benchmarks/create-conformance-card.mjs +12 -3
- package/benchmarks/create-submission-bundle.mjs +22 -8
- package/benchmarks/dry-run-external-adapters.mjs +24 -12
- package/benchmarks/guardbench.js +263 -123
- package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +4 -4
- package/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
- package/benchmarks/output/external/guardbench-external-evidence.json +1 -1
- package/benchmarks/output/guardbench-conformance-card.json +12 -12
- package/benchmarks/output/guardbench-raw.json +106 -106
- package/benchmarks/output/guardbench-summary.json +168 -168
- package/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
- package/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
- package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +12 -12
- package/benchmarks/output/submission-bundle/guardbench-raw.json +106 -106
- package/benchmarks/output/submission-bundle/guardbench-summary.json +168 -168
- package/benchmarks/output/submission-bundle/submission-manifest.json +11 -11
- package/benchmarks/output/submission-bundle/validation-report.json +1 -1
- package/benchmarks/output/summary.json +58 -58
- package/benchmarks/perf-snapshot.js +12 -9
- package/benchmarks/perf.bench.js +14 -6
- package/benchmarks/public-paths.mjs +11 -5
- package/benchmarks/reference-results.js +10 -5
- package/benchmarks/report.js +48 -27
- package/benchmarks/run-external-guardbench.mjs +47 -25
- package/benchmarks/run.js +112 -59
- package/benchmarks/validate-adapter-module.mjs +13 -10
- package/benchmarks/validate-adapter-registry.mjs +16 -5
- package/benchmarks/validate-guardbench-artifacts.mjs +76 -19
- package/benchmarks/verify-external-evidence.mjs +86 -31
- package/benchmarks/verify-publication-artifacts.mjs +34 -11
- package/benchmarks/verify-submission-bundle.mjs +9 -4
- package/dist/mcp-server/config.d.ts +1 -1
- package/dist/mcp-server/config.d.ts.map +1 -1
- package/dist/mcp-server/config.js +5 -3
- package/dist/mcp-server/config.js.map +1 -1
- package/dist/mcp-server/index.d.ts +7 -347
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/index.js +289 -256
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/mcp-server/tool-schemas.d.ts +341 -0
- package/dist/mcp-server/tool-schemas.d.ts.map +1 -0
- package/dist/mcp-server/tool-schemas.js +248 -0
- package/dist/mcp-server/tool-schemas.js.map +1 -0
- package/dist/mcp-server/tool-validation.d.ts +17 -0
- package/dist/mcp-server/tool-validation.d.ts.map +1 -0
- package/dist/mcp-server/tool-validation.js +41 -0
- package/dist/mcp-server/tool-validation.js.map +1 -0
- package/dist/src/action-key.d.ts.map +1 -1
- package/dist/src/action-key.js +6 -2
- package/dist/src/action-key.js.map +1 -1
- package/dist/src/adaptive.d.ts.map +1 -1
- package/dist/src/adaptive.js +4 -2
- package/dist/src/adaptive.js.map +1 -1
- package/dist/src/affect.d.ts.map +1 -1
- package/dist/src/affect.js +8 -5
- package/dist/src/affect.js.map +1 -1
- package/dist/src/audrey.d.ts +1 -1
- package/dist/src/audrey.d.ts.map +1 -1
- package/dist/src/audrey.js +93 -49
- package/dist/src/audrey.js.map +1 -1
- package/dist/src/capsule.d.ts.map +1 -1
- package/dist/src/capsule.js +37 -15
- package/dist/src/capsule.js.map +1 -1
- package/dist/src/causal.d.ts +1 -1
- package/dist/src/causal.d.ts.map +1 -1
- package/dist/src/causal.js +4 -2
- package/dist/src/causal.js.map +1 -1
- package/dist/src/confidence.d.ts.map +1 -1
- package/dist/src/confidence.js +5 -5
- package/dist/src/confidence.js.map +1 -1
- package/dist/src/consolidate.d.ts.map +1 -1
- package/dist/src/consolidate.js +17 -9
- package/dist/src/consolidate.js.map +1 -1
- package/dist/src/context.js +1 -1
- package/dist/src/context.js.map +1 -1
- package/dist/src/controller.d.ts.map +1 -1
- package/dist/src/controller.js +24 -13
- package/dist/src/controller.js.map +1 -1
- package/dist/src/db.d.ts.map +1 -1
- package/dist/src/db.js +78 -27
- package/dist/src/db.js.map +1 -1
- package/dist/src/decay.d.ts +1 -1
- package/dist/src/decay.d.ts.map +1 -1
- package/dist/src/decay.js +1 -1
- package/dist/src/decay.js.map +1 -1
- package/dist/src/embedding.d.ts +12 -4
- package/dist/src/embedding.d.ts.map +1 -1
- package/dist/src/embedding.js +18 -16
- package/dist/src/embedding.js.map +1 -1
- package/dist/src/encode.d.ts.map +1 -1
- package/dist/src/encode.js +5 -4
- package/dist/src/encode.js.map +1 -1
- package/dist/src/events.d.ts +3 -2
- package/dist/src/events.d.ts.map +1 -1
- package/dist/src/events.js +7 -3
- package/dist/src/events.js.map +1 -1
- package/dist/src/export.d.ts.map +1 -1
- package/dist/src/export.js +21 -7
- package/dist/src/export.js.map +1 -1
- package/dist/src/feedback.d.ts.map +1 -1
- package/dist/src/feedback.js +1 -1
- package/dist/src/feedback.js.map +1 -1
- package/dist/src/forget.d.ts.map +1 -1
- package/dist/src/forget.js +12 -6
- package/dist/src/forget.js.map +1 -1
- package/dist/src/fts.d.ts.map +1 -1
- package/dist/src/fts.js +20 -8
- package/dist/src/fts.js.map +1 -1
- package/dist/src/hybrid-recall.d.ts.map +1 -1
- package/dist/src/hybrid-recall.js +12 -6
- package/dist/src/hybrid-recall.js.map +1 -1
- package/dist/src/impact.d.ts.map +1 -1
- package/dist/src/impact.js +26 -10
- package/dist/src/impact.js.map +1 -1
- package/dist/src/import.d.ts.map +1 -1
- package/dist/src/import.js +11 -6
- package/dist/src/import.js.map +1 -1
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/interference.d.ts.map +1 -1
- package/dist/src/interference.js +10 -5
- package/dist/src/interference.js.map +1 -1
- package/dist/src/introspect.d.ts.map +1 -1
- package/dist/src/introspect.js +12 -6
- package/dist/src/introspect.js.map +1 -1
- package/dist/src/llm.d.ts +2 -2
- package/dist/src/llm.d.ts.map +1 -1
- package/dist/src/llm.js +6 -6
- package/dist/src/llm.js.map +1 -1
- package/dist/src/migrate.d.ts.map +1 -1
- package/dist/src/migrate.js +10 -4
- package/dist/src/migrate.js.map +1 -1
- package/dist/src/preflight.d.ts.map +1 -1
- package/dist/src/preflight.js +6 -8
- package/dist/src/preflight.js.map +1 -1
- package/dist/src/profile.d.ts.map +1 -1
- package/dist/src/profile.js.map +1 -1
- package/dist/src/promote.d.ts.map +1 -1
- package/dist/src/promote.js +16 -7
- package/dist/src/promote.js.map +1 -1
- package/dist/src/prompts.d.ts.map +1 -1
- package/dist/src/prompts.js +1 -2
- package/dist/src/prompts.js.map +1 -1
- package/dist/src/recall.d.ts.map +1 -1
- package/dist/src/recall.js +85 -18
- package/dist/src/recall.js.map +1 -1
- package/dist/src/redact.d.ts.map +1 -1
- package/dist/src/redact.js +9 -4
- package/dist/src/redact.js.map +1 -1
- package/dist/src/reflexes.d.ts.map +1 -1
- package/dist/src/reflexes.js +1 -7
- package/dist/src/reflexes.js.map +1 -1
- package/dist/src/rollback.d.ts.map +1 -1
- package/dist/src/rollback.js +4 -2
- package/dist/src/rollback.js.map +1 -1
- package/dist/src/routes.d.ts.map +1 -1
- package/dist/src/routes.js +33 -13
- package/dist/src/routes.js.map +1 -1
- package/dist/src/rules-compiler.d.ts.map +1 -1
- package/dist/src/rules-compiler.js +24 -2
- package/dist/src/rules-compiler.js.map +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/server.js.map +1 -1
- package/dist/src/tool-trace.d.ts +2 -2
- package/dist/src/tool-trace.d.ts.map +1 -1
- package/dist/src/tool-trace.js +12 -4
- package/dist/src/tool-trace.js.map +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/ulid.js +1 -1
- package/dist/src/ulid.js.map +1 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js.map +1 -1
- package/dist/src/validate.d.ts.map +1 -1
- package/dist/src/validate.js +20 -10
- package/dist/src/validate.js.map +1 -1
- package/docs/paper/07-evaluation.md +5 -5
- package/docs/paper/audrey-paper-v1.md +5 -5
- package/docs/paper/evidence-ledger.md +1 -1
- package/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
- package/docs/paper/output/arxiv/main.tex +5 -5
- package/docs/paper/output/arxiv-compile-report.json +3 -3
- package/docs/paper/output/submission-bundle/README.md +13 -3
- package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +4 -4
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +1 -1
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +12 -12
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +106 -106
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +168 -168
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +11 -11
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +1 -1
- package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +64 -64
- package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +5 -5
- package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +5 -5
- package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +1 -1
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +5 -5
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +3 -3
- package/docs/paper/output/submission-bundle/package.json +17 -4
- package/docs/paper/output/submission-bundle/paper-submission-manifest.json +34 -34
- package/examples/fintech-ops-demo.js +12 -5
- package/examples/healthcare-ops-demo.js +8 -4
- package/examples/ollama-memory-agent.js +41 -13
- package/examples/stripe-demo.js +12 -5
- package/package.json +17 -4
- package/scripts/audit-release-completion.mjs +179 -101
- package/scripts/create-arxiv-source.mjs +20 -14
- package/scripts/create-paper-submission-bundle.mjs +6 -2
- package/scripts/finalize-release.mjs +111 -36
- package/scripts/prepare-release-cut.mjs +14 -6
- package/scripts/publish-release-bundle.mjs +62 -23
- package/scripts/publish-release-github-api.mjs +89 -24
- package/scripts/smoke-cli.js +9 -9
- package/scripts/sync-paper-artifacts.mjs +5 -1
- package/scripts/verify-arxiv-compile.mjs +52 -16
- package/scripts/verify-arxiv-source.mjs +45 -15
- package/scripts/verify-browser-launch-plan.mjs +28 -11
- package/scripts/verify-browser-launch-results.mjs +32 -14
- package/scripts/verify-paper-artifacts.mjs +539 -79
- package/scripts/verify-paper-claims.mjs +48 -20
- package/scripts/verify-paper-submission-bundle.mjs +22 -11
- package/scripts/verify-publication-pack.mjs +23 -9
- package/scripts/verify-release-readiness.mjs +211 -76
package/dist/mcp-server/index.js
CHANGED
|
@@ -2,150 +2,24 @@
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { homedir, platform, tmpdir } from 'node:os';
|
|
4
4
|
import { dirname, join, resolve } from 'node:path';
|
|
5
|
-
import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync, } from 'node:fs';
|
|
6
6
|
import { execFileSync } from 'node:child_process';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
8
|
import { Audrey, MemoryController } from '../src/index.js';
|
|
9
9
|
import { readStoredDimensions } from '../src/db.js';
|
|
10
|
-
import { importSnapshotSchema } from '../src/import.js';
|
|
11
10
|
import { isAudreyProfileEnabled } from '../src/profile.js';
|
|
12
11
|
import { VERSION, SERVER_NAME, MCP_ENTRYPOINT, buildAudreyConfig, buildInstallArgs, formatMcpHostConfig, resolveDataDir, resolveEmbeddingProvider, resolveLLMProvider, } from './config.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
];
|
|
20
|
-
const VALID_TYPES = ['episodic', 'semantic', 'procedural'];
|
|
21
|
-
export const MAX_MEMORY_CONTENT_LENGTH = 50_000;
|
|
22
|
-
export const ADMIN_TOOLS_ENV = 'AUDREY_ENABLE_ADMIN_TOOLS';
|
|
12
|
+
import { initializeEmbeddingProvider, requireAdminTools, validateForgetSelection, validateMemoryContent, } from './tool-validation.js';
|
|
13
|
+
import { memoryEncodeToolSchema, memoryForgetToolSchema, memoryGuardAfterToolSchema, memoryGuardBeforeToolSchema, memoryImportToolSchema, memoryPreflightToolSchema, memoryRecallToolSchema, memoryReflexesToolSchema, memoryValidateToolSchema, } from './tool-schemas.js';
|
|
14
|
+
// Re-export the tool-validation and tool-schema public surface so existing
|
|
15
|
+
// importers of `mcp-server/index.js` (tests, embedders) keep resolving.
|
|
16
|
+
export { ADMIN_TOOLS_ENV, MAX_MEMORY_CONTENT_LENGTH, initializeEmbeddingProvider, isAdminToolsEnabled, requireAdminTools, validateForgetSelection, validateMemoryContent, } from './tool-validation.js';
|
|
17
|
+
export * from './tool-schemas.js';
|
|
23
18
|
const subcommand = (process.argv[2] || '').trim() || undefined;
|
|
24
|
-
function isNonEmptyText(value) {
|
|
25
|
-
return typeof value === 'string' && value.trim().length > 0;
|
|
26
|
-
}
|
|
27
|
-
export function validateMemoryContent(content) {
|
|
28
|
-
if (!isNonEmptyText(content)) {
|
|
29
|
-
throw new Error('content must be a non-empty string');
|
|
30
|
-
}
|
|
31
|
-
if (content.length > MAX_MEMORY_CONTENT_LENGTH) {
|
|
32
|
-
throw new Error(`content exceeds maximum length of ${MAX_MEMORY_CONTENT_LENGTH} characters`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export function validateForgetSelection(id, query) {
|
|
36
|
-
if ((id && query) || (!id && !query)) {
|
|
37
|
-
throw new Error('Provide exactly one of id or query');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export function isAdminToolsEnabled(env = process.env) {
|
|
41
|
-
const value = env[ADMIN_TOOLS_ENV]?.toLowerCase();
|
|
42
|
-
return value === '1' || value === 'true' || value === 'yes';
|
|
43
|
-
}
|
|
44
|
-
export function requireAdminTools(env = process.env) {
|
|
45
|
-
if (!isAdminToolsEnabled(env)) {
|
|
46
|
-
throw new Error(`Admin memory tools are disabled. Set ${ADMIN_TOOLS_ENV}=1 to enable export, import, and forget operations.`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
export async function initializeEmbeddingProvider(provider) {
|
|
50
|
-
if (provider && typeof provider.ready === 'function') {
|
|
51
|
-
await provider.ready();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
19
|
function isEmbeddingWarmupDisabled(env = process.env) {
|
|
55
20
|
const value = env['AUDREY_DISABLE_WARMUP'];
|
|
56
21
|
return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';
|
|
57
22
|
}
|
|
58
|
-
export const memoryEncodeToolSchema = {
|
|
59
|
-
content: z.string()
|
|
60
|
-
.max(MAX_MEMORY_CONTENT_LENGTH)
|
|
61
|
-
.refine(isNonEmptyText, 'Content must not be empty')
|
|
62
|
-
.describe('The memory content to encode'),
|
|
63
|
-
source: z.enum(VALID_SOURCES).describe('Source type of the memory'),
|
|
64
|
-
tags: z.array(z.string()).optional().describe('Optional tags for categorization'),
|
|
65
|
-
salience: z.number().min(0).max(1).optional().describe('Importance weight 0-1'),
|
|
66
|
-
context: z.record(z.string(), z.string()).optional().describe('Situational context as key-value pairs (e.g., {task: "debugging", domain: "payments"})'),
|
|
67
|
-
affect: z.object({
|
|
68
|
-
valence: z.number().min(-1).max(1).describe('Emotional valence: -1 (very negative) to 1 (very positive)'),
|
|
69
|
-
arousal: z.number().min(0).max(1).optional().describe('Emotional arousal: 0 (calm) to 1 (highly activated)'),
|
|
70
|
-
label: z.string().optional().describe('Human-readable emotion label (e.g., "curiosity", "frustration", "relief")'),
|
|
71
|
-
}).optional().describe('Emotional affect - how this memory feels'),
|
|
72
|
-
private: z.boolean().optional().describe('If true, memory is only visible to the AI and excluded from public recall results'),
|
|
73
|
-
wait_for_consolidation: z.boolean().optional().describe('If true, wait for post-encode validation/interference/resonance work before returning. Defaults to false.'),
|
|
74
|
-
};
|
|
75
|
-
export const memoryRecallToolSchema = {
|
|
76
|
-
query: z.string().describe('Search query to match against memories'),
|
|
77
|
-
limit: z.number().min(1).max(50).optional().describe('Max results (default 10)'),
|
|
78
|
-
types: z.array(z.enum(VALID_TYPES)).optional().describe('Memory types to search'),
|
|
79
|
-
min_confidence: z.number().min(0).max(1).optional().describe('Minimum confidence threshold'),
|
|
80
|
-
tags: z.array(z.string()).optional().describe('Only return episodic memories with these tags'),
|
|
81
|
-
sources: z.array(z.enum(VALID_SOURCES)).optional().describe('Only return episodic memories from these sources'),
|
|
82
|
-
after: z.string().optional().describe('Only return memories created after this ISO date'),
|
|
83
|
-
before: z.string().optional().describe('Only return memories created before this ISO date'),
|
|
84
|
-
context: z.record(z.string(), z.string()).optional().describe('Retrieval context - memories encoded in matching context get boosted'),
|
|
85
|
-
mood: z.object({
|
|
86
|
-
valence: z.number().min(-1).max(1).describe('Current emotional valence: -1 (negative) to 1 (positive)'),
|
|
87
|
-
arousal: z.number().min(0).max(1).optional().describe('Current arousal: 0 (calm) to 1 (activated)'),
|
|
88
|
-
}).optional().describe('Current mood - boosts recall of memories encoded in similar emotional state'),
|
|
89
|
-
retrieval: z.enum(['hybrid', 'vector']).optional().describe('Retrieval strategy. hybrid is the default (vector + FTS/BM25 fusion); vector bypasses FTS for lower latency but loses lexical exact-match signal.'),
|
|
90
|
-
scope: z.enum(['agent', 'shared']).optional().describe('agent restricts recall to this MCP server agent identity. shared searches the whole store. Defaults to shared for backward compatibility.'),
|
|
91
|
-
};
|
|
92
|
-
export const memoryImportToolSchema = {
|
|
93
|
-
snapshot: importSnapshotSchema.describe('A validated snapshot from memory_export'),
|
|
94
|
-
};
|
|
95
|
-
export const memoryForgetToolSchema = {
|
|
96
|
-
id: z.string().optional().describe('ID of the memory to forget'),
|
|
97
|
-
query: z.string().optional().describe('Semantic query to find and forget the closest matching memory'),
|
|
98
|
-
min_similarity: z.number().min(0).max(1).optional().describe('Minimum similarity for query-based forget (default 0.9)'),
|
|
99
|
-
purge: z.boolean().optional().describe('Hard-delete the memory permanently (default false, soft-delete)'),
|
|
100
|
-
};
|
|
101
|
-
export const memoryValidateToolSchema = {
|
|
102
|
-
id: z.string().describe('ID of the memory to validate'),
|
|
103
|
-
outcome: z.enum(['used', 'helpful', 'wrong']).describe('How the memory played out: "used" (referenced without obvious value), "helpful" (drove a correct action — reinforces salience and retrieval), "wrong" (memory was misleading — bumps challenge_count and decreases salience).'),
|
|
104
|
-
};
|
|
105
|
-
export const memoryPreflightToolSchema = {
|
|
106
|
-
action: z.string()
|
|
107
|
-
.refine(isNonEmptyText, 'Action must not be empty')
|
|
108
|
-
.describe('Natural-language description of the action the agent is about to take.'),
|
|
109
|
-
tool: z.string().optional().describe('Tool or command family about to be used, e.g. Bash, npm test, Edit, deploy.'),
|
|
110
|
-
session_id: z.string().optional().describe('Session identifier for grouping the optional preflight event.'),
|
|
111
|
-
cwd: z.string().optional().describe('Working directory for the action.'),
|
|
112
|
-
files: z.array(z.string()).optional().describe('File paths to fingerprint if record_event is true.'),
|
|
113
|
-
strict: z.boolean().optional().describe('If true, high-severity memory warnings produce decision=block instead of caution.'),
|
|
114
|
-
limit: z.number().int().min(1).max(50).optional().describe('Max recall results to consider before preflight categorization.'),
|
|
115
|
-
budget_chars: z.number().int().min(200).max(32000).optional().describe('Capsule budget in characters.'),
|
|
116
|
-
mode: z.enum(['balanced', 'conservative', 'aggressive']).optional().describe('Underlying capsule mode. Defaults to conservative.'),
|
|
117
|
-
failure_window_hours: z.number().int().min(1).max(8760).optional().describe('How far back to check failed tool events. Defaults to 168 hours.'),
|
|
118
|
-
include_status: z.boolean().optional().describe('Include memory health in the response and warning calculation. Defaults to true.'),
|
|
119
|
-
record_event: z.boolean().optional().describe('Record a redacted PreToolUse event for this preflight. Defaults to false.'),
|
|
120
|
-
include_capsule: z.boolean().optional().describe('If false, omit the embedded Memory Capsule from the response.'),
|
|
121
|
-
scope: z.enum(['agent', 'shared']).optional().describe('agent restricts memory recall to this server agent identity. shared searches the whole store. Defaults to agent.'),
|
|
122
|
-
};
|
|
123
|
-
const { record_event: _preflightRecordEvent, ...memoryGuardBeforeFields } = memoryPreflightToolSchema;
|
|
124
|
-
export const memoryGuardBeforeToolSchema = {
|
|
125
|
-
...memoryGuardBeforeFields,
|
|
126
|
-
session_id: z.string().optional().describe('Session identifier for grouping the required guard receipt event.'),
|
|
127
|
-
files: z.array(z.string()).optional().describe('File paths to fingerprint in the required guard receipt.'),
|
|
128
|
-
};
|
|
129
|
-
export const memoryGuardAfterToolSchema = {
|
|
130
|
-
receipt_id: z.string()
|
|
131
|
-
.refine(isNonEmptyText, 'Receipt id must not be empty')
|
|
132
|
-
.describe('Receipt id returned by memory_guard_before.'),
|
|
133
|
-
tool: z.string().optional().describe('Tool or command family that completed, e.g. Bash, npm test, Edit, deploy.'),
|
|
134
|
-
session_id: z.string().optional().describe('Session identifier for grouping related guard events.'),
|
|
135
|
-
input: z.unknown().optional().describe('Tool input. Hashed and never stored raw; redacted metadata is only stored when retain_details is true.'),
|
|
136
|
-
output: z.unknown().optional().describe('Tool output. Same redaction and storage policy as input.'),
|
|
137
|
-
outcome: z.enum(['succeeded', 'failed', 'blocked', 'skipped', 'unknown']).optional().describe('Outcome classification'),
|
|
138
|
-
error_summary: z.string().optional().describe('Short error description if the action failed. Redacted and truncated to 2 KB.'),
|
|
139
|
-
cwd: z.string().optional().describe('Working directory at the time of the action.'),
|
|
140
|
-
files: z.array(z.string()).optional().describe('File paths to fingerprint (size + mtime + content hash).'),
|
|
141
|
-
metadata: z.record(z.string(), z.unknown()).optional().describe('Arbitrary structured metadata (redacted before storage).'),
|
|
142
|
-
retain_details: z.boolean().optional().describe('If true, redacted input and output payloads are stored alongside hashes. Defaults to false.'),
|
|
143
|
-
evidence_feedback: z.record(z.string(), z.enum(['used', 'helpful', 'wrong'])).optional().describe('Map of evidence ids from the guard receipt to memory validation outcomes.'),
|
|
144
|
-
};
|
|
145
|
-
export const memoryReflexesToolSchema = {
|
|
146
|
-
...memoryPreflightToolSchema,
|
|
147
|
-
include_preflight: z.boolean().optional().describe('If true, include the full underlying preflight report.'),
|
|
148
|
-
};
|
|
149
23
|
// ---------------------------------------------------------------------------
|
|
150
24
|
// CLI subcommands
|
|
151
25
|
// ---------------------------------------------------------------------------
|
|
@@ -160,7 +34,9 @@ async function serveHttp() {
|
|
|
160
34
|
if (apiKey) {
|
|
161
35
|
console.error('[audrey-http] API key authentication enabled');
|
|
162
36
|
}
|
|
163
|
-
else if (server.hostname === '127.0.0.1' ||
|
|
37
|
+
else if (server.hostname === '127.0.0.1' ||
|
|
38
|
+
server.hostname === '::1' ||
|
|
39
|
+
server.hostname === 'localhost') {
|
|
164
40
|
console.error('[audrey-http] no API key set (loopback only — set AUDREY_API_KEY to enable network access)');
|
|
165
41
|
}
|
|
166
42
|
}
|
|
@@ -178,7 +54,9 @@ async function reembed() {
|
|
|
178
54
|
try {
|
|
179
55
|
await initializeEmbeddingProvider(audrey.embeddingProvider);
|
|
180
56
|
const { reembedAll } = await import('../src/migrate.js');
|
|
181
|
-
const counts = await reembedAll(audrey.db, audrey.embeddingProvider, {
|
|
57
|
+
const counts = await reembedAll(audrey.db, audrey.embeddingProvider, {
|
|
58
|
+
dropAndRecreate: dimensionsChanged,
|
|
59
|
+
});
|
|
182
60
|
console.log(`Done. Re-embedded: ${counts.episodes} episodes, ${counts.semantics} semantics, ${counts.procedures} procedures`);
|
|
183
61
|
}
|
|
184
62
|
finally {
|
|
@@ -208,13 +86,13 @@ async function dream() {
|
|
|
208
86
|
console.log(`[audrey] Embedding: ${embeddingLabel}`);
|
|
209
87
|
const result = await audrey.dream();
|
|
210
88
|
const health = audrey.memoryStatus();
|
|
211
|
-
console.log(`[audrey] Consolidation: evaluated ${result.consolidation.episodesEvaluated} episodes, `
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
console.log(`[audrey] Decay: evaluated ${result.decay.totalEvaluated} memories, `
|
|
215
|
-
|
|
216
|
-
console.log(`[audrey] Final: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ${result.stats.procedural} procedural `
|
|
217
|
-
|
|
89
|
+
console.log(`[audrey] Consolidation: evaluated ${result.consolidation.episodesEvaluated} episodes, ` +
|
|
90
|
+
`found ${result.consolidation.clustersFound} clusters, extracted ${result.consolidation.principlesExtracted} principles ` +
|
|
91
|
+
`(${result.consolidation.semanticsCreated ?? 0} semantic, ${result.consolidation.proceduresCreated ?? 0} procedural)`);
|
|
92
|
+
console.log(`[audrey] Decay: evaluated ${result.decay.totalEvaluated} memories, ` +
|
|
93
|
+
`${result.decay.transitionedToDormant} transitioned to dormant`);
|
|
94
|
+
console.log(`[audrey] Final: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ${result.stats.procedural} procedural ` +
|
|
95
|
+
`| ${health.healthy ? 'healthy' : 'unhealthy'}`);
|
|
218
96
|
console.log('[audrey] Dream complete.');
|
|
219
97
|
}
|
|
220
98
|
finally {
|
|
@@ -257,9 +135,9 @@ async function greeting() {
|
|
|
257
135
|
}
|
|
258
136
|
const storedDimensions = readStoredDimensions(dataDir);
|
|
259
137
|
const resolvedEmbedding = resolveEmbeddingProvider(process.env, process.env['AUDREY_EMBEDDING_PROVIDER']);
|
|
260
|
-
const canUseResolvedEmbedding = Boolean(contextArg)
|
|
261
|
-
|
|
262
|
-
|
|
138
|
+
const canUseResolvedEmbedding = Boolean(contextArg) &&
|
|
139
|
+
storedDimensions !== null &&
|
|
140
|
+
storedDimensions === resolvedEmbedding.dimensions;
|
|
263
141
|
const dimensions = storedDimensions || resolvedEmbedding.dimensions || 8;
|
|
264
142
|
const audrey = new Audrey({
|
|
265
143
|
dataDir,
|
|
@@ -272,28 +150,30 @@ async function greeting() {
|
|
|
272
150
|
if (canUseResolvedEmbedding) {
|
|
273
151
|
await initializeEmbeddingProvider(audrey.embeddingProvider);
|
|
274
152
|
}
|
|
275
|
-
const result = await audrey.greeting({
|
|
153
|
+
const result = await audrey.greeting({
|
|
154
|
+
context: canUseResolvedEmbedding ? contextArg : undefined,
|
|
155
|
+
});
|
|
276
156
|
const health = audrey.memoryStatus();
|
|
277
157
|
const lines = [];
|
|
278
158
|
lines.push(`[Audrey v${VERSION}] Memory briefing`);
|
|
279
159
|
lines.push('');
|
|
280
160
|
if (contextArg && !canUseResolvedEmbedding) {
|
|
281
|
-
lines.push(`Context recall skipped: stored index is ${storedDimensions ?? 'unknown'}d `
|
|
282
|
-
|
|
161
|
+
lines.push(`Context recall skipped: stored index is ${storedDimensions ?? 'unknown'}d ` +
|
|
162
|
+
`but current embedding config resolves to ${resolvedEmbedding.dimensions}d.`);
|
|
283
163
|
lines.push('');
|
|
284
164
|
}
|
|
285
165
|
// Mood
|
|
286
166
|
if (result.mood && result.mood.samples > 0) {
|
|
287
167
|
const v = result.mood.valence;
|
|
288
168
|
const moodWord = v > 0.3 ? 'positive' : v < -0.3 ? 'negative' : 'neutral';
|
|
289
|
-
lines.push(`Mood: ${moodWord} (valence=${v.toFixed(2)}, `
|
|
290
|
-
|
|
291
|
-
|
|
169
|
+
lines.push(`Mood: ${moodWord} (valence=${v.toFixed(2)}, ` +
|
|
170
|
+
`arousal=${result.mood.arousal.toFixed(2)}, ` +
|
|
171
|
+
`from ${result.mood.samples} recent memories)`);
|
|
292
172
|
}
|
|
293
173
|
// Health
|
|
294
174
|
const stats = audrey.introspect();
|
|
295
|
-
lines.push(`Memory: ${stats.episodic} episodic, ${stats.semantic} semantic, `
|
|
296
|
-
|
|
175
|
+
lines.push(`Memory: ${stats.episodic} episodic, ${stats.semantic} semantic, ` +
|
|
176
|
+
`${stats.procedural} procedural | ${health.healthy ? 'healthy' : 'needs attention'}`);
|
|
297
177
|
lines.push('');
|
|
298
178
|
// Principles (semantic memories)
|
|
299
179
|
if (result.principles?.length > 0) {
|
|
@@ -398,12 +278,12 @@ async function reflect() {
|
|
|
398
278
|
// Always run dream cycle after reflect
|
|
399
279
|
console.log('[audrey] Starting dream cycle...');
|
|
400
280
|
const result = await audrey.dream();
|
|
401
|
-
console.log(`[audrey] Consolidation: ${result.consolidation.episodesEvaluated} episodes evaluated, `
|
|
402
|
-
|
|
403
|
-
console.log(`[audrey] Decay: ${result.decay.totalEvaluated} evaluated, `
|
|
404
|
-
|
|
405
|
-
console.log(`[audrey] Status: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, `
|
|
406
|
-
|
|
281
|
+
console.log(`[audrey] Consolidation: ${result.consolidation.episodesEvaluated} episodes evaluated, ` +
|
|
282
|
+
`${result.consolidation.clustersFound} clusters, ${result.consolidation.principlesExtracted} principles`);
|
|
283
|
+
console.log(`[audrey] Decay: ${result.decay.totalEvaluated} evaluated, ` +
|
|
284
|
+
`${result.decay.transitionedToDormant} dormant`);
|
|
285
|
+
console.log(`[audrey] Status: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ` +
|
|
286
|
+
`${result.stats.procedural} procedural`);
|
|
407
287
|
console.log('[audrey] Dream complete.');
|
|
408
288
|
}
|
|
409
289
|
finally {
|
|
@@ -449,11 +329,7 @@ export function formatInstallGuide(host, env = process.env, dryRun = false) {
|
|
|
449
329
|
formatMcpHostConfig(normalizedHost, env),
|
|
450
330
|
'',
|
|
451
331
|
...(normalizedHost === 'claude-code'
|
|
452
|
-
? [
|
|
453
|
-
'Generated Claude Code hook config:',
|
|
454
|
-
formatClaudeCodeHookConfig(),
|
|
455
|
-
'',
|
|
456
|
-
]
|
|
332
|
+
? ['Generated Claude Code hook config:', formatClaudeCodeHookConfig(), '']
|
|
457
333
|
: []),
|
|
458
334
|
'Next steps:',
|
|
459
335
|
];
|
|
@@ -643,8 +519,12 @@ function printHookConfig() {
|
|
|
643
519
|
dryRun: options.dryRun,
|
|
644
520
|
});
|
|
645
521
|
const action = result.dryRun
|
|
646
|
-
? result.changed
|
|
647
|
-
|
|
522
|
+
? result.changed
|
|
523
|
+
? 'would update'
|
|
524
|
+
: 'would leave unchanged'
|
|
525
|
+
: result.changed
|
|
526
|
+
? 'updated'
|
|
527
|
+
: 'already up to date';
|
|
648
528
|
console.log(`[audrey] Claude Code hook settings ${action}: ${result.settingsPath}`);
|
|
649
529
|
if (result.backupPath)
|
|
650
530
|
console.log(`[audrey] backup written: ${result.backupPath}`);
|
|
@@ -826,7 +706,9 @@ export function applyClaudeCodeHookConfig(options) {
|
|
|
826
706
|
}
|
|
827
707
|
catch (err) {
|
|
828
708
|
const message = err instanceof Error ? err.message : String(err);
|
|
829
|
-
throw new Error(`Cannot merge Audrey hooks into invalid JSON at ${settingsPath}: ${message}
|
|
709
|
+
throw new Error(`Cannot merge Audrey hooks into invalid JSON at ${settingsPath}: ${message}`, {
|
|
710
|
+
cause: err,
|
|
711
|
+
});
|
|
830
712
|
}
|
|
831
713
|
}
|
|
832
714
|
const settings = mergeClaudeCodeHookSettings(existing);
|
|
@@ -875,11 +757,7 @@ function demoScenario(argv = process.argv) {
|
|
|
875
757
|
return cliValue('--scenario', argv);
|
|
876
758
|
}
|
|
877
759
|
function formatControllerGuardResult(result) {
|
|
878
|
-
const label = result.decision === 'block'
|
|
879
|
-
? 'BLOCKED'
|
|
880
|
-
: result.decision === 'warn'
|
|
881
|
-
? 'WARN'
|
|
882
|
-
: 'ALLOW';
|
|
760
|
+
const label = result.decision === 'block' ? 'BLOCKED' : result.decision === 'warn' ? 'WARN' : 'ALLOW';
|
|
883
761
|
const lines = [];
|
|
884
762
|
lines.push(`Audrey Guard: ${label}`);
|
|
885
763
|
lines.push('');
|
|
@@ -992,8 +870,8 @@ export async function runDemoCommand({ out = console.log, keep = process.argv.in
|
|
|
992
870
|
tags: ['procedure', 'memory-capsule', 'agent-loop'],
|
|
993
871
|
}));
|
|
994
872
|
ids.push(await audrey.encode({
|
|
995
|
-
content: 'If a host cannot auto-install Audrey, run npx audrey mcp-config codex '
|
|
996
|
-
|
|
873
|
+
content: 'If a host cannot auto-install Audrey, run npx audrey mcp-config codex ' +
|
|
874
|
+
'or npx audrey mcp-config generic and paste the generated config.',
|
|
997
875
|
source: 'direct-observation',
|
|
998
876
|
tags: ['procedure', 'mcp', 'first-contact'],
|
|
999
877
|
}));
|
|
@@ -1011,8 +889,8 @@ export async function runDemoCommand({ out = console.log, keep = process.argv.in
|
|
|
1011
889
|
event: 'PostToolUse',
|
|
1012
890
|
tool: 'npm test',
|
|
1013
891
|
outcome: 'failed',
|
|
1014
|
-
errorSummary: 'Vitest can fail with spawn EPERM on locked-down Windows hosts; '
|
|
1015
|
-
|
|
892
|
+
errorSummary: 'Vitest can fail with spawn EPERM on locked-down Windows hosts; ' +
|
|
893
|
+
'use build, typecheck, benchmarks, and direct dist smokes as the fallback evidence path.',
|
|
1016
894
|
cwd: process.cwd(),
|
|
1017
895
|
metadata: { demo: true, source: 'audrey demo' },
|
|
1018
896
|
});
|
|
@@ -1118,12 +996,15 @@ export function buildStatusReport({ dataDir = resolveDataDir(process.env), claud
|
|
|
1118
996
|
});
|
|
1119
997
|
report.stats = audrey.introspect();
|
|
1120
998
|
report.health = audrey.memoryStatus();
|
|
1121
|
-
report.lastConsolidation =
|
|
999
|
+
report.lastConsolidation =
|
|
1000
|
+
audrey.db
|
|
1001
|
+
.prepare(`
|
|
1122
1002
|
SELECT completed_at FROM consolidation_runs
|
|
1123
1003
|
WHERE status = 'completed'
|
|
1124
1004
|
ORDER BY completed_at DESC
|
|
1125
1005
|
LIMIT 1
|
|
1126
|
-
`)
|
|
1006
|
+
`)
|
|
1007
|
+
.get()?.completed_at ?? 'never';
|
|
1127
1008
|
audrey.close();
|
|
1128
1009
|
}
|
|
1129
1010
|
catch (err) {
|
|
@@ -1145,11 +1026,11 @@ export function formatStatusReport(report) {
|
|
|
1145
1026
|
lines.push(`Data directory: ${report.dataDir}`);
|
|
1146
1027
|
lines.push(`Stored dimensions: ${report.storedDimensions ?? 'unknown'}`);
|
|
1147
1028
|
lines.push(`Memories: ${report.stats.episodic} episodic, ${report.stats.semantic} semantic, ${report.stats.procedural} procedural`);
|
|
1148
|
-
lines.push(`Index sync: ${report.health.vec_episodes}/${report.health.searchable_episodes} episodic, `
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
lines.push(`Health: ${report.health.healthy ? 'healthy' : 'unhealthy'}`
|
|
1152
|
-
|
|
1029
|
+
lines.push(`Index sync: ${report.health.vec_episodes}/${report.health.searchable_episodes} episodic, ` +
|
|
1030
|
+
`${report.health.vec_semantics}/${report.health.searchable_semantics} semantic, ` +
|
|
1031
|
+
`${report.health.vec_procedures}/${report.health.searchable_procedures} procedural`);
|
|
1032
|
+
lines.push(`Health: ${report.health.healthy ? 'healthy' : 'unhealthy'}` +
|
|
1033
|
+
`${report.health.reembed_recommended ? ' (re-embed recommended)' : ''}`);
|
|
1153
1034
|
lines.push(`Dormant: ${report.stats.dormant}`);
|
|
1154
1035
|
lines.push(`Causal links: ${report.stats.causalLinks}`);
|
|
1155
1036
|
lines.push(`Contradictions: ${report.stats.contradictions.open} open, ${report.stats.contradictions.resolved} resolved`);
|
|
@@ -1165,8 +1046,11 @@ export function runStatusCommand({ argv = process.argv, dataDir = resolveDataDir
|
|
|
1165
1046
|
else {
|
|
1166
1047
|
out(formatStatusReport(report));
|
|
1167
1048
|
}
|
|
1168
|
-
const exitCode = report.error
|
|
1169
|
-
|
|
1049
|
+
const exitCode = report.error ||
|
|
1050
|
+
(cliHasFlag('--fail-on-unhealthy', argv) &&
|
|
1051
|
+
report.exists &&
|
|
1052
|
+
report.health &&
|
|
1053
|
+
!report.health.healthy)
|
|
1170
1054
|
? 1
|
|
1171
1055
|
: 0;
|
|
1172
1056
|
return { report, exitCode };
|
|
@@ -1319,23 +1203,30 @@ function toolResult(data, diagnostics) {
|
|
|
1319
1203
|
return result;
|
|
1320
1204
|
}
|
|
1321
1205
|
function toolError(err) {
|
|
1322
|
-
return {
|
|
1206
|
+
return {
|
|
1207
|
+
isError: true,
|
|
1208
|
+
content: [{ type: 'text', text: `Error: ${err.message || String(err)}` }],
|
|
1209
|
+
};
|
|
1323
1210
|
}
|
|
1324
1211
|
function jsonResource(uri, data) {
|
|
1325
1212
|
return {
|
|
1326
|
-
contents: [
|
|
1213
|
+
contents: [
|
|
1214
|
+
{
|
|
1327
1215
|
uri: uri.toString(),
|
|
1328
1216
|
mimeType: 'application/json',
|
|
1329
1217
|
text: JSON.stringify(data, null, 2),
|
|
1330
|
-
}
|
|
1218
|
+
},
|
|
1219
|
+
],
|
|
1331
1220
|
};
|
|
1332
1221
|
}
|
|
1333
1222
|
function promptText(text) {
|
|
1334
1223
|
return {
|
|
1335
|
-
messages: [
|
|
1224
|
+
messages: [
|
|
1225
|
+
{
|
|
1336
1226
|
role: 'user',
|
|
1337
1227
|
content: { type: 'text', text },
|
|
1338
|
-
}
|
|
1228
|
+
},
|
|
1229
|
+
],
|
|
1339
1230
|
};
|
|
1340
1231
|
}
|
|
1341
1232
|
export function registerShutdownHandlers(processRef, audrey, logger = console.error) {
|
|
@@ -1350,8 +1241,8 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
|
|
|
1350
1241
|
if (typeof audrey.drainPostEncodeQueue === 'function') {
|
|
1351
1242
|
const drain = await audrey.drainPostEncodeQueue(5000);
|
|
1352
1243
|
if (!drain.drained && drain.pendingIds.length > 0) {
|
|
1353
|
-
logger(`[audrey-mcp] post-encode queue did not drain within 5000ms; `
|
|
1354
|
-
|
|
1244
|
+
logger(`[audrey-mcp] post-encode queue did not drain within 5000ms; ` +
|
|
1245
|
+
`pending ids: ${drain.pendingIds.join(', ')}`);
|
|
1355
1246
|
}
|
|
1356
1247
|
}
|
|
1357
1248
|
audrey.close();
|
|
@@ -1365,9 +1256,15 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
|
|
|
1365
1256
|
processRef.exit(exitCode);
|
|
1366
1257
|
}
|
|
1367
1258
|
};
|
|
1368
|
-
processRef.once('SIGINT', () => {
|
|
1369
|
-
|
|
1370
|
-
|
|
1259
|
+
processRef.once('SIGINT', () => {
|
|
1260
|
+
void shutdown('[audrey-mcp] received SIGINT, shutting down');
|
|
1261
|
+
});
|
|
1262
|
+
processRef.once('SIGTERM', () => {
|
|
1263
|
+
void shutdown('[audrey-mcp] received SIGTERM, shutting down');
|
|
1264
|
+
});
|
|
1265
|
+
processRef.once('SIGHUP', () => {
|
|
1266
|
+
void shutdown('[audrey-mcp] received SIGHUP, shutting down');
|
|
1267
|
+
});
|
|
1371
1268
|
processRef.once('uncaughtException', (err) => {
|
|
1372
1269
|
logger('[audrey-mcp] uncaught exception:', err);
|
|
1373
1270
|
void shutdown(undefined, 1);
|
|
@@ -1381,13 +1278,20 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
|
|
|
1381
1278
|
});
|
|
1382
1279
|
return (message, exitCode = 0) => shutdown(message, exitCode);
|
|
1383
1280
|
}
|
|
1384
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1385
1281
|
export function registerDreamTool(server, audrey) {
|
|
1386
1282
|
server.tool('memory_dream', {
|
|
1387
1283
|
min_cluster_size: z.number().optional().describe('Minimum episodes per cluster (default 3)'),
|
|
1388
|
-
similarity_threshold: z
|
|
1389
|
-
|
|
1390
|
-
|
|
1284
|
+
similarity_threshold: z
|
|
1285
|
+
.number()
|
|
1286
|
+
.optional()
|
|
1287
|
+
.describe('Similarity threshold for clustering (default 0.85)'),
|
|
1288
|
+
dormant_threshold: z
|
|
1289
|
+
.number()
|
|
1290
|
+
.min(0)
|
|
1291
|
+
.max(1)
|
|
1292
|
+
.optional()
|
|
1293
|
+
.describe('Confidence below which memories go dormant (default 0.1)'),
|
|
1294
|
+
}, async ({ min_cluster_size, similarity_threshold, dormant_threshold, }) => {
|
|
1391
1295
|
try {
|
|
1392
1296
|
const result = await audrey.dream({
|
|
1393
1297
|
minClusterSize: min_cluster_size,
|
|
@@ -1401,7 +1305,6 @@ export function registerDreamTool(server, audrey) {
|
|
|
1401
1305
|
}
|
|
1402
1306
|
});
|
|
1403
1307
|
}
|
|
1404
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1405
1308
|
export function registerHostResources(server, audrey) {
|
|
1406
1309
|
server.registerResource('audrey-status', 'audrey://status', {
|
|
1407
1310
|
title: 'Audrey Status',
|
|
@@ -1448,7 +1351,6 @@ export function registerHostResources(server, audrey) {
|
|
|
1448
1351
|
});
|
|
1449
1352
|
});
|
|
1450
1353
|
}
|
|
1451
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1452
1354
|
export function registerHostPrompts(server) {
|
|
1453
1355
|
server.registerPrompt('audrey-session-briefing', {
|
|
1454
1356
|
title: 'Audrey Session Briefing',
|
|
@@ -1476,13 +1378,18 @@ export function registerHostPrompts(server) {
|
|
|
1476
1378
|
title: 'Audrey Memory Reflection',
|
|
1477
1379
|
description: 'Reflect at the end of a meaningful session and encode durable lessons.',
|
|
1478
1380
|
argsSchema: {
|
|
1479
|
-
summary: z
|
|
1381
|
+
summary: z
|
|
1382
|
+
.string()
|
|
1383
|
+
.optional()
|
|
1384
|
+
.describe('Optional compact summary of the session to reflect on.'),
|
|
1480
1385
|
},
|
|
1481
1386
|
}, ({ summary }) => promptText([
|
|
1482
1387
|
'Call memory_reflect with the important user and assistant turns from this session.',
|
|
1483
1388
|
'Encode only durable preferences, decisions, fixes, failures, and project facts that should affect future work.',
|
|
1484
1389
|
summary ? `Session summary hint: ${summary}` : undefined,
|
|
1485
|
-
]
|
|
1390
|
+
]
|
|
1391
|
+
.filter(Boolean)
|
|
1392
|
+
.join('\n')));
|
|
1486
1393
|
}
|
|
1487
1394
|
async function main() {
|
|
1488
1395
|
const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
|
|
@@ -1626,7 +1533,10 @@ async function main() {
|
|
|
1626
1533
|
purge: purge ?? false,
|
|
1627
1534
|
});
|
|
1628
1535
|
if (!result) {
|
|
1629
|
-
return toolResult({
|
|
1536
|
+
return toolResult({
|
|
1537
|
+
forgotten: false,
|
|
1538
|
+
reason: 'No memory found above similarity threshold',
|
|
1539
|
+
});
|
|
1630
1540
|
}
|
|
1631
1541
|
}
|
|
1632
1542
|
return toolResult({ forgotten: true, ...result });
|
|
@@ -1647,7 +1557,12 @@ async function main() {
|
|
|
1647
1557
|
}
|
|
1648
1558
|
});
|
|
1649
1559
|
server.tool('memory_decay', {
|
|
1650
|
-
dormant_threshold: z
|
|
1560
|
+
dormant_threshold: z
|
|
1561
|
+
.number()
|
|
1562
|
+
.min(0)
|
|
1563
|
+
.max(1)
|
|
1564
|
+
.optional()
|
|
1565
|
+
.describe('Confidence below which memories go dormant (default 0.1)'),
|
|
1651
1566
|
}, async ({ dormant_threshold }) => {
|
|
1652
1567
|
try {
|
|
1653
1568
|
return toolResult(audrey.decay({ dormantThreshold: dormant_threshold }));
|
|
@@ -1665,10 +1580,12 @@ async function main() {
|
|
|
1665
1580
|
}
|
|
1666
1581
|
});
|
|
1667
1582
|
server.tool('memory_reflect', {
|
|
1668
|
-
turns: z
|
|
1583
|
+
turns: z
|
|
1584
|
+
.array(z.object({
|
|
1669
1585
|
role: z.string().describe('Message role: user or assistant'),
|
|
1670
1586
|
content: z.string().describe('Message content'),
|
|
1671
|
-
}))
|
|
1587
|
+
}))
|
|
1588
|
+
.describe('Conversation turns to reflect on. Call at end of meaningful conversations to form lasting memories.'),
|
|
1672
1589
|
}, async ({ turns }) => {
|
|
1673
1590
|
try {
|
|
1674
1591
|
return toolResult(await audrey.reflect(turns));
|
|
@@ -1679,8 +1596,14 @@ async function main() {
|
|
|
1679
1596
|
});
|
|
1680
1597
|
registerDreamTool(server, audrey);
|
|
1681
1598
|
server.tool('memory_greeting', {
|
|
1682
|
-
context: z
|
|
1683
|
-
|
|
1599
|
+
context: z
|
|
1600
|
+
.string()
|
|
1601
|
+
.optional()
|
|
1602
|
+
.describe('Optional hint about this session. When provided, Audrey also returns semantically relevant memories.'),
|
|
1603
|
+
scope: z
|
|
1604
|
+
.enum(['agent', 'shared'])
|
|
1605
|
+
.optional()
|
|
1606
|
+
.describe('agent keeps greeting scoped to this server agent identity. shared includes the whole store. Defaults to agent.'),
|
|
1684
1607
|
}, async ({ context, scope }) => {
|
|
1685
1608
|
try {
|
|
1686
1609
|
return toolResult(await audrey.greeting({ context, scope: scope ?? 'agent' }));
|
|
@@ -1690,17 +1613,40 @@ async function main() {
|
|
|
1690
1613
|
}
|
|
1691
1614
|
});
|
|
1692
1615
|
server.tool('memory_observe_tool', {
|
|
1693
|
-
event: z
|
|
1616
|
+
event: z
|
|
1617
|
+
.string()
|
|
1618
|
+
.describe('Hook event name (PreToolUse, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, etc.)'),
|
|
1694
1619
|
tool: z.string().describe('Tool name being observed (Bash, Edit, Write, etc.)'),
|
|
1695
1620
|
session_id: z.string().optional().describe('Session identifier for grouping related events'),
|
|
1696
|
-
input: z
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1621
|
+
input: z
|
|
1622
|
+
.unknown()
|
|
1623
|
+
.optional()
|
|
1624
|
+
.describe('Tool input. Hashed and never stored raw; redacted metadata is only stored when retain_details is true.'),
|
|
1625
|
+
output: z
|
|
1626
|
+
.unknown()
|
|
1627
|
+
.optional()
|
|
1628
|
+
.describe('Tool output. Same redaction and storage policy as input.'),
|
|
1629
|
+
outcome: z
|
|
1630
|
+
.enum(['succeeded', 'failed', 'blocked', 'skipped', 'unknown'])
|
|
1631
|
+
.optional()
|
|
1632
|
+
.describe('Outcome classification'),
|
|
1633
|
+
error_summary: z
|
|
1634
|
+
.string()
|
|
1635
|
+
.optional()
|
|
1636
|
+
.describe('Short error description if the tool failed. Redacted and truncated to 2 KB.'),
|
|
1700
1637
|
cwd: z.string().optional().describe('Working directory at the time of the tool call'),
|
|
1701
|
-
files: z
|
|
1702
|
-
|
|
1703
|
-
|
|
1638
|
+
files: z
|
|
1639
|
+
.array(z.string())
|
|
1640
|
+
.optional()
|
|
1641
|
+
.describe('File paths to fingerprint (size + mtime + content hash)'),
|
|
1642
|
+
metadata: z
|
|
1643
|
+
.record(z.string(), z.unknown())
|
|
1644
|
+
.optional()
|
|
1645
|
+
.describe('Arbitrary structured metadata (redacted before storage)'),
|
|
1646
|
+
retain_details: z
|
|
1647
|
+
.boolean()
|
|
1648
|
+
.optional()
|
|
1649
|
+
.describe('If true, redacted input and output payloads are stored alongside hashes. Defaults to false.'),
|
|
1704
1650
|
}, async ({ event, tool, session_id, input, output, outcome, error_summary, cwd, files, metadata, retain_details, }) => {
|
|
1705
1651
|
try {
|
|
1706
1652
|
const result = audrey.observeTool({
|
|
@@ -1732,7 +1678,13 @@ async function main() {
|
|
|
1732
1678
|
});
|
|
1733
1679
|
server.tool('memory_recent_failures', {
|
|
1734
1680
|
since: z.string().optional().describe('ISO timestamp lower bound (defaults to 7 days ago)'),
|
|
1735
|
-
limit: z
|
|
1681
|
+
limit: z
|
|
1682
|
+
.number()
|
|
1683
|
+
.int()
|
|
1684
|
+
.min(1)
|
|
1685
|
+
.max(200)
|
|
1686
|
+
.optional()
|
|
1687
|
+
.describe('Max rows to return (defaults to 20)'),
|
|
1736
1688
|
}, async ({ since, limit }) => {
|
|
1737
1689
|
try {
|
|
1738
1690
|
return toolResult(audrey.recentFailures({ since, limit }));
|
|
@@ -1743,13 +1695,43 @@ async function main() {
|
|
|
1743
1695
|
});
|
|
1744
1696
|
server.tool('memory_capsule', {
|
|
1745
1697
|
query: z.string().describe('Natural-language query for the turn. Drives what gets surfaced.'),
|
|
1746
|
-
limit: z
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1698
|
+
limit: z
|
|
1699
|
+
.number()
|
|
1700
|
+
.int()
|
|
1701
|
+
.min(1)
|
|
1702
|
+
.max(50)
|
|
1703
|
+
.optional()
|
|
1704
|
+
.describe('Max recall results to consider before categorization.'),
|
|
1705
|
+
budget_chars: z
|
|
1706
|
+
.number()
|
|
1707
|
+
.int()
|
|
1708
|
+
.min(200)
|
|
1709
|
+
.max(32000)
|
|
1710
|
+
.optional()
|
|
1711
|
+
.describe('Token budget in characters (defaults to AUDREY_CONTEXT_BUDGET_CHARS or 4000).'),
|
|
1712
|
+
mode: z
|
|
1713
|
+
.enum(['balanced', 'conservative', 'aggressive'])
|
|
1714
|
+
.optional()
|
|
1715
|
+
.describe('Capsule mode: conservative = fewer, higher-confidence entries; aggressive = broader sweep.'),
|
|
1716
|
+
recent_change_window_hours: z
|
|
1717
|
+
.number()
|
|
1718
|
+
.int()
|
|
1719
|
+
.min(1)
|
|
1720
|
+
.max(720)
|
|
1721
|
+
.optional()
|
|
1722
|
+
.describe('How far back "recent_changes" looks (default 24h).'),
|
|
1723
|
+
include_risks: z
|
|
1724
|
+
.boolean()
|
|
1725
|
+
.optional()
|
|
1726
|
+
.describe('Include recent tool failures as risks (default true).'),
|
|
1727
|
+
include_contradictions: z
|
|
1728
|
+
.boolean()
|
|
1729
|
+
.optional()
|
|
1730
|
+
.describe('Include open contradictions (default true).'),
|
|
1731
|
+
scope: z
|
|
1732
|
+
.enum(['agent', 'shared'])
|
|
1733
|
+
.optional()
|
|
1734
|
+
.describe('agent restricts memory recall to this MCP server agent identity. shared searches the whole store. Defaults to agent.'),
|
|
1753
1735
|
}, async ({ query, limit, budget_chars, mode, recent_change_window_hours, include_risks, include_contradictions, scope, }) => {
|
|
1754
1736
|
try {
|
|
1755
1737
|
const capsule = await audrey.capsule(query, {
|
|
@@ -1860,14 +1842,42 @@ async function main() {
|
|
|
1860
1842
|
}
|
|
1861
1843
|
});
|
|
1862
1844
|
server.tool('memory_promote', {
|
|
1863
|
-
target: z
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1845
|
+
target: z
|
|
1846
|
+
.enum(['claude-rules'])
|
|
1847
|
+
.optional()
|
|
1848
|
+
.describe('Promotion target. Only claude-rules is implemented in PR 4 v1.'),
|
|
1849
|
+
min_confidence: z
|
|
1850
|
+
.number()
|
|
1851
|
+
.min(0)
|
|
1852
|
+
.max(1)
|
|
1853
|
+
.optional()
|
|
1854
|
+
.describe('Minimum memory confidence for promotion (default 0.7 for procedural, 0.8 for semantic).'),
|
|
1855
|
+
min_evidence: z
|
|
1856
|
+
.number()
|
|
1857
|
+
.int()
|
|
1858
|
+
.min(1)
|
|
1859
|
+
.optional()
|
|
1860
|
+
.describe('Minimum supporting episode count (default 2).'),
|
|
1861
|
+
limit: z
|
|
1862
|
+
.number()
|
|
1863
|
+
.int()
|
|
1864
|
+
.min(1)
|
|
1865
|
+
.max(50)
|
|
1866
|
+
.optional()
|
|
1867
|
+
.describe('Max candidates to return/apply (default 20).'),
|
|
1868
|
+
dry_run: z
|
|
1869
|
+
.boolean()
|
|
1870
|
+
.optional()
|
|
1871
|
+
.describe('If true (default), return candidates without writing. Pair with yes=true to actually write.'),
|
|
1872
|
+
yes: z
|
|
1873
|
+
.boolean()
|
|
1874
|
+
.optional()
|
|
1875
|
+
.describe('Confirm write. Without this or dry_run=false the command stays in dry-run mode.'),
|
|
1876
|
+
project_dir: z
|
|
1877
|
+
.string()
|
|
1878
|
+
.optional()
|
|
1879
|
+
.describe('Absolute path to the project root where .claude/rules/ should be created. Defaults to process.cwd().'),
|
|
1880
|
+
}, async ({ target, min_confidence, min_evidence, limit, dry_run, yes, project_dir }) => {
|
|
1871
1881
|
try {
|
|
1872
1882
|
const result = await audrey.promote({
|
|
1873
1883
|
target,
|
|
@@ -1890,7 +1900,8 @@ async function main() {
|
|
|
1890
1900
|
console.error('[audrey-mcp] connected via stdio');
|
|
1891
1901
|
}
|
|
1892
1902
|
if (!isEmbeddingWarmupDisabled(process.env)) {
|
|
1893
|
-
void audrey
|
|
1903
|
+
void audrey
|
|
1904
|
+
.startEmbeddingWarmup()
|
|
1894
1905
|
.then(() => {
|
|
1895
1906
|
if (process.env.AUDREY_DEBUG === '1') {
|
|
1896
1907
|
const status = audrey.memoryStatus();
|
|
@@ -1925,7 +1936,10 @@ function parseObserveToolArgs(argv) {
|
|
|
1925
1936
|
else if (token === '--files') {
|
|
1926
1937
|
const list = next();
|
|
1927
1938
|
if (list)
|
|
1928
|
-
out.files = list
|
|
1939
|
+
out.files = list
|
|
1940
|
+
.split(',')
|
|
1941
|
+
.map(s => s.trim())
|
|
1942
|
+
.filter(Boolean);
|
|
1929
1943
|
}
|
|
1930
1944
|
else if (token === '--input-json')
|
|
1931
1945
|
out.inputJson = next();
|
|
@@ -1980,13 +1994,11 @@ async function observeToolCli() {
|
|
|
1980
1994
|
};
|
|
1981
1995
|
const inputPayload = args.inputJson !== undefined
|
|
1982
1996
|
? parseMaybeJson(args.inputJson)
|
|
1983
|
-
: stdinPayload?.tool_input ?? stdinPayload?.input;
|
|
1997
|
+
: (stdinPayload?.tool_input ?? stdinPayload?.input);
|
|
1984
1998
|
const outputPayload = args.outputJson !== undefined
|
|
1985
1999
|
? parseMaybeJson(args.outputJson)
|
|
1986
|
-
: stdinPayload?.tool_response ?? stdinPayload?.tool_output ?? stdinPayload?.output;
|
|
1987
|
-
const metadataPayload = args.metadataJson !== undefined
|
|
1988
|
-
? parseMaybeJson(args.metadataJson)
|
|
1989
|
-
: stdinPayload?.metadata;
|
|
2000
|
+
: (stdinPayload?.tool_response ?? stdinPayload?.tool_output ?? stdinPayload?.output);
|
|
2001
|
+
const metadataPayload = args.metadataJson !== undefined ? parseMaybeJson(args.metadataJson) : stdinPayload?.metadata;
|
|
1990
2002
|
const sessionId = args.sessionId ?? stdinPayload?.session_id;
|
|
1991
2003
|
const cwd = args.cwd ?? stdinPayload?.cwd;
|
|
1992
2004
|
// Detect failure from Claude Code hook payload shape: tool_response often
|
|
@@ -2124,7 +2136,7 @@ function guardDisplayDecision(result) {
|
|
|
2124
2136
|
return 'allow';
|
|
2125
2137
|
}
|
|
2126
2138
|
function summarizeToolInput(payload, tool) {
|
|
2127
|
-
const input =
|
|
2139
|
+
const input = payload.tool_input && typeof payload.tool_input === 'object'
|
|
2128
2140
|
? payload.tool_input
|
|
2129
2141
|
: {};
|
|
2130
2142
|
const command = typeof input.command === 'string' ? input.command : undefined;
|
|
@@ -2139,9 +2151,7 @@ function summarizeToolInput(payload, tool) {
|
|
|
2139
2151
|
return { action: `${tool}: ${description}`, files };
|
|
2140
2152
|
const compactInput = JSON.stringify(input);
|
|
2141
2153
|
return {
|
|
2142
|
-
action: compactInput && compactInput !== '{}'
|
|
2143
|
-
? `${tool} ${compactInput}`
|
|
2144
|
-
: `Use ${tool}`,
|
|
2154
|
+
action: compactInput && compactInput !== '{}' ? `${tool} ${compactInput}` : `Use ${tool}`,
|
|
2145
2155
|
files,
|
|
2146
2156
|
};
|
|
2147
2157
|
}
|
|
@@ -2160,7 +2170,9 @@ function formatHookReason(result) {
|
|
|
2160
2170
|
result.summary,
|
|
2161
2171
|
recommendations.length > 0 ? `Recommended: ${recommendations.join(' ')}` : '',
|
|
2162
2172
|
result.evidence_ids.length > 0 ? `Evidence: ${result.evidence_ids.slice(0, 5).join(', ')}` : '',
|
|
2163
|
-
]
|
|
2173
|
+
]
|
|
2174
|
+
.filter(Boolean)
|
|
2175
|
+
.join('\n');
|
|
2164
2176
|
}
|
|
2165
2177
|
function formatPreToolUseHookOutput(result, failOnWarn) {
|
|
2166
2178
|
const decision = guardDisplayDecision(result);
|
|
@@ -2253,7 +2265,11 @@ async function guardCli() {
|
|
|
2253
2265
|
tool: hookTool ?? args.tool,
|
|
2254
2266
|
sessionId: args.sessionId ?? hookSessionId,
|
|
2255
2267
|
cwd: args.cwd ?? hookCwd ?? process.cwd(),
|
|
2256
|
-
files: args.files.length > 0
|
|
2268
|
+
files: args.files.length > 0
|
|
2269
|
+
? args.files
|
|
2270
|
+
: hookSummary?.files?.length
|
|
2271
|
+
? hookSummary.files
|
|
2272
|
+
: undefined,
|
|
2257
2273
|
strict: args.strict || args.failOnWarn || args.hook,
|
|
2258
2274
|
recordEvent: true,
|
|
2259
2275
|
includeCapsule: args.includeCapsule || args.explain,
|
|
@@ -2268,7 +2284,9 @@ async function guardCli() {
|
|
|
2268
2284
|
console.log(formatGuardDecision(result, { explain: args.explain }));
|
|
2269
2285
|
}
|
|
2270
2286
|
const display = guardDisplayDecision(result);
|
|
2271
|
-
if (!args.hook &&
|
|
2287
|
+
if (!args.hook &&
|
|
2288
|
+
(display === 'block' || (args.failOnWarn && display === 'warn')) &&
|
|
2289
|
+
!args.override) {
|
|
2272
2290
|
process.exitCode = 2;
|
|
2273
2291
|
}
|
|
2274
2292
|
}
|
|
@@ -2314,9 +2332,9 @@ async function readOptionalJsonFromStdin(command) {
|
|
|
2314
2332
|
}
|
|
2315
2333
|
}
|
|
2316
2334
|
function inferGuardAfterOutcome(stdinPayload) {
|
|
2317
|
-
const response = stdinPayload?.tool_response
|
|
2318
|
-
|
|
2319
|
-
|
|
2335
|
+
const response = stdinPayload?.tool_response ??
|
|
2336
|
+
stdinPayload?.tool_output ??
|
|
2337
|
+
stdinPayload?.output;
|
|
2320
2338
|
const success = response?.success;
|
|
2321
2339
|
if (typeof success === 'boolean')
|
|
2322
2340
|
return success ? 'succeeded' : 'failed';
|
|
@@ -2433,8 +2451,8 @@ async function promoteCli() {
|
|
|
2433
2451
|
const snippet = c.content.length > 120 ? c.content.slice(0, 117) + '...' : c.content;
|
|
2434
2452
|
console.log(` memory: ${snippet}`);
|
|
2435
2453
|
console.log(` why: ${c.reason}`);
|
|
2436
|
-
console.log(` confidence=${(c.confidence * 100).toFixed(1)}% `
|
|
2437
|
-
|
|
2454
|
+
console.log(` confidence=${(c.confidence * 100).toFixed(1)}% ` +
|
|
2455
|
+
`evidence=${c.evidence_count} prevented_failures=${c.failure_prevented}`);
|
|
2438
2456
|
}
|
|
2439
2457
|
if (result.dry_run) {
|
|
2440
2458
|
console.log('');
|
|
@@ -2454,11 +2472,26 @@ function canonicalEntryPath(path) {
|
|
|
2454
2472
|
return resolved.toLowerCase();
|
|
2455
2473
|
}
|
|
2456
2474
|
}
|
|
2457
|
-
const isDirectRun = Boolean(process.argv[1])
|
|
2458
|
-
|
|
2475
|
+
const isDirectRun = Boolean(process.argv[1]) &&
|
|
2476
|
+
canonicalEntryPath(process.argv[1]) === canonicalEntryPath(fileURLToPath(import.meta.url));
|
|
2459
2477
|
const KNOWN_SUBCOMMANDS = [
|
|
2460
|
-
'install',
|
|
2461
|
-
'
|
|
2478
|
+
'install',
|
|
2479
|
+
'uninstall',
|
|
2480
|
+
'mcp-config',
|
|
2481
|
+
'hook-config',
|
|
2482
|
+
'demo',
|
|
2483
|
+
'reembed',
|
|
2484
|
+
'dream',
|
|
2485
|
+
'greeting',
|
|
2486
|
+
'reflect',
|
|
2487
|
+
'serve',
|
|
2488
|
+
'status',
|
|
2489
|
+
'doctor',
|
|
2490
|
+
'observe-tool',
|
|
2491
|
+
'guard',
|
|
2492
|
+
'guard-after',
|
|
2493
|
+
'promote',
|
|
2494
|
+
'impact',
|
|
2462
2495
|
];
|
|
2463
2496
|
function printHelp() {
|
|
2464
2497
|
process.stdout.write(`audrey ${VERSION} — local-first memory runtime for AI agents
|