agent-working-memory 0.9.0 → 0.9.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/dist/cli/migrate.js +29 -29
- package/dist/cli.js +6 -2
- package/dist/cli.js.map +1 -1
- package/dist/coordination/circuit-breaker.js +23 -23
- package/dist/storage/pglite-schema.js +143 -143
- package/dist/storage/pglite.js +138 -138
- package/package.json +1 -1
- package/src/api/index.ts +3 -3
- package/src/cli/migrate.ts +307 -307
- package/src/cli.ts +6 -2
- package/src/coordination/circuit-breaker.ts +83 -83
- package/src/coordination/failure-modes.ts +50 -50
- package/src/core/decay.ts +63 -63
- package/src/core/embeddings.ts +110 -110
- package/src/core/index.ts +5 -5
- package/src/core/logger.ts +36 -36
- package/src/core/ml-worker-entry.ts +194 -194
- package/src/core/ml-worker.ts +281 -281
- package/src/core/query-expander.ts +122 -122
- package/src/core/reranker.ts +119 -119
- package/src/engine/confidence.ts +120 -120
- package/src/engine/consolidation-scheduler.ts +242 -242
- package/src/engine/eval.ts +102 -102
- package/src/engine/eviction.ts +101 -101
- package/src/engine/index.ts +8 -8
- package/src/engine/retraction.ts +366 -366
- package/src/engine/staging.ts +74 -74
- package/src/storage/factory.ts +147 -147
- package/src/storage/index.ts +3 -3
- package/src/storage/pglite-schema.ts +166 -166
- package/src/storage/pglite.ts +1363 -1363
- package/src/storage/store.ts +80 -80
- package/src/types/agent.ts +67 -67
- package/src/types/checkpoint.ts +46 -46
- package/src/types/eval.ts +100 -100
- package/src/types/index.ts +6 -6
package/src/engine/confidence.ts
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
// Copyright 2026 Robert Winter / Complete Ideas
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
/**
|
|
4
|
-
* Retrieval confidence — score-distribution-aware signal that complements
|
|
5
|
-
* the per-result `score`. The shape of the result set carries information
|
|
6
|
-
* the raw scores do not:
|
|
7
|
-
*
|
|
8
|
-
* - Confident recall: top-1 dominates, sharp cliff, non-trivial floor.
|
|
9
|
-
* - Noisy recall: many similar scores, flat distribution, weak floor.
|
|
10
|
-
* - "Best of bad bunch": sharp cliff but the cliff sits below a usable
|
|
11
|
-
* floor — the system found a winner among uninteresting candidates.
|
|
12
|
-
*
|
|
13
|
-
* Research grounding:
|
|
14
|
-
* - Geifman & El-Yaniv, "Selective Classification for Deep Neural
|
|
15
|
-
* Networks" (NeurIPS 2017): abstaining improves precision on confused
|
|
16
|
-
* inputs more than recalibrating thresholds.
|
|
17
|
-
* - Roitero et al, "Predictive Confidence in Retrieval" (SIGIR 2022):
|
|
18
|
-
* score-distribution shape predicts retrieval quality better than
|
|
19
|
-
* top-1 score in isolation.
|
|
20
|
-
* - Carmel & Yom-Tov, "Estimating Query Difficulty for IR" (Synthesis
|
|
21
|
-
* Lectures, 2010): post-retrieval predictors — sharpness, depth of
|
|
22
|
-
* score drop — correlate with TREC topic difficulty.
|
|
23
|
-
*
|
|
24
|
-
* AWM 0.8.5 integration: confidence is computed once per recall after
|
|
25
|
-
* final scoring and attached to every `ActivationResult`. Consumers may
|
|
26
|
-
* use it however they like (display, abstention, paired retrieval).
|
|
27
|
-
* Default behavior of recall is unchanged — confidence is data, not a
|
|
28
|
-
* gate, in PR-1.
|
|
29
|
-
*
|
|
30
|
-
* Configurable via env vars (initial weights tuned to favour sharpness):
|
|
31
|
-
* AWM_CONF_SHARPNESS_W (default 0.4) — weight of top1/mean(top5) signal
|
|
32
|
-
* AWM_CONF_CLIFF_W (default 0.3) — weight of (top1 - top10) / top1
|
|
33
|
-
* AWM_CONF_FLOOR_W (default 0.3) — weight of top1 absolute score
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
export interface RecallConfidence {
|
|
37
|
-
/** Composite confidence in [0, 1]. Higher = recall result is more trustworthy. */
|
|
38
|
-
confidence: number;
|
|
39
|
-
/** top1 / mean(top5), mapped to [0, 1] via (s-1)/(s+1). High = clear winner. */
|
|
40
|
-
sharpness: number;
|
|
41
|
-
/** (top1 - top10) / top1 in [0, 1]. High = sharp dropoff after winner. */
|
|
42
|
-
cliff: number;
|
|
43
|
-
/** top1 raw score, clamped to [0, 1]. Low = "best of bad bunch" risk. */
|
|
44
|
-
floor: number;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const SHARPNESS_W = parseFloat(process.env.AWM_CONF_SHARPNESS_W ?? '0.4');
|
|
48
|
-
const CLIFF_W = parseFloat(process.env.AWM_CONF_CLIFF_W ?? '0.3');
|
|
49
|
-
const FLOOR_W = parseFloat(process.env.AWM_CONF_FLOOR_W ?? '0.3');
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Compute recall confidence from an ordered (descending) array of result scores.
|
|
53
|
-
*
|
|
54
|
-
* Returns a confidence near 0 when:
|
|
55
|
-
* - Empty result set (no winner)
|
|
56
|
-
* - Flat distribution (sharpness ~1, cliff ~0)
|
|
57
|
-
* - Low absolute scores (floor low — "best of bad bunch")
|
|
58
|
-
*
|
|
59
|
-
* Returns a confidence near 1 when:
|
|
60
|
-
* - top-1 dominates (sharpness >> 1)
|
|
61
|
-
* - Sharp cliff after top-1 (cliff close to 1)
|
|
62
|
-
* - top-1 is itself a strong absolute match (floor close to 1)
|
|
63
|
-
*
|
|
64
|
-
* Edge cases:
|
|
65
|
-
* - 1 result: cliff is 0 (no runner-up). Sharpness defaults to 1 (no peers
|
|
66
|
-
* to dominate). Confidence anchored entirely by floor.
|
|
67
|
-
* - 0 results: all zero, confidence = 0.
|
|
68
|
-
*/
|
|
69
|
-
export function computeRecallConfidence(scoresDesc: number[]): RecallConfidence {
|
|
70
|
-
if (scoresDesc.length === 0) {
|
|
71
|
-
return { confidence: 0, sharpness: 0, cliff: 0, floor: 0 };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const top1 = scoresDesc[0];
|
|
75
|
-
|
|
76
|
-
// Floor: clamp top1 into [0, 1]. AWM composite scores already lie in this
|
|
77
|
-
// range under normal use, but be defensive.
|
|
78
|
-
const floor = Math.max(0, Math.min(1, top1));
|
|
79
|
-
|
|
80
|
-
// Sharpness: top1 / mean(top-5). Skip if only 1 result (no peers).
|
|
81
|
-
let sharpness = 0;
|
|
82
|
-
if (scoresDesc.length >= 2) {
|
|
83
|
-
const window = scoresDesc.slice(0, Math.min(5, scoresDesc.length));
|
|
84
|
-
const mean = window.reduce((s, v) => s + v, 0) / window.length;
|
|
85
|
-
if (mean > 0) {
|
|
86
|
-
const ratio = top1 / mean; // typically in [1, K]
|
|
87
|
-
sharpness = (ratio - 1) / (ratio + 1); // maps [1, ∞) → [0, 1)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Cliff: how steep is the drop from top-1 to the K-th candidate?
|
|
92
|
-
// Use top-10 (or last available). If only 1 result, no cliff to measure.
|
|
93
|
-
let cliff = 0;
|
|
94
|
-
if (scoresDesc.length >= 2 && top1 > 0) {
|
|
95
|
-
const tail = scoresDesc[Math.min(9, scoresDesc.length - 1)];
|
|
96
|
-
cliff = Math.max(0, Math.min(1, (top1 - tail) / top1));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Geometric blend — any near-zero component pulls confidence down.
|
|
100
|
-
// Add a tiny epsilon so log/zero doesn't collapse the whole signal when
|
|
101
|
-
// a result is genuinely sharp but the cliff is computed off only 2-3
|
|
102
|
-
// candidates (cliff small even for confident recalls).
|
|
103
|
-
const EPS = 0.05;
|
|
104
|
-
const s = sharpness + EPS;
|
|
105
|
-
const c = cliff + EPS;
|
|
106
|
-
const f = floor + EPS;
|
|
107
|
-
|
|
108
|
-
// Weighted geometric mean: prod(x_i ^ w_i)
|
|
109
|
-
const logConf =
|
|
110
|
-
SHARPNESS_W * Math.log(s)
|
|
111
|
-
+ CLIFF_W * Math.log(c)
|
|
112
|
-
+ FLOOR_W * Math.log(f);
|
|
113
|
-
const totalW = SHARPNESS_W + CLIFF_W + FLOOR_W;
|
|
114
|
-
// Subtract epsilon contribution so the floor of confidence is ~0 when all
|
|
115
|
-
// signals are zero (rather than the value of EPS).
|
|
116
|
-
const rawConf = Math.exp(logConf / totalW) - EPS;
|
|
117
|
-
const confidence = Math.max(0, Math.min(1, rawConf));
|
|
118
|
-
|
|
119
|
-
return { confidence, sharpness, cliff, floor };
|
|
120
|
-
}
|
|
1
|
+
// Copyright 2026 Robert Winter / Complete Ideas
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Retrieval confidence — score-distribution-aware signal that complements
|
|
5
|
+
* the per-result `score`. The shape of the result set carries information
|
|
6
|
+
* the raw scores do not:
|
|
7
|
+
*
|
|
8
|
+
* - Confident recall: top-1 dominates, sharp cliff, non-trivial floor.
|
|
9
|
+
* - Noisy recall: many similar scores, flat distribution, weak floor.
|
|
10
|
+
* - "Best of bad bunch": sharp cliff but the cliff sits below a usable
|
|
11
|
+
* floor — the system found a winner among uninteresting candidates.
|
|
12
|
+
*
|
|
13
|
+
* Research grounding:
|
|
14
|
+
* - Geifman & El-Yaniv, "Selective Classification for Deep Neural
|
|
15
|
+
* Networks" (NeurIPS 2017): abstaining improves precision on confused
|
|
16
|
+
* inputs more than recalibrating thresholds.
|
|
17
|
+
* - Roitero et al, "Predictive Confidence in Retrieval" (SIGIR 2022):
|
|
18
|
+
* score-distribution shape predicts retrieval quality better than
|
|
19
|
+
* top-1 score in isolation.
|
|
20
|
+
* - Carmel & Yom-Tov, "Estimating Query Difficulty for IR" (Synthesis
|
|
21
|
+
* Lectures, 2010): post-retrieval predictors — sharpness, depth of
|
|
22
|
+
* score drop — correlate with TREC topic difficulty.
|
|
23
|
+
*
|
|
24
|
+
* AWM 0.8.5 integration: confidence is computed once per recall after
|
|
25
|
+
* final scoring and attached to every `ActivationResult`. Consumers may
|
|
26
|
+
* use it however they like (display, abstention, paired retrieval).
|
|
27
|
+
* Default behavior of recall is unchanged — confidence is data, not a
|
|
28
|
+
* gate, in PR-1.
|
|
29
|
+
*
|
|
30
|
+
* Configurable via env vars (initial weights tuned to favour sharpness):
|
|
31
|
+
* AWM_CONF_SHARPNESS_W (default 0.4) — weight of top1/mean(top5) signal
|
|
32
|
+
* AWM_CONF_CLIFF_W (default 0.3) — weight of (top1 - top10) / top1
|
|
33
|
+
* AWM_CONF_FLOOR_W (default 0.3) — weight of top1 absolute score
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export interface RecallConfidence {
|
|
37
|
+
/** Composite confidence in [0, 1]. Higher = recall result is more trustworthy. */
|
|
38
|
+
confidence: number;
|
|
39
|
+
/** top1 / mean(top5), mapped to [0, 1] via (s-1)/(s+1). High = clear winner. */
|
|
40
|
+
sharpness: number;
|
|
41
|
+
/** (top1 - top10) / top1 in [0, 1]. High = sharp dropoff after winner. */
|
|
42
|
+
cliff: number;
|
|
43
|
+
/** top1 raw score, clamped to [0, 1]. Low = "best of bad bunch" risk. */
|
|
44
|
+
floor: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const SHARPNESS_W = parseFloat(process.env.AWM_CONF_SHARPNESS_W ?? '0.4');
|
|
48
|
+
const CLIFF_W = parseFloat(process.env.AWM_CONF_CLIFF_W ?? '0.3');
|
|
49
|
+
const FLOOR_W = parseFloat(process.env.AWM_CONF_FLOOR_W ?? '0.3');
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Compute recall confidence from an ordered (descending) array of result scores.
|
|
53
|
+
*
|
|
54
|
+
* Returns a confidence near 0 when:
|
|
55
|
+
* - Empty result set (no winner)
|
|
56
|
+
* - Flat distribution (sharpness ~1, cliff ~0)
|
|
57
|
+
* - Low absolute scores (floor low — "best of bad bunch")
|
|
58
|
+
*
|
|
59
|
+
* Returns a confidence near 1 when:
|
|
60
|
+
* - top-1 dominates (sharpness >> 1)
|
|
61
|
+
* - Sharp cliff after top-1 (cliff close to 1)
|
|
62
|
+
* - top-1 is itself a strong absolute match (floor close to 1)
|
|
63
|
+
*
|
|
64
|
+
* Edge cases:
|
|
65
|
+
* - 1 result: cliff is 0 (no runner-up). Sharpness defaults to 1 (no peers
|
|
66
|
+
* to dominate). Confidence anchored entirely by floor.
|
|
67
|
+
* - 0 results: all zero, confidence = 0.
|
|
68
|
+
*/
|
|
69
|
+
export function computeRecallConfidence(scoresDesc: number[]): RecallConfidence {
|
|
70
|
+
if (scoresDesc.length === 0) {
|
|
71
|
+
return { confidence: 0, sharpness: 0, cliff: 0, floor: 0 };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const top1 = scoresDesc[0];
|
|
75
|
+
|
|
76
|
+
// Floor: clamp top1 into [0, 1]. AWM composite scores already lie in this
|
|
77
|
+
// range under normal use, but be defensive.
|
|
78
|
+
const floor = Math.max(0, Math.min(1, top1));
|
|
79
|
+
|
|
80
|
+
// Sharpness: top1 / mean(top-5). Skip if only 1 result (no peers).
|
|
81
|
+
let sharpness = 0;
|
|
82
|
+
if (scoresDesc.length >= 2) {
|
|
83
|
+
const window = scoresDesc.slice(0, Math.min(5, scoresDesc.length));
|
|
84
|
+
const mean = window.reduce((s, v) => s + v, 0) / window.length;
|
|
85
|
+
if (mean > 0) {
|
|
86
|
+
const ratio = top1 / mean; // typically in [1, K]
|
|
87
|
+
sharpness = (ratio - 1) / (ratio + 1); // maps [1, ∞) → [0, 1)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Cliff: how steep is the drop from top-1 to the K-th candidate?
|
|
92
|
+
// Use top-10 (or last available). If only 1 result, no cliff to measure.
|
|
93
|
+
let cliff = 0;
|
|
94
|
+
if (scoresDesc.length >= 2 && top1 > 0) {
|
|
95
|
+
const tail = scoresDesc[Math.min(9, scoresDesc.length - 1)];
|
|
96
|
+
cliff = Math.max(0, Math.min(1, (top1 - tail) / top1));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Geometric blend — any near-zero component pulls confidence down.
|
|
100
|
+
// Add a tiny epsilon so log/zero doesn't collapse the whole signal when
|
|
101
|
+
// a result is genuinely sharp but the cliff is computed off only 2-3
|
|
102
|
+
// candidates (cliff small even for confident recalls).
|
|
103
|
+
const EPS = 0.05;
|
|
104
|
+
const s = sharpness + EPS;
|
|
105
|
+
const c = cliff + EPS;
|
|
106
|
+
const f = floor + EPS;
|
|
107
|
+
|
|
108
|
+
// Weighted geometric mean: prod(x_i ^ w_i)
|
|
109
|
+
const logConf =
|
|
110
|
+
SHARPNESS_W * Math.log(s)
|
|
111
|
+
+ CLIFF_W * Math.log(c)
|
|
112
|
+
+ FLOOR_W * Math.log(f);
|
|
113
|
+
const totalW = SHARPNESS_W + CLIFF_W + FLOOR_W;
|
|
114
|
+
// Subtract epsilon contribution so the floor of confidence is ~0 when all
|
|
115
|
+
// signals are zero (rather than the value of EPS).
|
|
116
|
+
const rawConf = Math.exp(logConf / totalW) - EPS;
|
|
117
|
+
const confidence = Math.max(0, Math.min(1, rawConf));
|
|
118
|
+
|
|
119
|
+
return { confidence, sharpness, cliff, floor };
|
|
120
|
+
}
|