rubric-chat 0.2.3 → 0.4.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.
@@ -0,0 +1,130 @@
1
+ import { ARCHETYPES, getArchetype } from "./archetypes.js";
2
+ import { candidateArchetypes, heuristicDimensions } from "./heuristics.js";
3
+ import { generateLocalJudgment } from "./model.js";
4
+ import { applyStrictness, DIMENSION_WEIGHTS, LOCAL_SYSTEM_PROMPT } from "./rubric.js";
5
+ // Much smaller than the server's 240k-char budget: prompt processing on CPU
6
+ // dominates local latency, and ~24k chars (~6k tokens) keeps a session under
7
+ // a minute on most machines while preserving the same sampling algorithm.
8
+ export const LOCAL_MAX_ANALYSIS_CHARS = 24_000;
9
+ export function truncateSession(session, maxChars) {
10
+ const total = session.turns.reduce((sum, turn) => sum + turn.text.length, 0);
11
+ if (total <= maxChars)
12
+ return { session, wasTruncated: false };
13
+ const turns = session.turns;
14
+ const keep = new Set();
15
+ for (let i = 0; i < Math.min(5, turns.length); i++)
16
+ keep.add(i);
17
+ for (let i = Math.max(0, turns.length - 10); i < turns.length; i++)
18
+ keep.add(i);
19
+ if (turns.length > 15) {
20
+ const middleStart = 5;
21
+ const middleEnd = turns.length - 10;
22
+ const middleSlots = 10;
23
+ const span = Math.max(1, middleEnd - middleStart);
24
+ for (let slot = 0; slot < middleSlots; slot++) {
25
+ keep.add(middleStart +
26
+ Math.min(span - 1, Math.round((slot / Math.max(1, middleSlots - 1)) * (span - 1))));
27
+ }
28
+ }
29
+ const kept = turns.filter((_, index) => keep.has(index));
30
+ return { session: { ...session, turns: kept }, wasTruncated: true };
31
+ }
32
+ export function buildUserPrompt(session, candidates) {
33
+ const archetypeLines = candidates
34
+ .map((slug) => `- ${slug}: ${ARCHETYPES[slug].name} — ${ARCHETYPES[slug].tagline}`)
35
+ .join("\n");
36
+ const turns = session.turns.map((turn) => `[TURN ${turn.index}]\n${turn.text}`).join("\n\n");
37
+ return `Here are the user turns from a session with ${session.target_tool}.
38
+ Total user turns: ${session.turns.length}.
39
+ Candidate archetypes:
40
+ ${archetypeLines}
41
+
42
+ User turns:
43
+ ${turns}`;
44
+ }
45
+ export function normalizeDimensions(parsed, session) {
46
+ const byName = new Map(parsed.dimensions.map((dimension) => [dimension.dimension, dimension]));
47
+ const maxIndex = Math.max(...session.turns.map((turn) => turn.index));
48
+ const fallbackIndex = session.turns[0].index;
49
+ const normalized = [];
50
+ for (const [name, weight] of Object.entries(DIMENSION_WEIGHTS)) {
51
+ const source = byName.get(name);
52
+ let score;
53
+ let feedback;
54
+ let evidence;
55
+ if (!source) {
56
+ score = 50;
57
+ feedback = "The model did not return feedback for this dimension.";
58
+ evidence = [fallbackIndex];
59
+ }
60
+ else {
61
+ score = Math.max(0, Math.min(100, Math.round(source.score)));
62
+ feedback = source.feedback.trim();
63
+ evidence = source.evidence_turn_indices.filter((index) => index >= 0 && index <= maxIndex);
64
+ if (evidence.length === 0)
65
+ evidence = [fallbackIndex];
66
+ }
67
+ normalized.push({ dimension: name, score, weight, feedback, evidence_turn_indices: evidence });
68
+ }
69
+ return normalized;
70
+ }
71
+ export function weightedRawScore(dimensions) {
72
+ return dimensions.reduce((sum, dimension) => sum + dimension.score * dimension.weight, 0);
73
+ }
74
+ export async function analyzeLocally(session, options = {}) {
75
+ const { session: trimmed, wasTruncated } = truncateSession(session, LOCAL_MAX_ANALYSIS_CHARS);
76
+ const candidates = candidateArchetypes(trimmed);
77
+ const prompt = buildUserPrompt(trimmed, candidates);
78
+ let parsed = null;
79
+ let modelUsed = "heuristic";
80
+ let heuristicReason = null;
81
+ try {
82
+ const generation = await generateLocalJudgment({
83
+ systemPrompt: LOCAL_SYSTEM_PROMPT,
84
+ userPrompt: prompt,
85
+ candidates,
86
+ timeoutMs: options.timeoutMs ?? 180_000,
87
+ ...options
88
+ });
89
+ parsed = generation.parsed;
90
+ modelUsed = generation.modelName;
91
+ }
92
+ catch (err) {
93
+ heuristicReason = err instanceof Error ? err.message : String(err);
94
+ }
95
+ let dimensions;
96
+ let summary;
97
+ let archetypeSlug;
98
+ let mode;
99
+ if (parsed) {
100
+ dimensions = normalizeDimensions(parsed, trimmed);
101
+ summary = parsed.summary.trim();
102
+ archetypeSlug = parsed.archetype_slug in ARCHETYPES ? parsed.archetype_slug : candidates[0];
103
+ mode = "model";
104
+ }
105
+ else {
106
+ dimensions = heuristicDimensions(trimmed);
107
+ summary =
108
+ "Heuristic estimate only — the local model was unavailable" +
109
+ (heuristicReason ? ` (${heuristicReason})` : "") +
110
+ ". Run without --local for a calibrated, model-judged score.";
111
+ archetypeSlug = candidates[0];
112
+ mode = "heuristic";
113
+ }
114
+ const rawScore = weightedRawScore(dimensions);
115
+ return {
116
+ kind: "local",
117
+ mode,
118
+ model_used: modelUsed,
119
+ score: applyStrictness(rawScore),
120
+ raw_score: Math.round(rawScore),
121
+ archetype: getArchetype(archetypeSlug),
122
+ dimensions,
123
+ summary,
124
+ was_truncated: wasTruncated,
125
+ target_tool: session.target_tool,
126
+ turn_count: session.turns.length,
127
+ created_at: new Date().toISOString()
128
+ };
129
+ }
130
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/local/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,156 @@
1
+ // Parity tests: the local scoring math must match the backend
2
+ // (apps/backend/app/analysis/{rubric,engine,heuristics}.py) exactly.
3
+ import { describe, expect, it } from "vitest";
4
+ import { buildUserPrompt, normalizeDimensions, truncateSession, weightedRawScore } from "./engine.js";
5
+ import { candidateArchetypes, heuristicDimensions } from "./heuristics.js";
6
+ import { applyStrictness, DIMENSION_WEIGHTS } from "./rubric.js";
7
+ function makeSession(texts) {
8
+ const turns = texts.map((text, index) => ({ index, text }));
9
+ return {
10
+ schema_version: "1.0",
11
+ target_tool: "chatgpt",
12
+ source_client: "cli",
13
+ source_client_version: "test",
14
+ ingested_at: new Date().toISOString(),
15
+ turns
16
+ };
17
+ }
18
+ describe("applyStrictness (server parity)", () => {
19
+ it("matches the server curve at known points", () => {
20
+ // round(raw**1.15 / 100**0.15) — values verified against the Python impl.
21
+ expect(applyStrictness(0)).toBe(0);
22
+ expect(applyStrictness(50)).toBe(45);
23
+ expect(applyStrictness(100)).toBe(100);
24
+ expect(applyStrictness(70)).toBe(66);
25
+ });
26
+ });
27
+ describe("DIMENSION_WEIGHTS", () => {
28
+ it("sums to 1.0 with the server's six dimensions", () => {
29
+ const total = Object.values(DIMENSION_WEIGHTS).reduce((a, b) => a + b, 0);
30
+ expect(total).toBeCloseTo(1.0, 10);
31
+ expect(Object.keys(DIMENSION_WEIGHTS)).toEqual([
32
+ "specificity",
33
+ "context_provision",
34
+ "structure",
35
+ "iteration_quality",
36
+ "scope_discipline",
37
+ "meta_prompting"
38
+ ]);
39
+ });
40
+ });
41
+ describe("truncateSession", () => {
42
+ it("returns untouched session under the budget", () => {
43
+ const session = makeSession(["short", "turns"]);
44
+ const result = truncateSession(session, 1000);
45
+ expect(result.wasTruncated).toBe(false);
46
+ expect(result.session.turns).toHaveLength(2);
47
+ });
48
+ it("keeps first 5 + last 10 + sampled middle when over budget", () => {
49
+ const session = makeSession(Array.from({ length: 30 }, (_, i) => `turn ${i} ${"x".repeat(100)}`));
50
+ const result = truncateSession(session, 500);
51
+ expect(result.wasTruncated).toBe(true);
52
+ const indices = result.session.turns.map((turn) => turn.index);
53
+ // First five and last ten always survive.
54
+ for (const i of [0, 1, 2, 3, 4])
55
+ expect(indices).toContain(i);
56
+ for (const i of [20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
57
+ expect(indices).toContain(i);
58
+ expect(indices.length).toBeLessThanOrEqual(25);
59
+ // Order preserved.
60
+ expect([...indices].sort((a, b) => a - b)).toEqual(indices);
61
+ });
62
+ });
63
+ describe("normalizeDimensions", () => {
64
+ const session = makeSession(["one", "two", "three"]);
65
+ it("fills missing dimensions with score 50 and fallback evidence", () => {
66
+ const parsed = {
67
+ raw_score: 60,
68
+ archetype_slug: "sniper",
69
+ dimensions: [
70
+ { dimension: "specificity", score: 70, feedback: "good", evidence_turn_indices: [1] }
71
+ ],
72
+ summary: "ok"
73
+ };
74
+ const normalized = normalizeDimensions(parsed, session);
75
+ expect(normalized).toHaveLength(6);
76
+ const structure = normalized.find((d) => d.dimension === "structure");
77
+ expect(structure.score).toBe(50);
78
+ expect(structure.evidence_turn_indices).toEqual([0]);
79
+ const specificity = normalized.find((d) => d.dimension === "specificity");
80
+ expect(specificity.score).toBe(70);
81
+ expect(specificity.weight).toBe(0.2);
82
+ });
83
+ it("clamps out-of-range evidence indices to the first turn", () => {
84
+ const parsed = {
85
+ raw_score: 50,
86
+ archetype_slug: "sniper",
87
+ dimensions: [
88
+ { dimension: "specificity", score: 55, feedback: "x", evidence_turn_indices: [99, -1] }
89
+ ],
90
+ summary: "ok"
91
+ };
92
+ const normalized = normalizeDimensions(parsed, session);
93
+ const specificity = normalized.find((d) => d.dimension === "specificity");
94
+ expect(specificity.evidence_turn_indices).toEqual([0]);
95
+ });
96
+ });
97
+ describe("weightedRawScore", () => {
98
+ it("returns the score when all dimensions are equal", () => {
99
+ const session = makeSession(["a"]);
100
+ const parsed = {
101
+ raw_score: 50,
102
+ archetype_slug: "sniper",
103
+ dimensions: [],
104
+ summary: ""
105
+ };
106
+ const normalized = normalizeDimensions(parsed, session); // all 50s
107
+ expect(weightedRawScore(normalized)).toBeCloseTo(50, 10);
108
+ });
109
+ });
110
+ describe("candidateArchetypes (server parity)", () => {
111
+ it("flags a short two-turn session as sniper", () => {
112
+ const session = makeSession(["fix this bug", "thanks"]);
113
+ expect(candidateArchetypes(session)[0]).toBe("sniper");
114
+ });
115
+ it("flags a huge single opener as firehose", () => {
116
+ const session = makeSession(["x".repeat(2000)]);
117
+ expect(candidateArchetypes(session)).toContain("firehose");
118
+ });
119
+ it("flags structured prompts as architect", () => {
120
+ const session = makeSession([
121
+ "Role: senior dev\nConstraints: keep it short\nOutput: a list",
122
+ "format: table please"
123
+ ]);
124
+ expect(candidateArchetypes(session)).toContain("architect");
125
+ });
126
+ it("always includes the baseline spread, capped at 5", () => {
127
+ const session = makeSession(["hello"]);
128
+ const candidates = candidateArchetypes(session);
129
+ expect(candidates.length).toBeLessThanOrEqual(5);
130
+ for (const slug of ["sniper", "architect", "sculptor"]) {
131
+ expect(candidates).toContain(slug);
132
+ }
133
+ });
134
+ });
135
+ describe("heuristicDimensions", () => {
136
+ it("returns all six dimensions clamped to 30-65", () => {
137
+ const session = makeSession(["short ask", "another", "ok"]);
138
+ const dims = heuristicDimensions(session);
139
+ expect(dims).toHaveLength(6);
140
+ for (const dim of dims) {
141
+ expect(dim.score).toBeGreaterThanOrEqual(30);
142
+ expect(dim.score).toBeLessThanOrEqual(65);
143
+ }
144
+ });
145
+ });
146
+ describe("buildUserPrompt", () => {
147
+ it("renders [TURN n] blocks and candidate lines", () => {
148
+ const session = makeSession(["first ask", "second ask"]);
149
+ const prompt = buildUserPrompt(session, ["sniper", "explorer"]);
150
+ expect(prompt).toContain("[TURN 0]\nfirst ask");
151
+ expect(prompt).toContain("[TURN 1]\nsecond ask");
152
+ expect(prompt).toContain("- sniper: The Sniper");
153
+ expect(prompt).toContain("Total user turns: 2");
154
+ });
155
+ });
156
+ //# sourceMappingURL=engine.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.test.js","sourceRoot":"","sources":["../../src/local/engine.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ import { DIMENSION_WEIGHTS } from "./rubric.js";
2
+ export function candidateArchetypes(session) {
3
+ const turns = session.turns.map((turn) => turn.text);
4
+ const turnCount = turns.length;
5
+ const lengths = turns.map((text) => text.length);
6
+ const avgLen = lengths.reduce((a, b) => a + b, 0) / Math.max(1, turnCount);
7
+ const firstLen = lengths[0] ?? 0;
8
+ const joined = turns.join("\n").toLowerCase();
9
+ const markers = [
10
+ "\n#",
11
+ "\n-",
12
+ "\n1.",
13
+ "format:",
14
+ "role:",
15
+ "constraints:",
16
+ "output:",
17
+ "acceptance criteria",
18
+ "edge case",
19
+ "tradeoff",
20
+ "deliverable"
21
+ ];
22
+ const structuredMarkers = markers.reduce((sum, marker) => sum + countOccurrences(joined, marker), 0);
23
+ const repeatedTerms = repeatedOpeningTerms(turns);
24
+ const candidates = [];
25
+ if (turnCount <= 2 && avgLen < 500)
26
+ candidates.push("sniper");
27
+ if (firstLen > 1800 && turnCount <= 3)
28
+ candidates.push("firehose");
29
+ if (structuredMarkers >= 2)
30
+ candidates.push("architect");
31
+ if (turnCount >= 7 && avgLen < 500)
32
+ candidates.push("interrogator");
33
+ if (turnCount >= 4 && repeatedTerms >= 2)
34
+ candidates.push("repeater");
35
+ if ((turnCount >= 4 && avgLen >= 650) || (turnCount >= 2 && firstLen >= 400 && structuredMarkers >= 1)) {
36
+ candidates.push("sculptor");
37
+ }
38
+ if (turnCount >= 5 && topicDriftSignal(joined))
39
+ candidates.push("wanderer");
40
+ for (const fallback of ["architect", "sculptor", "sniper", "explorer"]) {
41
+ if (!candidates.includes(fallback))
42
+ candidates.push(fallback);
43
+ }
44
+ return [...new Set(candidates)].slice(0, 5);
45
+ }
46
+ export function repeatedOpeningTerms(turns) {
47
+ const firstWords = [];
48
+ for (const turn of turns) {
49
+ const words = turn
50
+ .split(/\s+/)
51
+ .slice(0, 8)
52
+ .map((word) => word.replace(/^[.,!?;:]+|[.,!?;:]+$/g, "").toLowerCase());
53
+ firstWords.push(...words.filter((word) => word.length > 4));
54
+ }
55
+ const counts = new Map();
56
+ for (const word of firstWords)
57
+ counts.set(word, (counts.get(word) ?? 0) + 1);
58
+ let repeated = 0;
59
+ for (const count of counts.values())
60
+ if (count >= 3)
61
+ repeated += 1;
62
+ return repeated;
63
+ }
64
+ export function topicDriftSignal(text) {
65
+ const domains = [
66
+ ["code", "bug", "api", "test", "function"],
67
+ ["write", "essay", "copy", "email", "headline"],
68
+ ["plan", "trip", "hotel", "flight", "itinerary"],
69
+ ["recipe", "meal", "cook", "ingredient"],
70
+ ["legal", "contract", "policy", "clause"]
71
+ ];
72
+ const hits = domains.reduce((sum, words) => sum + (words.some((word) => text.includes(word)) ? 1 : 0), 0);
73
+ return hits >= 3;
74
+ }
75
+ function countOccurrences(haystack, needle) {
76
+ let count = 0;
77
+ let index = haystack.indexOf(needle);
78
+ while (index !== -1) {
79
+ count += 1;
80
+ index = haystack.indexOf(needle, index + needle.length);
81
+ }
82
+ return count;
83
+ }
84
+ /**
85
+ * Heuristic-only dimension scores for when no model is available. Derived
86
+ * from the same signals the candidate heuristics use, clamped to 30–65 so a
87
+ * guess never masquerades as a confident judgment in either direction.
88
+ */
89
+ export function heuristicDimensions(session) {
90
+ const turns = session.turns.map((turn) => turn.text);
91
+ const turnCount = turns.length;
92
+ const lengths = turns.map((text) => text.length);
93
+ const avgLen = lengths.reduce((a, b) => a + b, 0) / Math.max(1, turnCount);
94
+ const firstLen = lengths[0] ?? 0;
95
+ const joined = turns.join("\n").toLowerCase();
96
+ const firstIndex = session.turns[0]?.index ?? 0;
97
+ const structuredMarkers = [
98
+ "\n#",
99
+ "\n-",
100
+ "\n1.",
101
+ "format:",
102
+ "role:",
103
+ "constraints:",
104
+ "output:",
105
+ "acceptance criteria"
106
+ ].reduce((sum, marker) => sum + countOccurrences(joined, marker), 0);
107
+ const metaMarkers = ["format", "role", "act as", "respond in", "output", "step by step", "concise"].reduce((sum, marker) => sum + countOccurrences(joined, marker), 0);
108
+ const repeated = repeatedOpeningTerms(turns);
109
+ const drift = topicDriftSignal(joined);
110
+ const clamp = (value) => Math.max(30, Math.min(65, Math.round(value)));
111
+ const scores = {
112
+ specificity: clamp(35 + Math.min(20, avgLen / 60)),
113
+ context_provision: clamp(32 + Math.min(25, firstLen / 80)),
114
+ structure: clamp(34 + structuredMarkers * 6),
115
+ iteration_quality: clamp(50 - repeated * 7 + (turnCount >= 3 ? 5 : 0)),
116
+ scope_discipline: clamp(drift ? 36 : 54),
117
+ meta_prompting: clamp(33 + metaMarkers * 5)
118
+ };
119
+ return Object.keys(DIMENSION_WEIGHTS).map((dimension) => ({
120
+ dimension,
121
+ score: scores[dimension],
122
+ weight: DIMENSION_WEIGHTS[dimension],
123
+ feedback: "Heuristic estimate — run without --local for model-judged feedback.",
124
+ evidence_turn_indices: [firstIndex]
125
+ }));
126
+ }
127
+ //# sourceMappingURL=heuristics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heuristics.js","sourceRoot":"","sources":["../../src/local/heuristics.ts"],"names":[],"mappings":"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"}