audrey 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/causal.js CHANGED
@@ -1,95 +1,95 @@
1
- import { generateId } from './ulid.js';
2
- import { buildCausalArticulationPrompt } from './prompts.js';
3
-
4
- /**
5
- * @param {import('better-sqlite3').Database} db
6
- * @param {{ causeId: string, effectId: string, linkType?: string, mechanism?: string, confidence?: number }} params
7
- * @returns {string}
8
- */
9
- export function addCausalLink(db, { causeId, effectId, linkType = 'causal', mechanism, confidence }) {
10
- const id = generateId();
11
- const now = new Date().toISOString();
12
-
13
- db.prepare(`
14
- INSERT INTO causal_links (id, cause_id, effect_id, link_type, mechanism, confidence, created_at)
15
- VALUES (?, ?, ?, ?, ?, ?, ?)
16
- `).run(id, causeId, effectId, linkType, mechanism, confidence, now);
17
-
18
- return id;
19
- }
20
-
21
- /**
22
- * @param {import('better-sqlite3').Database} db
23
- * @param {string} memoryId
24
- * @param {{ depth?: number }} [options]
25
- * @returns {Object[]}
26
- */
27
- export function getCausalChain(db, memoryId, options = {}) {
28
- const { depth = 10 } = options;
29
- const results = [];
30
- const visited = new Set();
31
- const queue = [memoryId];
32
- let currentDepth = 0;
33
-
34
- while (queue.length > 0 && currentDepth < depth) {
35
- const nextQueue = [];
36
- for (const nodeId of queue) {
37
- if (visited.has(nodeId)) continue;
38
- visited.add(nodeId);
39
-
40
- const links = db.prepare(
41
- 'SELECT * FROM causal_links WHERE cause_id = ?'
42
- ).all(nodeId);
43
-
44
- for (const link of links) {
45
- if (!visited.has(link.effect_id)) {
46
- results.push(link);
47
- nextQueue.push(link.effect_id);
48
- }
49
- }
50
- }
51
- queue.length = 0;
52
- queue.push(...nextQueue);
53
- currentDepth++;
54
- }
55
-
56
- return results;
57
- }
58
-
59
- /**
60
- * @param {import('better-sqlite3').Database} db
61
- * @param {import('./llm.js').LLMProvider} llmProvider
62
- * @param {{ id: string, content: string, source: string }} cause
63
- * @param {{ id: string, content: string, source: string }} effect
64
- * @returns {Promise<{ linkId: string|null, mechanism: string, linkType: string, confidence: number, spurious: boolean }>}
65
- */
66
- export async function articulateCausalLink(db, llmProvider, cause, effect) {
67
- const messages = buildCausalArticulationPrompt(cause, effect);
68
- const result = await llmProvider.json(messages);
69
-
70
- if (result.spurious) {
71
- return {
72
- linkId: null,
73
- mechanism: result.mechanism,
74
- linkType: result.linkType,
75
- confidence: result.confidence,
76
- spurious: true,
77
- };
78
- }
79
-
80
- const linkId = addCausalLink(db, {
81
- causeId: cause.id,
82
- effectId: effect.id,
83
- linkType: result.linkType || 'correlational',
84
- mechanism: result.mechanism,
85
- confidence: result.confidence,
86
- });
87
-
88
- return {
89
- linkId,
90
- mechanism: result.mechanism,
91
- linkType: result.linkType,
92
- confidence: result.confidence,
93
- spurious: false,
94
- };
95
- }
1
+ import { generateId } from './ulid.js';
2
+ import { buildCausalArticulationPrompt } from './prompts.js';
3
+
4
+ /**
5
+ * @param {import('better-sqlite3').Database} db
6
+ * @param {{ causeId: string, effectId: string, linkType?: string, mechanism?: string, confidence?: number }} params
7
+ * @returns {string}
8
+ */
9
+ export function addCausalLink(db, { causeId, effectId, linkType = 'causal', mechanism, confidence }) {
10
+ const id = generateId();
11
+ const now = new Date().toISOString();
12
+
13
+ db.prepare(`
14
+ INSERT INTO causal_links (id, cause_id, effect_id, link_type, mechanism, confidence, created_at)
15
+ VALUES (?, ?, ?, ?, ?, ?, ?)
16
+ `).run(id, causeId, effectId, linkType, mechanism, confidence, now);
17
+
18
+ return id;
19
+ }
20
+
21
+ /**
22
+ * @param {import('better-sqlite3').Database} db
23
+ * @param {string} memoryId
24
+ * @param {{ depth?: number }} [options]
25
+ * @returns {Object[]}
26
+ */
27
+ export function getCausalChain(db, memoryId, options = {}) {
28
+ const { depth = 10 } = options;
29
+ const results = [];
30
+ const visited = new Set();
31
+ const queue = [memoryId];
32
+ let currentDepth = 0;
33
+
34
+ while (queue.length > 0 && currentDepth < depth) {
35
+ const nextQueue = [];
36
+ for (const nodeId of queue) {
37
+ if (visited.has(nodeId)) continue;
38
+ visited.add(nodeId);
39
+
40
+ const links = db.prepare(
41
+ 'SELECT * FROM causal_links WHERE cause_id = ?'
42
+ ).all(nodeId);
43
+
44
+ for (const link of links) {
45
+ if (!visited.has(link.effect_id)) {
46
+ results.push(link);
47
+ nextQueue.push(link.effect_id);
48
+ }
49
+ }
50
+ }
51
+ queue.length = 0;
52
+ queue.push(...nextQueue);
53
+ currentDepth++;
54
+ }
55
+
56
+ return results;
57
+ }
58
+
59
+ /**
60
+ * @param {import('better-sqlite3').Database} db
61
+ * @param {import('./llm.js').LLMProvider} llmProvider
62
+ * @param {{ id: string, content: string, source: string }} cause
63
+ * @param {{ id: string, content: string, source: string }} effect
64
+ * @returns {Promise<{ linkId: string|null, mechanism: string, linkType: string, confidence: number, spurious: boolean }>}
65
+ */
66
+ export async function articulateCausalLink(db, llmProvider, cause, effect) {
67
+ const messages = buildCausalArticulationPrompt(cause, effect);
68
+ const result = await llmProvider.json(messages);
69
+
70
+ if (result.spurious) {
71
+ return {
72
+ linkId: null,
73
+ mechanism: result.mechanism,
74
+ linkType: result.linkType,
75
+ confidence: result.confidence,
76
+ spurious: true,
77
+ };
78
+ }
79
+
80
+ const linkId = addCausalLink(db, {
81
+ causeId: cause.id,
82
+ effectId: effect.id,
83
+ linkType: result.linkType || 'correlational',
84
+ mechanism: result.mechanism,
85
+ confidence: result.confidence,
86
+ });
87
+
88
+ return {
89
+ linkId,
90
+ mechanism: result.mechanism,
91
+ linkType: result.linkType,
92
+ confidence: result.confidence,
93
+ spurious: false,
94
+ };
95
+ }
package/src/confidence.js CHANGED
@@ -1,120 +1,120 @@
1
- /** @type {Record<string, number>} */
2
- export const DEFAULT_SOURCE_RELIABILITY = {
3
- 'direct-observation': 0.95,
4
- 'told-by-user': 0.90,
5
- 'tool-result': 0.85,
6
- 'inference': 0.60,
7
- 'model-generated': 0.40,
8
- };
9
-
10
- /** @type {{ source: number, evidence: number, recency: number, retrieval: number }} */
11
- export const DEFAULT_WEIGHTS = {
12
- source: 0.30,
13
- evidence: 0.35,
14
- recency: 0.20,
15
- retrieval: 0.15,
16
- };
17
-
18
- /** @type {{ episodic: number, semantic: number, procedural: number }} */
19
- export const DEFAULT_HALF_LIVES = {
20
- episodic: 7,
21
- semantic: 30,
22
- procedural: 90,
23
- };
24
-
25
- /** @type {number} */
26
- export const MODEL_GENERATED_CONFIDENCE_CAP = 0.6;
27
-
28
- /**
29
- * @param {string} sourceType
30
- * @param {Record<string, number>} [customReliability]
31
- * @returns {number}
32
- */
33
- export function sourceReliability(sourceType, customReliability) {
34
- const table = customReliability || DEFAULT_SOURCE_RELIABILITY;
35
- const value = table[sourceType];
36
- if (value === undefined) {
37
- throw new Error(`Unknown source type: ${sourceType}. Valid types: ${Object.keys(table).join(', ')}`);
38
- }
39
- return value;
40
- }
41
-
42
- /**
43
- * @param {number} supportingCount
44
- * @param {number} contradictingCount
45
- * @returns {number}
46
- */
47
- export function evidenceAgreement(supportingCount, contradictingCount) {
48
- const total = supportingCount + contradictingCount;
49
- if (total === 0) return 1.0;
50
- return supportingCount / total;
51
- }
52
-
53
- /**
54
- * @param {number} ageDays
55
- * @param {number} halfLifeDays
56
- * @returns {number}
57
- */
58
- export function recencyDecay(ageDays, halfLifeDays) {
59
- const lambda = Math.LN2 / halfLifeDays;
60
- return Math.exp(-lambda * ageDays);
61
- }
62
-
63
- /**
64
- * @param {number} retrievalCount
65
- * @param {number} daysSinceRetrieval
66
- * @returns {number}
67
- */
68
- export function retrievalReinforcement(retrievalCount, daysSinceRetrieval) {
69
- if (retrievalCount === 0) return 0;
70
- const lambdaRet = Math.LN2 / 14;
71
- const baseReinforcement = 0.3 * Math.log(1 + retrievalCount);
72
- const recencyWeight = Math.exp(-lambdaRet * daysSinceRetrieval);
73
- const spacedBonus = Math.min(0.15, 0.02 * Math.log(1 + daysSinceRetrieval));
74
- return Math.min(1.0, baseReinforcement * recencyWeight + spacedBonus);
75
- }
76
-
77
- export function salienceModifier(salience) {
78
- const s = salience ?? 0.5;
79
- return 0.5 + s;
80
- }
81
-
82
- /**
83
- * @param {object} params
84
- * @param {string} params.sourceType
85
- * @param {number} params.supportingCount
86
- * @param {number} params.contradictingCount
87
- * @param {number} params.ageDays
88
- * @param {number} params.halfLifeDays
89
- * @param {number} params.retrievalCount
90
- * @param {number} params.daysSinceRetrieval
91
- * @param {{ source: number, evidence: number, recency: number, retrieval: number }} [params.weights]
92
- * @param {Record<string, number>} [params.customSourceReliability]
93
- * @returns {number}
94
- */
95
- export function computeConfidence({
96
- sourceType,
97
- supportingCount,
98
- contradictingCount,
99
- ageDays,
100
- halfLifeDays,
101
- retrievalCount,
102
- daysSinceRetrieval,
103
- weights,
104
- customSourceReliability,
105
- }) {
106
- const w = weights || DEFAULT_WEIGHTS;
107
-
108
- const s = sourceReliability(sourceType, customSourceReliability);
109
- const e = evidenceAgreement(supportingCount, contradictingCount);
110
- const r = recencyDecay(ageDays, halfLifeDays);
111
- const ret = retrievalReinforcement(retrievalCount, daysSinceRetrieval);
112
-
113
- let confidence = w.source * s + w.evidence * e + w.recency * r + w.retrieval * ret;
114
-
115
- if (sourceType === 'model-generated') {
116
- confidence = Math.min(confidence, MODEL_GENERATED_CONFIDENCE_CAP);
117
- }
118
-
119
- return Math.max(0, Math.min(1, confidence));
120
- }
1
+ /** @type {Record<string, number>} */
2
+ export const DEFAULT_SOURCE_RELIABILITY = {
3
+ 'direct-observation': 0.95,
4
+ 'told-by-user': 0.90,
5
+ 'tool-result': 0.85,
6
+ 'inference': 0.60,
7
+ 'model-generated': 0.40,
8
+ };
9
+
10
+ /** @type {{ source: number, evidence: number, recency: number, retrieval: number }} */
11
+ export const DEFAULT_WEIGHTS = {
12
+ source: 0.30,
13
+ evidence: 0.35,
14
+ recency: 0.20,
15
+ retrieval: 0.15,
16
+ };
17
+
18
+ /** @type {{ episodic: number, semantic: number, procedural: number }} */
19
+ export const DEFAULT_HALF_LIVES = {
20
+ episodic: 7,
21
+ semantic: 30,
22
+ procedural: 90,
23
+ };
24
+
25
+ /** @type {number} */
26
+ export const MODEL_GENERATED_CONFIDENCE_CAP = 0.6;
27
+
28
+ /**
29
+ * @param {string} sourceType
30
+ * @param {Record<string, number>} [customReliability]
31
+ * @returns {number}
32
+ */
33
+ export function sourceReliability(sourceType, customReliability) {
34
+ const table = customReliability || DEFAULT_SOURCE_RELIABILITY;
35
+ const value = table[sourceType];
36
+ if (value === undefined) {
37
+ throw new Error(`Unknown source type: ${sourceType}. Valid types: ${Object.keys(table).join(', ')}`);
38
+ }
39
+ return value;
40
+ }
41
+
42
+ /**
43
+ * @param {number} supportingCount
44
+ * @param {number} contradictingCount
45
+ * @returns {number}
46
+ */
47
+ export function evidenceAgreement(supportingCount, contradictingCount) {
48
+ const total = supportingCount + contradictingCount;
49
+ if (total === 0) return 1.0;
50
+ return supportingCount / total;
51
+ }
52
+
53
+ /**
54
+ * @param {number} ageDays
55
+ * @param {number} halfLifeDays
56
+ * @returns {number}
57
+ */
58
+ export function recencyDecay(ageDays, halfLifeDays) {
59
+ const lambda = Math.LN2 / halfLifeDays;
60
+ return Math.exp(-lambda * ageDays);
61
+ }
62
+
63
+ /**
64
+ * @param {number} retrievalCount
65
+ * @param {number} daysSinceRetrieval
66
+ * @returns {number}
67
+ */
68
+ export function retrievalReinforcement(retrievalCount, daysSinceRetrieval) {
69
+ if (retrievalCount === 0) return 0;
70
+ const lambdaRet = Math.LN2 / 14;
71
+ const baseReinforcement = 0.3 * Math.log(1 + retrievalCount);
72
+ const recencyWeight = Math.exp(-lambdaRet * daysSinceRetrieval);
73
+ const spacedBonus = Math.min(0.15, 0.02 * Math.log(1 + daysSinceRetrieval));
74
+ return Math.min(1.0, baseReinforcement * recencyWeight + spacedBonus);
75
+ }
76
+
77
+ export function salienceModifier(salience) {
78
+ const s = salience ?? 0.5;
79
+ return 0.5 + s;
80
+ }
81
+
82
+ /**
83
+ * @param {object} params
84
+ * @param {string} params.sourceType
85
+ * @param {number} params.supportingCount
86
+ * @param {number} params.contradictingCount
87
+ * @param {number} params.ageDays
88
+ * @param {number} params.halfLifeDays
89
+ * @param {number} params.retrievalCount
90
+ * @param {number} params.daysSinceRetrieval
91
+ * @param {{ source: number, evidence: number, recency: number, retrieval: number }} [params.weights]
92
+ * @param {Record<string, number>} [params.customSourceReliability]
93
+ * @returns {number}
94
+ */
95
+ export function computeConfidence({
96
+ sourceType,
97
+ supportingCount,
98
+ contradictingCount,
99
+ ageDays,
100
+ halfLifeDays,
101
+ retrievalCount,
102
+ daysSinceRetrieval,
103
+ weights,
104
+ customSourceReliability,
105
+ }) {
106
+ const w = weights || DEFAULT_WEIGHTS;
107
+
108
+ const s = sourceReliability(sourceType, customSourceReliability);
109
+ const e = evidenceAgreement(supportingCount, contradictingCount);
110
+ const r = recencyDecay(ageDays, halfLifeDays);
111
+ const ret = retrievalReinforcement(retrievalCount, daysSinceRetrieval);
112
+
113
+ let confidence = w.source * s + w.evidence * e + w.recency * r + w.retrieval * ret;
114
+
115
+ if (sourceType === 'model-generated') {
116
+ confidence = Math.min(confidence, MODEL_GENERATED_CONFIDENCE_CAP);
117
+ }
118
+
119
+ return Math.max(0, Math.min(1, confidence));
120
+ }