@ngockhoale/ukit 3.4.45 → 3.4.46

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.
@@ -1,195 +0,0 @@
1
- const HEAVY_INPUT_SIDE_MIN = 250_000;
2
- const HEAVY_OUTPUT_MAX = 2_000;
3
- const MIN_HEAVY_CALLS_FOR_VERDICT = 10;
4
- const TOP_LIMIT = 20;
5
-
6
- const isFiniteNumber = Number.isFinite;
7
- const inputSide = (call) => (isFiniteNumber(call.input) ? call.input : 0)
8
- + (isFiniteNumber(call.cacheRead) ? call.cacheRead : 0)
9
- + (isFiniteNumber(call.cacheWrite) ? call.cacheWrite : 0);
10
- const ratio = (numerator, denominator) => denominator > 0 ? numerator / denominator : null;
11
- const agentType = (agent) => agent.agentType ?? 'unknown';
12
- const sortText = (a, b) => String(a) < String(b) ? -1 : (String(a) > String(b) ? 1 : 0);
13
-
14
- function getAgents(corpus) {
15
- return Array.isArray(corpus?.agents) ? corpus.agents.filter((agent) => agent && typeof agent === 'object') : [];
16
- }
17
-
18
- function getCalls(corpus) {
19
- return Array.isArray(corpus?.calls) ? corpus.calls.filter((call) => call && typeof call === 'object') : [];
20
- }
21
-
22
- function collectSegments(agents) {
23
- const byHash = new Map();
24
- for (const agent of agents) {
25
- if (!Array.isArray(agent.segments)) continue;
26
- for (const segment of agent.segments) {
27
- if (!segment || typeof segment !== 'object' || segment.h == null
28
- || !isFiniteNumber(segment.t) || segment.t < 0) continue;
29
- if (!byHash.has(segment.h)) byHash.set(segment.h, []);
30
- byHash.get(segment.h).push({
31
- h: segment.h,
32
- t: segment.t,
33
- turnId: agent.turnId,
34
- agentId: agent.agentId,
35
- agentType: agentType(agent),
36
- });
37
- }
38
- }
39
- return byHash;
40
- }
41
-
42
- function repeatedOccurrences(occurrences) {
43
- // A segment can occur more than once inside an agent prompt. Repetition is
44
- // measured between agents, so retain that agent's first occurrence only.
45
- const firstByAgent = new Map();
46
- for (const occurrence of occurrences) {
47
- if (occurrence.agentId == null || firstByAgent.has(occurrence.agentId)) continue;
48
- firstByAgent.set(occurrence.agentId, occurrence);
49
- }
50
- const distinctAgents = [...firstByAgent.values()];
51
- if (distinctAgents.length < 2) return null;
52
- return distinctAgents;
53
- }
54
-
55
- function duplicateBreakdown(occurrences) {
56
- const agents = repeatedOccurrences(occurrences);
57
- if (!agents) return null;
58
-
59
- let withinTokens = 0;
60
- let crossTokens = 0;
61
- const first = agents[0];
62
- for (const occurrence of agents.slice(1)) {
63
- if (occurrence.turnId === first.turnId) withinTokens += occurrence.t;
64
- else crossTokens += occurrence.t;
65
- }
66
- return {
67
- withinTokens,
68
- crossTokens,
69
- count: agents.length,
70
- displayTokens: first.t,
71
- duplicateTokens: withinTokens + crossTokens,
72
- };
73
- }
74
-
75
- function computeAmplification(corpus, agents, calls) {
76
- const agentsById = new Map(agents.filter((agent) => agent.agentId != null)
77
- .map((agent) => [agent.agentId, agent]));
78
- const inputByType = new Map();
79
- for (const call of calls) {
80
- const agent = agentsById.get(call.agentId);
81
- if (!agent || call.zero || (call.depth ?? agent.depth ?? 1) <= 0) continue;
82
- const type = agentType(agent);
83
- inputByType.set(type, (inputByType.get(type) ?? 0) + inputSide(call));
84
- }
85
-
86
- const promptsByType = new Map();
87
- for (const agent of agents) {
88
- if (agent.agentId == null || (agent.depth ?? 1) <= 0
89
- || !isFiniteNumber(agent.promptTokensEst) || agent.promptTokensEst < 0) continue;
90
- const type = agentType(agent);
91
- promptsByType.set(type, (promptsByType.get(type) ?? 0) + agent.promptTokensEst);
92
- }
93
-
94
- const inputTotal = [...inputByType.values()].reduce((sum, value) => sum + value, 0);
95
- const promptTotal = [...promptsByType.values()].reduce((sum, value) => sum + value, 0);
96
- const types = [...new Set([...inputByType.keys(), ...promptsByType.keys()])].sort(sortText);
97
- return {
98
- overall: promptTotal === 0 ? null : inputTotal / promptTotal,
99
- byType: Object.fromEntries(types.map((type) => [
100
- type,
101
- (promptsByType.get(type) ?? 0) === 0 ? null : (inputByType.get(type) ?? 0) / promptsByType.get(type),
102
- ])),
103
- };
104
- }
105
-
106
- function summarizeSegments(byHash) {
107
- let totalTokens = 0;
108
- let duplicateTokens = 0;
109
- let withinTokens = 0;
110
- let crossTokens = 0;
111
- const repeated = [];
112
-
113
- for (const [hash, occurrences] of byHash) {
114
- totalTokens += occurrences.reduce((sum, item) => sum + item.t, 0);
115
- const breakdown = duplicateBreakdown(occurrences);
116
- if (!breakdown) continue;
117
- duplicateTokens += breakdown.duplicateTokens;
118
- withinTokens += breakdown.withinTokens;
119
- crossTokens += breakdown.crossTokens;
120
- repeated.push({
121
- h: hash,
122
- t: breakdown.displayTokens,
123
- count: breakdown.count,
124
- agentTypes: [...new Set(occurrences.filter((item) => item.agentId != null)
125
- .map((item) => item.agentType))].sort(sortText),
126
- duplicateTokens: breakdown.duplicateTokens,
127
- });
128
- }
129
-
130
- repeated.sort((a, b) => b.duplicateTokens - a.duplicateTokens || sortText(a.h, b.h));
131
- return {
132
- totalTokens,
133
- duplicateTokens,
134
- withinTokens,
135
- crossTokens,
136
- topRepeatedSegments: repeated.slice(0, TOP_LIMIT).map(({ duplicateTokens: _tokens, ...segment }) => segment),
137
- };
138
- }
139
-
140
- function computeReplayHypothesis(calls, agents, byHash) {
141
- const agentsById = new Map(agents.filter((agent) => agent.agentId != null)
142
- .map((agent) => [agent.agentId, agent]));
143
- const heavyCalls = calls.filter((call) => {
144
- const agent = agentsById.get(call.agentId);
145
- if (!agent || call.zero || (call.depth ?? agent.depth ?? 1) <= 0) return false;
146
- return inputSide(call) >= HEAVY_INPUT_SIDE_MIN
147
- && isFiniteNumber(call.output) && call.output <= HEAVY_OUTPUT_MAX;
148
- });
149
- const heavyTurns = new Set(heavyCalls.map((call) => call.turnId).filter((turnId) => turnId != null));
150
- const sharedHeavyTurns = new Set();
151
-
152
- for (const occurrences of byHash.values()) {
153
- const agentIdsByTurn = new Map();
154
- for (const occurrence of repeatedOccurrences(occurrences) ?? []) {
155
- if (occurrence.turnId == null || !heavyTurns.has(occurrence.turnId)) continue;
156
- if (!agentIdsByTurn.has(occurrence.turnId)) agentIdsByTurn.set(occurrence.turnId, new Set());
157
- agentIdsByTurn.get(occurrence.turnId).add(occurrence.agentId);
158
- }
159
- for (const [turnId, ids] of agentIdsByTurn) if (ids.size >= 2) sharedHeavyTurns.add(turnId);
160
- }
161
-
162
- return {
163
- verdict: heavyCalls.length < MIN_HEAVY_CALLS_FOR_VERDICT
164
- ? 'inconclusive'
165
- : (sharedHeavyTurns.size > 0 ? 'supported' : 'not_supported'),
166
- heavyCalls: heavyCalls.length,
167
- heavyTurns: heavyTurns.size,
168
- sharedHeavyTurns: sharedHeavyTurns.size,
169
- share: ratio(sharedHeavyTurns.size, heavyTurns.size),
170
- };
171
- }
172
-
173
- export function computeDuplicates(corpus) {
174
- const agents = getAgents(corpus);
175
- const calls = getCalls(corpus);
176
- const byHash = collectSegments(agents);
177
- const segments = summarizeSegments(byHash);
178
- const amplification = computeAmplification(corpus, agents, calls);
179
-
180
- return {
181
- amplification: amplification.overall,
182
- amplificationByType: amplification.byType,
183
- duplicateRatio: ratio(segments.duplicateTokens, segments.totalTokens),
184
- withinTurn: {
185
- tokens: segments.withinTokens,
186
- ratio: ratio(segments.withinTokens, segments.totalTokens),
187
- },
188
- crossTurn: {
189
- tokens: segments.crossTokens,
190
- ratio: ratio(segments.crossTokens, segments.totalTokens),
191
- },
192
- topRepeatedSegments: segments.topRepeatedSegments,
193
- replayHypothesis: computeReplayHypothesis(calls, agents, byHash),
194
- };
195
- }
@@ -1,193 +0,0 @@
1
- const N_PLUS_ONE_MIN_AGENTS = 3;
2
- const N_PLUS_ONE_MAX_PROMPT_TOKENS = 2_000;
3
- const RETRY_MIN_OCCURRENCES = 2;
4
- const LOOP_MIN_OCCURRENCES = 5;
5
- const HEAVY_INPUT_SIDE_MIN = 250_000;
6
- const HEAVY_OUTPUT_MAX = 2_000;
7
- const TOP_LIMIT = 20;
8
-
9
- export function percentile(values, p) {
10
- if (!Array.isArray(values) || values.length === 0) return null;
11
- const sorted = values.filter(Number.isFinite).sort((a, b) => a - b);
12
- if (sorted.length === 0) return null;
13
- const rank = Math.max(1, Math.ceil(p * sorted.length));
14
- return sorted[rank - 1];
15
- }
16
-
17
- const sum = (items, field) => items.reduce((total, item) => total + (Number.isFinite(item[field]) ? item[field] : 0), 0);
18
- const ratio = (n, d) => d > 0 ? n / d : null;
19
- const inputSide = (call) => (call.input ?? 0) + (call.cacheRead ?? 0) + (call.cacheWrite ?? 0);
20
- const uncached = (call) => (call.input ?? 0) + (call.cacheWrite ?? 0);
21
- const callTokens = (call) => inputSide(call) + (call.output ?? 0);
22
- const validCalls = (corpus) => (corpus.calls ?? []).filter((call) => !call.zero);
23
- const grouped = (items, keyFn) => {
24
- const result = new Map();
25
- for (const item of items) {
26
- const key = keyFn(item);
27
- if (key == null) continue;
28
- if (!result.has(key)) result.set(key, []);
29
- result.get(key).push(item);
30
- }
31
- return result;
32
- };
33
- const totalFor = (calls) => ({
34
- calls: calls.length,
35
- input: sum(calls, 'input'),
36
- cacheRead: sum(calls, 'cacheRead'),
37
- cacheWrite: sum(calls, 'cacheWrite'),
38
- output: sum(calls, 'output'),
39
- uncached: calls.reduce((n, c) => n + uncached(c), 0),
40
- inputSide: calls.reduce((n, c) => n + inputSide(c), 0),
41
- });
42
- // Cache metadata is only trustworthy when the read key was recorded (present_zero/present_positive).
43
- // Absent/invalid calls are excluded from the hit-rate denominator — they are UNKNOWN, not a miss.
44
- // Calls without a status (historical corpora built before MB-1) are treated as recorded.
45
- const cacheKnown = (call) => call.cacheMetadataStatus == null
46
- || call.cacheMetadataStatus === 'present_zero' || call.cacheMetadataStatus === 'present_positive';
47
- const cacheFor = (calls) => {
48
- const known = calls.filter(cacheKnown);
49
- const totals = totalFor(known);
50
- return {
51
- hitRate: ratio(totals.cacheRead, totals.inputSide),
52
- cacheRead: totals.cacheRead,
53
- inputSide: totals.inputSide,
54
- knownCalls: known.length,
55
- unknownCalls: calls.length - known.length,
56
- };
57
- };
58
- const sortedTop = (items, getValue, getKey) => [...items]
59
- .map((item) => ({ ...item, uncached: getValue(item), inputSide: getKey(item) }))
60
- .sort((a, b) => b.uncached - a.uncached || b.inputSide - a.inputSide || String(a.agentId ?? a.turnId).localeCompare(String(b.agentId ?? b.turnId)))
61
- .slice(0, TOP_LIMIT);
62
-
63
- function callPercentiles(calls, selector) {
64
- return {
65
- p50: percentile(calls.map(selector), 0.5),
66
- p90: percentile(calls.map(selector), 0.9),
67
- p99: percentile(calls.map(selector), 0.99),
68
- };
69
- }
70
-
71
- function computeTasks(corpus, calls) {
72
- const tasks = new Map();
73
- for (const turn of corpus.turns ?? []) tasks.set(turn.turnId, { turnId: turn.turnId, calls: [] });
74
- for (const call of calls) {
75
- const key = call.turnId ?? `${call.sessionId}#unattributed`;
76
- if (!tasks.has(key)) tasks.set(key, { turnId: key, calls: [] });
77
- tasks.get(key).calls.push(call);
78
- }
79
- const rows = [...tasks.values()];
80
- const subAgentCounts = rows.map((task) => new Set((corpus.agents ?? []).filter((a) => a.turnId === task.turnId).map((a) => a.agentId)).size);
81
- return {
82
- tasks: rows.length,
83
- avgSubAgents: ratio(subAgentCounts.reduce((a, b) => a + b, 0), rows.length),
84
- avgCalls: ratio(rows.reduce((n, task) => n + task.calls.length, 0), rows.length),
85
- ...Object.fromEntries(['Calls', 'Tokens'].flatMap((label) => {
86
- const values = rows.map((task) => label === 'Calls' ? task.calls.length : task.calls.reduce((n, c) => n + callTokens(c), 0));
87
- return [[`p50${label}`, percentile(values, 0.5)], [`p90${label}`, percentile(values, 0.9)], [`p99${label}`, percentile(values, 0.99)]];
88
- })),
89
- };
90
- }
91
-
92
- export function computeMetrics(corpus) {
93
- const calls = validCalls(corpus);
94
- const mainCalls = calls.filter((call) => (call.depth ?? 0) === 0);
95
- const subCalls = calls.filter((call) => (call.depth ?? 0) > 0);
96
- const main = totalFor(mainCalls);
97
- const sub = totalFor(subCalls);
98
- const all = totalFor(calls);
99
- const totalOutput = all.output;
100
- const cacheByType = {};
101
- const byType = {};
102
- const typeCalls = grouped(subCalls, (call) => call.agentType ?? 'unknown');
103
- for (const [type, typeGroup] of typeCalls) {
104
- const agents = (corpus.agents ?? []).filter((agent) => (agent.agentType ?? 'unknown') === type);
105
- const totals = totalFor(typeGroup);
106
- const latencies = typeGroup.map((call) => call.latencyMs).filter(Number.isFinite);
107
- const finalTokens = agents.map((agent) => agent.finalTokensEst).filter(Number.isFinite);
108
- const refs = agents.map((agent) => agent.finalRefRatio).filter(Number.isFinite);
109
- byType[type] = {
110
- agents: new Set(agents.map((agent) => agent.agentId)).size,
111
- calls: totals.calls,
112
- inputSide: totals.inputSide,
113
- uncached: totals.uncached,
114
- output: totals.output,
115
- avgCallsPerAgent: ratio(totals.calls, new Set(agents.map((agent) => agent.agentId)).size),
116
- outputPerInput: ratio(totals.output, totals.inputSide),
117
- avgFinalTokensEst: ratio(finalTokens.reduce((a, b) => a + b, 0), finalTokens.length),
118
- avgFinalRefRatio: ratio(refs.reduce((a, b) => a + b, 0), refs.length),
119
- latencyP50: percentile(latencies, 0.5),
120
- latencyP90: percentile(latencies, 0.9),
121
- valueProxy: { label: 'proxy; not a measure of true agent value', avgFinalTokensEst: ratio(finalTokens.reduce((a, b) => a + b, 0), finalTokens.length), avgFinalRefRatio: ratio(refs.reduce((a, b) => a + b, 0), refs.length), outputPerInput: ratio(totals.output, totals.inputSide) },
122
- };
123
- cacheByType[type] = cacheFor(typeGroup);
124
- }
125
- const depthCalls = grouped(calls, (call) => call.depth ?? 0);
126
- const byDepth = Object.fromEntries([...depthCalls].map(([depth, group]) => [depth, totalFor(group)]));
127
- const modelCalls = grouped(calls, (call) => call.model ?? 'unknown');
128
- const byModel = Object.fromEntries([...modelCalls].map(([model, group]) => [model, totalFor(group)]));
129
- const turnAgents = grouped(corpus.agents ?? [], (agent) => agent.turnId);
130
- const fanoutCounts = [...turnAgents.values()].map((agents) => agents.length);
131
- const fanoutHistogram = {};
132
- for (const count of fanoutCounts) fanoutHistogram[count] = (fanoutHistogram[count] ?? 0) + 1;
133
- const heavy = subCalls.filter((call) => inputSide(call) >= HEAVY_INPUT_SIDE_MIN && call.output <= HEAVY_OUTPUT_MAX);
134
- const heavyByType = {};
135
- for (const [type, group] of grouped(heavy, (call) => call.agentType ?? 'unknown')) heavyByType[type] = group.length;
136
- const heavyBySession = {};
137
- for (const [sessionId, group] of grouped(heavy, (call) => call.sessionId ?? 'unknown')) heavyBySession[sessionId] = group.length;
138
- const turns = [...new Set([...calls.map((call) => call.turnId), ...(corpus.turns ?? []).map((turn) => turn.turnId)].filter(Boolean))];
139
- const turnAgentsAll = grouped(corpus.agents ?? [], (agent) => agent.turnId);
140
- const flagged = (predicate) => {
141
- const ids = [];
142
- for (const [turnId, agents] of turnAgentsAll) if (predicate(agents)) ids.push(turnId);
143
- return { count: ids.length, turnIds: ids.slice(0, TOP_LIMIT) };
144
- };
145
- const nPlusOne = flagged((agents) => {
146
- const sorted = [...agents].sort((a, b) => a.firstTs - b.firstTs);
147
- let run = 0;
148
- let previous = null;
149
- for (const agent of sorted) {
150
- const small = Number.isFinite(agent.promptTokensEst) && agent.promptTokensEst <= N_PLUS_ONE_MAX_PROMPT_TOKENS;
151
- if (small && previous && previous.agentType === agent.agentType && agent.firstTs >= previous.lastTs) run += 1;
152
- else run = small ? 1 : 0;
153
- previous = agent;
154
- if (run >= N_PLUS_ONE_MIN_AGENTS) return true;
155
- }
156
- return false;
157
- });
158
- const retryLoops = flagged((agents) => [...grouped(agents.filter((a) => a.promptHash != null), (a) => `${a.agentType}\0${a.promptHash}`).values()].some((group) => group.length >= RETRY_MIN_OCCURRENCES));
159
- const loops = flagged((agents) => [...grouped(agents, (a) => a.agentType).values()].some((group) => group.length >= LOOP_MIN_OCCURRENCES));
160
- const agentStats = (corpus.agents ?? []).map((agent) => {
161
- const group = calls.filter((call) => call.agentId === agent.agentId);
162
- return { agentId: agent.agentId, agentType: agent.agentType, turnId: agent.turnId, calls: group.length, uncached: group.reduce((n, c) => n + uncached(c), 0), inputSide: group.reduce((n, c) => n + inputSide(c), 0), output: sum(group, 'output') };
163
- });
164
- const turnStats = turns.map((turnId) => {
165
- const group = calls.filter((call) => call.turnId === turnId);
166
- return { turnId, calls: group.length, uncached: group.reduce((n, c) => n + uncached(c), 0), inputSide: group.reduce((n, c) => n + inputSide(c), 0), output: sum(group, 'output') };
167
- });
168
- const costliest = [...turnStats].sort((a, b) => b.uncached - a.uncached).slice(0, 5);
169
- const tokenFlow = costliest.map(({ turnId }) => ({ turnId, calls: calls.filter((call) => call.turnId === turnId).sort((a, b) => a.ts - b.ts).map((call) => ({ ts: call.ts, agentType: call.agentType, depth: call.depth, input: call.input, cacheRead: call.cacheRead, cacheWrite: call.cacheWrite, output: call.output })) }));
170
-
171
- return {
172
- totals: { main, sub },
173
- share: {
174
- subOfInputSide: ratio(sub.inputSide, all.inputSide),
175
- subOfUncached: ratio(sub.uncached, all.uncached),
176
- subOfOutput: ratio(sub.output, totalOutput),
177
- subOfCalls: ratio(sub.calls, all.calls),
178
- },
179
- cache: { main: cacheFor(mainCalls), sub: cacheFor(subCalls), byType: cacheByType },
180
- perTask: computeTasks(corpus, calls),
181
- byType,
182
- byDepth,
183
- byModel,
184
- fanout: { histogram: fanoutHistogram, max: fanoutCounts.length ? Math.max(...fanoutCounts) : 0, p90: percentile(fanoutCounts, 0.9) },
185
- heavyCalls: { count: heavy.length, share: ratio(heavy.length, subCalls.length), byType: heavyByType, bySession: heavyBySession },
186
- nPlusOne,
187
- retryLoops,
188
- loops,
189
- topAgents: sortedTop(agentStats, (agent) => agent.uncached, (agent) => agent.inputSide),
190
- topTurns: sortedTop(turnStats, (turn) => turn.uncached, (turn) => turn.inputSide),
191
- tokenFlow,
192
- };
193
- }