@eeshans/howiprompt 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/bin/bootstrap-db.mjs +166 -0
- package/bin/cli-helpers.mjs +86 -0
- package/bin/cli.mjs +205 -0
- package/config/ml.json +47 -0
- package/data/claude_code/.gitkeep +3 -0
- package/data/codex/.gitkeep +0 -0
- package/data/reference_clusters.json +314 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +194 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/backends.d.ts +39 -0
- package/dist/pipeline/backends.js +411 -0
- package/dist/pipeline/backends.js.map +1 -0
- package/dist/pipeline/classifiers.d.ts +17 -0
- package/dist/pipeline/classifiers.js +181 -0
- package/dist/pipeline/classifiers.js.map +1 -0
- package/dist/pipeline/config.d.ts +21 -0
- package/dist/pipeline/config.js +79 -0
- package/dist/pipeline/config.js.map +1 -0
- package/dist/pipeline/db.d.ts +41 -0
- package/dist/pipeline/db.js +130 -0
- package/dist/pipeline/db.js.map +1 -0
- package/dist/pipeline/embeddings.d.ts +15 -0
- package/dist/pipeline/embeddings.js +82 -0
- package/dist/pipeline/embeddings.js.map +1 -0
- package/dist/pipeline/exclusions.d.ts +86 -0
- package/dist/pipeline/exclusions.js +320 -0
- package/dist/pipeline/exclusions.js.map +1 -0
- package/dist/pipeline/metrics.d.ts +12 -0
- package/dist/pipeline/metrics.js +278 -0
- package/dist/pipeline/metrics.js.map +1 -0
- package/dist/pipeline/ml-config.d.ts +23 -0
- package/dist/pipeline/ml-config.js +54 -0
- package/dist/pipeline/ml-config.js.map +1 -0
- package/dist/pipeline/models.d.ts +23 -0
- package/dist/pipeline/models.js +21 -0
- package/dist/pipeline/models.js.map +1 -0
- package/dist/pipeline/nlp.d.ts +20 -0
- package/dist/pipeline/nlp.js +200 -0
- package/dist/pipeline/nlp.js.map +1 -0
- package/dist/pipeline/parsers.d.ts +11 -0
- package/dist/pipeline/parsers.js +492 -0
- package/dist/pipeline/parsers.js.map +1 -0
- package/dist/pipeline/registry.d.ts +21 -0
- package/dist/pipeline/registry.js +45 -0
- package/dist/pipeline/registry.js.map +1 -0
- package/dist/pipeline/style.d.ts +37 -0
- package/dist/pipeline/style.js +204 -0
- package/dist/pipeline/style.js.map +1 -0
- package/dist/pipeline/sync.d.ts +8 -0
- package/dist/pipeline/sync.js +52 -0
- package/dist/pipeline/sync.js.map +1 -0
- package/dist/pipeline/trends.d.ts +8 -0
- package/dist/pipeline/trends.js +226 -0
- package/dist/pipeline/trends.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +216 -0
- package/dist/server.js.map +1 -0
- package/frontend/dist/_astro/MethodologyModal.astro_astro_type_script_index_0_lang.jiHwSrn-.js +34 -0
- package/frontend/dist/_astro/index.Ck1ZXjve.css +1 -0
- package/frontend/dist/_astro/index.astro_astro_type_script_index_0_lang.PuBlxVje.js +37 -0
- package/frontend/dist/_astro/index.astro_astro_type_script_index_1_lang.DmQY6kFx.js +1 -0
- package/frontend/dist/_astro/theme.CbYAaQI4.js +1 -0
- package/frontend/dist/_astro/wrapped.CpzRcLjf.css +1 -0
- package/frontend/dist/_astro/wrapped.astro_astro_type_script_index_0_lang.D4GeWu2-.js +11 -0
- package/frontend/dist/_astro/wrapped.astro_astro_type_script_index_1_lang.CPAAJDh5.js +1 -0
- package/frontend/dist/favicon.svg +4 -0
- package/frontend/dist/images/card_architect.png +0 -0
- package/frontend/dist/images/card_commander.png +0 -0
- package/frontend/dist/images/card_delegator.png +0 -0
- package/frontend/dist/images/card_explorer.png +0 -0
- package/frontend/dist/images/card_partner.png +0 -0
- package/frontend/dist/images/char_architect.png +0 -0
- package/frontend/dist/images/char_commander.png +0 -0
- package/frontend/dist/images/char_delegator.png +0 -0
- package/frontend/dist/images/char_explorer.png +0 -0
- package/frontend/dist/images/char_partner.png +0 -0
- package/frontend/dist/index.html +9 -0
- package/frontend/dist/wrapped/index.html +9 -0
- package/package.json +66 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified exclusion rules engine.
|
|
3
|
+
*
|
|
4
|
+
* All message filtering rules live in the `exclusion_rules` DB table.
|
|
5
|
+
* The parser and flagging system read from this table — no hardcoded filters.
|
|
6
|
+
*
|
|
7
|
+
* Rule types:
|
|
8
|
+
* - content_prefix: message content starts with pattern
|
|
9
|
+
* - cwd_pattern: JSONL entry cwd field contains pattern
|
|
10
|
+
* - dir_name: source file directory name matches pattern
|
|
11
|
+
* - skill_invocation: message matches a skill invocation syntax (regex)
|
|
12
|
+
*
|
|
13
|
+
* Match modes:
|
|
14
|
+
* - starts_with: content.startsWith(pattern)
|
|
15
|
+
* - contains: content.includes(pattern)
|
|
16
|
+
* - exact: content === pattern
|
|
17
|
+
* - regex: new RegExp(pattern).test(content)
|
|
18
|
+
*/
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
// ── Load & Compile ────────────────────────────────────
|
|
21
|
+
export async function loadExclusionRules(client) {
|
|
22
|
+
const result = await client.execute("SELECT * FROM exclusion_rules WHERE is_active = 1");
|
|
23
|
+
return result.rows.map((r) => ({
|
|
24
|
+
id: Number(r.id),
|
|
25
|
+
platform: String(r.platform),
|
|
26
|
+
ruleType: String(r.rule_type),
|
|
27
|
+
pattern: String(r.pattern),
|
|
28
|
+
matchMode: String(r.match_mode),
|
|
29
|
+
description: String(r.description ?? ""),
|
|
30
|
+
source: String(r.source),
|
|
31
|
+
templateContent: String(r.template_content ?? ""),
|
|
32
|
+
isActive: Boolean(r.is_active),
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
function buildMatcher(pattern, matchMode) {
|
|
36
|
+
switch (matchMode) {
|
|
37
|
+
case "starts_with":
|
|
38
|
+
return (text) => text.startsWith(pattern);
|
|
39
|
+
case "contains":
|
|
40
|
+
return (text) => text.includes(pattern);
|
|
41
|
+
case "exact":
|
|
42
|
+
return (text) => text === pattern;
|
|
43
|
+
case "regex":
|
|
44
|
+
try {
|
|
45
|
+
const regex = new RegExp(pattern, "i");
|
|
46
|
+
return (text) => regex.test(text);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return () => false;
|
|
50
|
+
}
|
|
51
|
+
default:
|
|
52
|
+
return () => false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function compileRules(rules) {
|
|
56
|
+
const compiled = {
|
|
57
|
+
contentPrefix: [],
|
|
58
|
+
cwdPattern: [],
|
|
59
|
+
dirName: [],
|
|
60
|
+
skillInvocation: [],
|
|
61
|
+
};
|
|
62
|
+
for (const rule of rules) {
|
|
63
|
+
const matcher = buildMatcher(rule.pattern, rule.matchMode);
|
|
64
|
+
switch (rule.ruleType) {
|
|
65
|
+
case "content_prefix":
|
|
66
|
+
compiled.contentPrefix.push({ rule, test: matcher });
|
|
67
|
+
break;
|
|
68
|
+
case "cwd_pattern":
|
|
69
|
+
compiled.cwdPattern.push({ rule, test: matcher });
|
|
70
|
+
break;
|
|
71
|
+
case "dir_name":
|
|
72
|
+
compiled.dirName.push({ rule, test: matcher });
|
|
73
|
+
break;
|
|
74
|
+
case "skill_invocation":
|
|
75
|
+
compiled.skillInvocation.push({
|
|
76
|
+
rule,
|
|
77
|
+
test: (content, platform) => {
|
|
78
|
+
if (rule.platform !== "*" && rule.platform !== platform)
|
|
79
|
+
return false;
|
|
80
|
+
return matcher(content);
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return compiled;
|
|
87
|
+
}
|
|
88
|
+
// ── Parse-time checks ─────────────────────────────────
|
|
89
|
+
/** Check if a message content should be excluded (content_prefix rules). */
|
|
90
|
+
export function shouldExcludeContent(compiled, content, platform) {
|
|
91
|
+
for (const { rule, test } of compiled.contentPrefix) {
|
|
92
|
+
if (rule.platform !== "*" && rule.platform !== platform)
|
|
93
|
+
continue;
|
|
94
|
+
if (test(content))
|
|
95
|
+
return { excluded: true, ruleId: rule.id };
|
|
96
|
+
}
|
|
97
|
+
return { excluded: false, ruleId: null };
|
|
98
|
+
}
|
|
99
|
+
/** Check if a CWD indicates a programmatic (non-human) session. */
|
|
100
|
+
export function shouldExcludeCwd(compiled, cwd) {
|
|
101
|
+
for (const { rule, test } of compiled.cwdPattern) {
|
|
102
|
+
if (test(cwd))
|
|
103
|
+
return { excluded: true, ruleId: rule.id };
|
|
104
|
+
}
|
|
105
|
+
return { excluded: false, ruleId: null };
|
|
106
|
+
}
|
|
107
|
+
/** Check if a source directory name should be excluded. */
|
|
108
|
+
export function shouldExcludeDir(compiled, dirName) {
|
|
109
|
+
for (const { rule, test } of compiled.dirName) {
|
|
110
|
+
if (test(dirName))
|
|
111
|
+
return { excluded: true, ruleId: rule.id };
|
|
112
|
+
}
|
|
113
|
+
return { excluded: false, ruleId: null };
|
|
114
|
+
}
|
|
115
|
+
// ── Post-insert flagging ──────────────────────────────
|
|
116
|
+
/**
|
|
117
|
+
* Flag existing messages that match exclusion rules.
|
|
118
|
+
* Checks skill_invocation and content_prefix rules against unflagged messages.
|
|
119
|
+
* Also checks template_content via hash comparison.
|
|
120
|
+
*/
|
|
121
|
+
export async function flagExcludedMessages(client) {
|
|
122
|
+
const rules = await loadExclusionRules(client);
|
|
123
|
+
const compiled = compileRules(rules);
|
|
124
|
+
// Build template hash lookup (full template content -> rule id)
|
|
125
|
+
const templateHashToRuleId = new Map();
|
|
126
|
+
for (const rule of rules) {
|
|
127
|
+
if (rule.templateContent && rule.templateContent.length >= 20) {
|
|
128
|
+
const prefix = rule.templateContent.slice(0, 200);
|
|
129
|
+
const hash = createHash("sha256").update(prefix).digest("hex");
|
|
130
|
+
templateHashToRuleId.set(hash, rule.id);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Load unflagged human messages
|
|
134
|
+
const msgRows = await client.execute(`SELECT id, platform, content FROM messages
|
|
135
|
+
WHERE role = 'human' AND is_excluded = 0`);
|
|
136
|
+
const updates = [];
|
|
137
|
+
for (const row of msgRows.rows) {
|
|
138
|
+
const msgId = Number(row.id);
|
|
139
|
+
const platform = String(row.platform);
|
|
140
|
+
const content = String(row.content);
|
|
141
|
+
let matchedRuleId = null;
|
|
142
|
+
// Check skill invocation rules
|
|
143
|
+
for (const { rule, test } of compiled.skillInvocation) {
|
|
144
|
+
if (test(content, platform)) {
|
|
145
|
+
matchedRuleId = rule.id;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Check content prefix rules
|
|
150
|
+
if (!matchedRuleId) {
|
|
151
|
+
const result = shouldExcludeContent(compiled, content, platform);
|
|
152
|
+
if (result.excluded)
|
|
153
|
+
matchedRuleId = result.ruleId;
|
|
154
|
+
}
|
|
155
|
+
// Check template content hash match
|
|
156
|
+
if (!matchedRuleId && templateHashToRuleId.size > 0) {
|
|
157
|
+
const msgPrefix = content.slice(0, 200);
|
|
158
|
+
const msgHash = createHash("sha256").update(msgPrefix).digest("hex");
|
|
159
|
+
const ruleId = templateHashToRuleId.get(msgHash);
|
|
160
|
+
if (ruleId)
|
|
161
|
+
matchedRuleId = ruleId;
|
|
162
|
+
}
|
|
163
|
+
if (matchedRuleId !== null) {
|
|
164
|
+
updates.push({ msgId, ruleId: matchedRuleId });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Batch update
|
|
168
|
+
const batchSize = 500;
|
|
169
|
+
let flagged = 0;
|
|
170
|
+
for (let i = 0; i < updates.length; i += batchSize) {
|
|
171
|
+
const batch = updates.slice(i, i + batchSize);
|
|
172
|
+
await client.batch(batch.map((u) => ({
|
|
173
|
+
sql: `UPDATE messages SET is_excluded = 1, matched_rule_id = ? WHERE id = ?`,
|
|
174
|
+
args: [u.ruleId, u.msgId],
|
|
175
|
+
})), "write");
|
|
176
|
+
flagged += batch.length;
|
|
177
|
+
}
|
|
178
|
+
return flagged;
|
|
179
|
+
}
|
|
180
|
+
// ── Discovery → Rules ─────────────────────────────────
|
|
181
|
+
/**
|
|
182
|
+
* Discover skills from all backends and upsert as exclusion rules.
|
|
183
|
+
* Also upserts into skills table for template content storage.
|
|
184
|
+
*/
|
|
185
|
+
export async function discoverAndSyncRules(client, backends) {
|
|
186
|
+
let skillsFound = 0;
|
|
187
|
+
let rulesUpserted = 0;
|
|
188
|
+
for (const backend of backends) {
|
|
189
|
+
if (!backend.discoverSkills)
|
|
190
|
+
continue;
|
|
191
|
+
const skills = backend.discoverSkills();
|
|
192
|
+
for (const skill of skills) {
|
|
193
|
+
skillsFound++;
|
|
194
|
+
const contentHash = skill.templateContent
|
|
195
|
+
? createHash("sha256").update(skill.templateContent).digest("hex")
|
|
196
|
+
: "";
|
|
197
|
+
// Upsert into skills table (template content storage)
|
|
198
|
+
await client.execute({
|
|
199
|
+
sql: `INSERT INTO skills (platform, skill_name, skill_path, invocation_pattern, template_content, content_hash, source, discovered_at)
|
|
200
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
201
|
+
ON CONFLICT(platform, skill_name) DO UPDATE SET
|
|
202
|
+
skill_path = excluded.skill_path,
|
|
203
|
+
invocation_pattern = excluded.invocation_pattern,
|
|
204
|
+
template_content = excluded.template_content,
|
|
205
|
+
content_hash = excluded.content_hash,
|
|
206
|
+
source = excluded.source,
|
|
207
|
+
discovered_at = excluded.discovered_at`,
|
|
208
|
+
args: [
|
|
209
|
+
backend.id,
|
|
210
|
+
skill.skillName,
|
|
211
|
+
skill.skillPath,
|
|
212
|
+
skill.invocationPattern,
|
|
213
|
+
skill.templateContent,
|
|
214
|
+
contentHash,
|
|
215
|
+
skill.source ?? "discovered",
|
|
216
|
+
],
|
|
217
|
+
});
|
|
218
|
+
// Upsert into exclusion_rules table
|
|
219
|
+
if (skill.invocationPattern) {
|
|
220
|
+
const result = await client.execute({
|
|
221
|
+
sql: `INSERT INTO exclusion_rules (platform, rule_type, pattern, match_mode, description, source, template_content)
|
|
222
|
+
VALUES (?, 'skill_invocation', ?, 'regex', ?, ?, ?)
|
|
223
|
+
ON CONFLICT(platform, rule_type, pattern) DO UPDATE SET
|
|
224
|
+
description = excluded.description,
|
|
225
|
+
template_content = excluded.template_content`,
|
|
226
|
+
args: [
|
|
227
|
+
backend.id,
|
|
228
|
+
skill.invocationPattern,
|
|
229
|
+
`${skill.skillName} skill invocation`,
|
|
230
|
+
skill.source ?? "discovered",
|
|
231
|
+
skill.templateContent || null,
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
if (result.rowsAffected > 0)
|
|
235
|
+
rulesUpserted++;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return { skillsFound, rulesUpserted };
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Seed system-level exclusion rules.
|
|
243
|
+
* These are platform-inherent rules that don't come from skill discovery.
|
|
244
|
+
* Uses INSERT OR IGNORE so they're only added once.
|
|
245
|
+
*/
|
|
246
|
+
export async function seedSystemRules(client) {
|
|
247
|
+
const systemRules = [
|
|
248
|
+
// Claude Code framework messages
|
|
249
|
+
{
|
|
250
|
+
platform: "claude_code",
|
|
251
|
+
ruleType: "content_prefix",
|
|
252
|
+
pattern: "<command-",
|
|
253
|
+
matchMode: "starts_with",
|
|
254
|
+
description: "Claude Code system command",
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
platform: "claude_code",
|
|
258
|
+
ruleType: "content_prefix",
|
|
259
|
+
pattern: "<local-command",
|
|
260
|
+
matchMode: "starts_with",
|
|
261
|
+
description: "Claude Code local command",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
platform: "claude_code",
|
|
265
|
+
ruleType: "content_prefix",
|
|
266
|
+
pattern: "<task-notification>",
|
|
267
|
+
matchMode: "starts_with",
|
|
268
|
+
description: "Claude Code background task notification",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
platform: "claude_code",
|
|
272
|
+
ruleType: "content_prefix",
|
|
273
|
+
pattern: "This session is being continued from a previous conversation that ran out of context",
|
|
274
|
+
matchMode: "starts_with",
|
|
275
|
+
description: "Claude Code auto-compaction summary",
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
platform: "claude_code",
|
|
279
|
+
ruleType: "content_prefix",
|
|
280
|
+
pattern: "<bash-input>",
|
|
281
|
+
matchMode: "starts_with",
|
|
282
|
+
description: "Tool output leaked into human message",
|
|
283
|
+
},
|
|
284
|
+
// Programmatic CWD detection (all platforms)
|
|
285
|
+
{
|
|
286
|
+
platform: "*",
|
|
287
|
+
ruleType: "cwd_pattern",
|
|
288
|
+
pattern: "node_modules",
|
|
289
|
+
matchMode: "contains",
|
|
290
|
+
description: "Programmatic CLI invocation via npm package",
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
platform: "*",
|
|
294
|
+
ruleType: "cwd_pattern",
|
|
295
|
+
pattern: ".npm/_npx",
|
|
296
|
+
matchMode: "contains",
|
|
297
|
+
description: "Programmatic CLI invocation via npx",
|
|
298
|
+
},
|
|
299
|
+
// Subagent directory exclusion
|
|
300
|
+
{
|
|
301
|
+
platform: "claude_code",
|
|
302
|
+
ruleType: "dir_name",
|
|
303
|
+
pattern: "subagents",
|
|
304
|
+
matchMode: "exact",
|
|
305
|
+
description: "Claude Code subagent sidechain directory",
|
|
306
|
+
},
|
|
307
|
+
];
|
|
308
|
+
let seeded = 0;
|
|
309
|
+
for (const rule of systemRules) {
|
|
310
|
+
const result = await client.execute({
|
|
311
|
+
sql: `INSERT OR IGNORE INTO exclusion_rules (platform, rule_type, pattern, match_mode, description, source)
|
|
312
|
+
VALUES (?, ?, ?, ?, ?, 'system')`,
|
|
313
|
+
args: [rule.platform, rule.ruleType, rule.pattern, rule.matchMode, rule.description],
|
|
314
|
+
});
|
|
315
|
+
if (result.rowsAffected > 0)
|
|
316
|
+
seeded++;
|
|
317
|
+
}
|
|
318
|
+
return seeded;
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=exclusions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclusions.js","sourceRoot":"","sources":["../../src/pipeline/exclusions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Client } from "@libsql/client";
|
|
2
|
+
import type { Config } from "./config.js";
|
|
3
|
+
import { type Platform } from "./models.js";
|
|
4
|
+
export declare function computeModelUsage(client: Client, platform?: Platform): Promise<Record<string, any>>;
|
|
5
|
+
export declare function computeMetrics(client: Client, _config: Config, platform?: Platform): Promise<Record<string, any>>;
|
|
6
|
+
export declare function hasHumanMessages(client: Client, platform?: Platform): Promise<boolean>;
|
|
7
|
+
export declare function computeSourceViews(client: Client, config: Config): Promise<{
|
|
8
|
+
sourceViews: Record<string, any>;
|
|
9
|
+
metadata: {
|
|
10
|
+
default_view: string;
|
|
11
|
+
};
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { platformFilter, queryMessages } from "./db.js";
|
|
2
|
+
import { PLATFORM_VALUES, Role } from "./models.js";
|
|
3
|
+
import { computeNlpMetrics } from "./nlp.js";
|
|
4
|
+
import { getPersona } from "./style.js";
|
|
5
|
+
import { computeNormalized } from "./registry.js";
|
|
6
|
+
import { computeTrendMetrics } from "./trends.js";
|
|
7
|
+
function countAllMatches(texts, pattern) {
|
|
8
|
+
let total = 0;
|
|
9
|
+
for (const t of texts) {
|
|
10
|
+
total += (t.match(pattern) ?? []).length;
|
|
11
|
+
pattern.lastIndex = 0;
|
|
12
|
+
}
|
|
13
|
+
return total;
|
|
14
|
+
}
|
|
15
|
+
function round(n, decimals) {
|
|
16
|
+
const f = 10 ** decimals;
|
|
17
|
+
return Math.round(n * f) / f;
|
|
18
|
+
}
|
|
19
|
+
export async function computeModelUsage(client, platform) {
|
|
20
|
+
const pf = platformFilter(platform);
|
|
21
|
+
const totalHuman = Number((await client.execute({ sql: `SELECT COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause}`, args: pf.args })).rows[0].cnt);
|
|
22
|
+
const withMeta = Number((await client.execute({ sql: `SELECT COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0 AND (model_id IS NOT NULL OR model_provider IS NOT NULL)${pf.clause}`, args: pf.args })).rows[0].cnt);
|
|
23
|
+
const coveragePct = totalHuman ? round((withMeta / totalHuman) * 100, 1) : 0;
|
|
24
|
+
// By model with source breakdown
|
|
25
|
+
const modelSourceRows = (await client.execute({
|
|
26
|
+
sql: `SELECT COALESCE(model_id, 'unknown'), COALESCE(model_provider, 'unknown'), platform, COUNT(*) as cnt, SUM(word_count) as words FROM messages WHERE role = 'human' AND is_excluded = 0 AND (model_id IS NOT NULL OR model_provider IS NOT NULL)${pf.clause} GROUP BY 1, 2, platform`,
|
|
27
|
+
args: pf.args,
|
|
28
|
+
})).rows;
|
|
29
|
+
const byModelMap = new Map();
|
|
30
|
+
for (const r of modelSourceRows) {
|
|
31
|
+
const key = `${r[0]}|${r[1]}`;
|
|
32
|
+
if (!byModelMap.has(key))
|
|
33
|
+
byModelMap.set(key, { model_id: String(r[0]), model_provider: String(r[1]), prompts: 0, words: 0, sources: {} });
|
|
34
|
+
const entry = byModelMap.get(key);
|
|
35
|
+
entry.prompts += Number(r.cnt ?? r[3]);
|
|
36
|
+
entry.words += Number(r.words ?? r[4]);
|
|
37
|
+
entry.sources[String(r.platform ?? r[2])] = Number(r.cnt ?? r[3]);
|
|
38
|
+
}
|
|
39
|
+
const convRows = (await client.execute({
|
|
40
|
+
sql: `SELECT COALESCE(model_id, 'unknown'), COALESCE(model_provider, 'unknown'), COUNT(DISTINCT conversation_id) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0 AND (model_id IS NOT NULL OR model_provider IS NOT NULL)${pf.clause} GROUP BY 1, 2`,
|
|
41
|
+
args: pf.args,
|
|
42
|
+
})).rows;
|
|
43
|
+
const convMap = new Map(convRows.map((r) => [`${r[0]}|${r[1]}`, Number(r.cnt ?? r[2])]));
|
|
44
|
+
const byModelList = Array.from(byModelMap.entries())
|
|
45
|
+
.map(([key, stats]) => ({ ...stats, conversations: convMap.get(key) ?? 0 }))
|
|
46
|
+
.sort((a, b) => b.prompts - a.prompts);
|
|
47
|
+
// By provider
|
|
48
|
+
const provRows = (await client.execute({
|
|
49
|
+
sql: `SELECT COALESCE(model_provider, 'unknown'), platform, COUNT(*) as cnt, SUM(word_count) as words FROM messages WHERE role = 'human' AND is_excluded = 0 AND (model_id IS NOT NULL OR model_provider IS NOT NULL)${pf.clause} GROUP BY 1, platform`,
|
|
50
|
+
args: pf.args,
|
|
51
|
+
})).rows;
|
|
52
|
+
const byProvMap = new Map();
|
|
53
|
+
for (const r of provRows) {
|
|
54
|
+
const prov = String(r[0]);
|
|
55
|
+
if (!byProvMap.has(prov))
|
|
56
|
+
byProvMap.set(prov, { model_provider: prov, prompts: 0, words: 0, sources: {} });
|
|
57
|
+
const entry = byProvMap.get(prov);
|
|
58
|
+
entry.prompts += Number(r.cnt ?? r[2]);
|
|
59
|
+
entry.words += Number(r.words ?? r[3]);
|
|
60
|
+
entry.sources[String(r.platform ?? r[1])] = Number(r.cnt ?? r[2]);
|
|
61
|
+
}
|
|
62
|
+
const provConvRows = (await client.execute({
|
|
63
|
+
sql: `SELECT COALESCE(model_provider, 'unknown'), COUNT(DISTINCT conversation_id) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0 AND (model_id IS NOT NULL OR model_provider IS NOT NULL)${pf.clause} GROUP BY 1`,
|
|
64
|
+
args: pf.args,
|
|
65
|
+
})).rows;
|
|
66
|
+
const provConvMap = new Map(provConvRows.map((r) => [String(r[0]), Number(r.cnt ?? r[1])]));
|
|
67
|
+
const byProvList = Array.from(byProvMap.entries())
|
|
68
|
+
.map(([prov, stats]) => ({ ...stats, conversations: provConvMap.get(prov) ?? 0 }))
|
|
69
|
+
.sort((a, b) => b.prompts - a.prompts);
|
|
70
|
+
// Time series
|
|
71
|
+
const tsRows = (await client.execute({
|
|
72
|
+
sql: `SELECT platform, local_date, COALESCE(model_id, 'unknown') as mid, COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0 AND (model_id IS NOT NULL OR model_provider IS NOT NULL)${pf.clause} GROUP BY platform, local_date, 3 ORDER BY platform, local_date`,
|
|
73
|
+
args: pf.args,
|
|
74
|
+
})).rows;
|
|
75
|
+
const bySourceDate = new Map();
|
|
76
|
+
for (const r of tsRows) {
|
|
77
|
+
const plat = String(r.platform ?? r[0]);
|
|
78
|
+
const date = String(r.local_date ?? r[1]);
|
|
79
|
+
const mid = String(r.mid ?? r[2]);
|
|
80
|
+
const cnt = Number(r.cnt ?? r[3]);
|
|
81
|
+
if (!bySourceDate.has(plat))
|
|
82
|
+
bySourceDate.set(plat, new Map());
|
|
83
|
+
const dayMap = bySourceDate.get(plat);
|
|
84
|
+
if (!dayMap.has(date))
|
|
85
|
+
dayMap.set(date, {});
|
|
86
|
+
dayMap.get(date)[mid] = cnt;
|
|
87
|
+
}
|
|
88
|
+
const timeSeriesBySource = {};
|
|
89
|
+
for (const [source, dayMap] of bySourceDate) {
|
|
90
|
+
timeSeriesBySource[source] = Array.from(dayMap.entries())
|
|
91
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
92
|
+
.map(([date, models]) => ({
|
|
93
|
+
date,
|
|
94
|
+
total_prompts: Object.values(models).reduce((a, b) => a + b, 0),
|
|
95
|
+
models: Object.fromEntries(Object.entries(models).sort(([, a], [, b]) => b - a)),
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
coverage: { total_human_prompts: totalHuman, prompts_with_model_metadata: withMeta, metadata_coverage_pct: coveragePct },
|
|
100
|
+
by_model: byModelList,
|
|
101
|
+
by_provider: byProvList,
|
|
102
|
+
time_series_by_source: timeSeriesBySource,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export async function computeMetrics(client, _config, platform) {
|
|
106
|
+
const pf = platformFilter(platform);
|
|
107
|
+
// Volume (human-only — the universal unit across all platforms)
|
|
108
|
+
const vol = (await client.execute({
|
|
109
|
+
sql: `SELECT COUNT(*) as total, SUM(CASE WHEN role = 'human' AND is_excluded = 0 THEN 1 ELSE 0 END) as human, SUM(CASE WHEN role = 'human' AND is_excluded = 0 THEN word_count ELSE 0 END) as words_h, COUNT(DISTINCT CASE WHEN role = 'human' AND is_excluded = 0 THEN conversation_id END) as convos FROM messages WHERE 1=1${pf.clause}`,
|
|
110
|
+
args: pf.args,
|
|
111
|
+
})).rows[0];
|
|
112
|
+
const totalMessages = Number(vol.total);
|
|
113
|
+
const totalHuman = Number(vol.human);
|
|
114
|
+
const totalWordsHuman = Number(vol.words_h ?? 0);
|
|
115
|
+
const totalConversations = Number(vol.convos);
|
|
116
|
+
if (!totalHuman)
|
|
117
|
+
throw new Error("No human messages found in data");
|
|
118
|
+
const avgWordsPerPrompt = totalWordsHuman / totalHuman;
|
|
119
|
+
// Conversation depth (human turns only — comparable across all platforms)
|
|
120
|
+
const depthRows = (await client.execute({
|
|
121
|
+
sql: `SELECT conversation_id, COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause} GROUP BY conversation_id`,
|
|
122
|
+
args: pf.args,
|
|
123
|
+
})).rows;
|
|
124
|
+
const turns = depthRows.map((r) => Number(r.cnt));
|
|
125
|
+
const avgTurns = turns.length ? turns.reduce((a, b) => a + b, 0) / turns.length : 0;
|
|
126
|
+
const maxTurns = turns.length ? Math.max(...turns) : 0;
|
|
127
|
+
const quickAsks = turns.filter((t) => t <= 3).length;
|
|
128
|
+
const workingSessions = turns.filter((t) => t >= 4 && t <= 10).length;
|
|
129
|
+
const deepDives = turns.filter((t) => t > 10).length;
|
|
130
|
+
// Temporal
|
|
131
|
+
const heatmapRows = (await client.execute({
|
|
132
|
+
sql: `SELECT local_weekday, local_hour, COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause} GROUP BY local_weekday, local_hour`,
|
|
133
|
+
args: pf.args,
|
|
134
|
+
})).rows;
|
|
135
|
+
const heatmap = Array.from({ length: 7 }, () => Array(24).fill(0));
|
|
136
|
+
for (const r of heatmapRows)
|
|
137
|
+
heatmap[Number(r.local_weekday)][Number(r.local_hour)] = Number(r.cnt);
|
|
138
|
+
const nightOwl = Number((await client.execute({
|
|
139
|
+
sql: `SELECT COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0 AND (local_hour >= 23 OR local_hour < 4)${pf.clause}`,
|
|
140
|
+
args: pf.args,
|
|
141
|
+
})).rows[0].cnt);
|
|
142
|
+
const nightOwlPct = (nightOwl / totalHuman) * 100;
|
|
143
|
+
const hourRows = (await client.execute({
|
|
144
|
+
sql: `SELECT local_hour, COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause} GROUP BY local_hour`,
|
|
145
|
+
args: pf.args,
|
|
146
|
+
})).rows;
|
|
147
|
+
const hourCounts = {};
|
|
148
|
+
let peakHour = 0, peakHourCount = 0;
|
|
149
|
+
for (const r of hourRows) {
|
|
150
|
+
const h = Number(r.local_hour);
|
|
151
|
+
const c = Number(r.cnt);
|
|
152
|
+
hourCounts[h] = c;
|
|
153
|
+
if (c > peakHourCount) {
|
|
154
|
+
peakHour = h;
|
|
155
|
+
peakHourCount = c;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const dayRows = (await client.execute({
|
|
159
|
+
sql: `SELECT local_weekday, COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause} GROUP BY local_weekday`,
|
|
160
|
+
args: pf.args,
|
|
161
|
+
})).rows;
|
|
162
|
+
let peakDay = 0, peakDayCount = 0;
|
|
163
|
+
for (const r of dayRows) {
|
|
164
|
+
const d = Number(r.local_weekday);
|
|
165
|
+
const c = Number(r.cnt);
|
|
166
|
+
if (c > peakDayCount) {
|
|
167
|
+
peakDay = d;
|
|
168
|
+
peakDayCount = c;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const dayNames = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
|
172
|
+
// "You're right" affirmation count
|
|
173
|
+
const assistantMsgs = await queryMessages(client, { role: Role.ASSISTANT, platform });
|
|
174
|
+
const assistantTexts = assistantMsgs.map((m) => m.content);
|
|
175
|
+
const yrPattern = /you'?re (absolutely |completely |totally )?right|(?:that'?s |this is )(?:a )?(?:great|good|excellent) (?:point|idea|suggestion|approach|call)|(?:exactly|precisely|absolutely)[!.,]|great (?:catch|observation|question)/gi;
|
|
176
|
+
const yrCount = countAllMatches(assistantTexts, yrPattern);
|
|
177
|
+
const yrPerConvo = totalConversations ? yrCount / totalConversations : 0;
|
|
178
|
+
// Platform stats
|
|
179
|
+
const platRows = (await client.execute({
|
|
180
|
+
sql: `SELECT platform, COUNT(*) as cnt, SUM(word_count) as words, COUNT(DISTINCT conversation_id) as convos, MIN(timestamp) as first_ts FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause} GROUP BY platform`,
|
|
181
|
+
args: pf.args,
|
|
182
|
+
})).rows;
|
|
183
|
+
const platformStats = {};
|
|
184
|
+
for (const r of platRows) {
|
|
185
|
+
platformStats[String(r.platform)] = {
|
|
186
|
+
messages: Number(r.cnt),
|
|
187
|
+
words: Number(r.words),
|
|
188
|
+
conversations: Number(r.convos),
|
|
189
|
+
first_message: String(r.first_ts),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
// Date range
|
|
193
|
+
const dateRange = (await client.execute({
|
|
194
|
+
sql: `SELECT MIN(timestamp) as first_ts, MAX(timestamp) as last_ts FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause}`,
|
|
195
|
+
args: pf.args,
|
|
196
|
+
})).rows[0];
|
|
197
|
+
// Sub-module metrics
|
|
198
|
+
const [modelUsage, trends, nlp] = await Promise.all([
|
|
199
|
+
computeModelUsage(client, platform),
|
|
200
|
+
computeTrendMetrics(client, platform),
|
|
201
|
+
computeNlpMetrics(client, platform),
|
|
202
|
+
]);
|
|
203
|
+
const result = {
|
|
204
|
+
generated_at: new Date().toISOString(),
|
|
205
|
+
volume: {
|
|
206
|
+
total_messages: totalMessages,
|
|
207
|
+
total_human: totalHuman,
|
|
208
|
+
total_words_human: totalWordsHuman,
|
|
209
|
+
total_conversations: totalConversations,
|
|
210
|
+
avg_words_per_prompt: round(avgWordsPerPrompt, 1),
|
|
211
|
+
},
|
|
212
|
+
conversation_depth: {
|
|
213
|
+
avg_turns: round(avgTurns, 1),
|
|
214
|
+
max_turns: maxTurns,
|
|
215
|
+
quick_asks: quickAsks,
|
|
216
|
+
working_sessions: workingSessions,
|
|
217
|
+
deep_dives: deepDives,
|
|
218
|
+
},
|
|
219
|
+
temporal: {
|
|
220
|
+
heatmap,
|
|
221
|
+
night_owl_pct: round(nightOwlPct, 1),
|
|
222
|
+
peak_hour: peakHour,
|
|
223
|
+
peak_hour_count: peakHourCount,
|
|
224
|
+
peak_day: dayNames[peakDay],
|
|
225
|
+
peak_day_count: peakDayCount,
|
|
226
|
+
hour_counts: hourCounts,
|
|
227
|
+
},
|
|
228
|
+
politeness: { score: nlp.politeness?.avg_score ?? 0, total_prompts: totalHuman },
|
|
229
|
+
youre_right: { count: yrCount, per_conversation: round(yrPerConvo, 1) },
|
|
230
|
+
platform_stats: platformStats,
|
|
231
|
+
model_usage: modelUsage,
|
|
232
|
+
trends,
|
|
233
|
+
nlp,
|
|
234
|
+
date_range: { first: String(dateRange.first_ts), last: String(dateRange.last_ts) },
|
|
235
|
+
};
|
|
236
|
+
// Derive persona quadrant from 2×2 style scores (aggregated from nlp_enrichments)
|
|
237
|
+
const styleAgg = await client.execute({
|
|
238
|
+
sql: `SELECT AVG(e.detail_score) as avg_detail, AVG(e.style_score) as avg_style
|
|
239
|
+
FROM nlp_enrichments e JOIN messages m ON e.message_id = m.id
|
|
240
|
+
WHERE m.role = 'human' AND m.is_excluded = 0 AND e.detail_score IS NOT NULL${pf.clause}`,
|
|
241
|
+
args: pf.args,
|
|
242
|
+
});
|
|
243
|
+
const avgDetail = Math.round(Number(styleAgg.rows[0]?.avg_detail ?? 50) * 10) / 10;
|
|
244
|
+
const avgStyle = Math.round(Number(styleAgg.rows[0]?.avg_style ?? 50) * 10) / 10;
|
|
245
|
+
const persona = getPersona(avgDetail, avgStyle);
|
|
246
|
+
result.persona = {
|
|
247
|
+
...persona,
|
|
248
|
+
detail_score: avgDetail,
|
|
249
|
+
style_score: avgStyle,
|
|
250
|
+
};
|
|
251
|
+
// Compute normalized 0-100 values for all registry metrics
|
|
252
|
+
result.normalized = computeNormalized(result);
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
export async function hasHumanMessages(client, platform) {
|
|
256
|
+
const pf = platformFilter(platform);
|
|
257
|
+
const r = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM messages WHERE role = 'human' AND is_excluded = 0${pf.clause}`, args: pf.args });
|
|
258
|
+
return Number(r.rows[0].cnt) > 0;
|
|
259
|
+
}
|
|
260
|
+
export async function computeSourceViews(client, config) {
|
|
261
|
+
const allMetrics = await computeMetrics(client, config);
|
|
262
|
+
const sourceViews = { both: allMetrics };
|
|
263
|
+
for (const platform of PLATFORM_VALUES) {
|
|
264
|
+
const hasMessages = await hasHumanMessages(client, platform);
|
|
265
|
+
sourceViews[platform] = hasMessages ? await computeMetrics(client, config, platform) : null;
|
|
266
|
+
}
|
|
267
|
+
let defaultView = "both";
|
|
268
|
+
if (!sourceViews[defaultView]) {
|
|
269
|
+
for (const candidate of PLATFORM_VALUES) {
|
|
270
|
+
if (sourceViews[candidate]) {
|
|
271
|
+
defaultView = candidate;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return { sourceViews, metadata: { default_view: defaultView } };
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/pipeline/metrics.ts"],"names":[],"mappings":"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"}
|