stackmem 1.0.13 → 1.0.15
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/benchmark.js +552 -0
- package/dist/cli.js +29 -1
- package/dist/index.js +15 -0
- package/dist/scoring.js +6 -1
- package/dist/tools.js +1 -0
- package/package.json +1 -1
- package/src/benchmark.ts +798 -0
- package/src/cli.ts +31 -1
- package/src/index.ts +18 -0
- package/src/scoring.ts +7 -1
package/src/cli.ts
CHANGED
|
@@ -282,11 +282,31 @@ async function cmdStart(project: string) {
|
|
|
282
282
|
|
|
283
283
|
const budgetedMemories = applyContextBudget(scoredMemories, CONTEXT_BUDGET_TOKENS);
|
|
284
284
|
const omittedCount = scoredMemories.length - budgetedMemories.length;
|
|
285
|
-
|
|
285
|
+
let tokensUsed = budgetedMemories.reduce(
|
|
286
286
|
(sum, memory) => sum + estimateTokens(memory.content),
|
|
287
287
|
0
|
|
288
288
|
);
|
|
289
289
|
|
|
290
|
+
const { data: fixData, error: fixError } = await supabase
|
|
291
|
+
.from("execution_log")
|
|
292
|
+
.select("*")
|
|
293
|
+
.eq("project", project)
|
|
294
|
+
.eq("resolved", false)
|
|
295
|
+
.order("created_at", { ascending: false })
|
|
296
|
+
.limit(5);
|
|
297
|
+
|
|
298
|
+
if (fixError) fail(`Failed to load execution log: ${fixError.message}`);
|
|
299
|
+
|
|
300
|
+
// Fixes share the same 2000-token budget as memories, which already
|
|
301
|
+
// consumed their portion above — fixes only get whatever room is left.
|
|
302
|
+
const budgetedFixes: { problem: string; solution: string | null }[] = [];
|
|
303
|
+
for (const fix of fixData ?? []) {
|
|
304
|
+
const tokens = estimateTokens(`${fix.problem} ${fix.solution ?? ""}`);
|
|
305
|
+
if (tokensUsed + tokens > CONTEXT_BUDGET_TOKENS) break;
|
|
306
|
+
budgetedFixes.push(fix);
|
|
307
|
+
tokensUsed += tokens;
|
|
308
|
+
}
|
|
309
|
+
|
|
290
310
|
const memoryIds = budgetedMemories.map((m) => m.id);
|
|
291
311
|
const linkedIdsByMemory = new Map<string, Set<string>>();
|
|
292
312
|
|
|
@@ -323,6 +343,16 @@ async function cmdStart(project: string) {
|
|
|
323
343
|
console.log("");
|
|
324
344
|
}
|
|
325
345
|
|
|
346
|
+
if (budgetedFixes.length > 0) {
|
|
347
|
+
console.log(`Past Fixes (${budgetedFixes.length})`);
|
|
348
|
+
console.log("-".repeat(14));
|
|
349
|
+
for (const fix of budgetedFixes) {
|
|
350
|
+
console.log(` Problem: ${fix.problem}`);
|
|
351
|
+
console.log(` Solution: ${fix.solution ?? "(pending)"}`);
|
|
352
|
+
console.log("");
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
326
356
|
console.log(`Context budget: ${tokensUsed}/${CONTEXT_BUDGET_TOKENS} tokens used`);
|
|
327
357
|
if (omittedCount > 0) {
|
|
328
358
|
console.log(`${omittedCount} memories omitted (budget exceeded)`);
|
package/src/index.ts
CHANGED
|
@@ -92,6 +92,23 @@ server.registerTool(
|
|
|
92
92
|
linked_memory_ids: Array.from(linkedIdsByMemory.get(m.id) ?? []),
|
|
93
93
|
}));
|
|
94
94
|
|
|
95
|
+
const { data: fixData, error: fixError } = await supabase
|
|
96
|
+
.from("execution_log")
|
|
97
|
+
.select("*")
|
|
98
|
+
.eq("project", project)
|
|
99
|
+
.eq("resolved", false)
|
|
100
|
+
.order("created_at", { ascending: false })
|
|
101
|
+
.limit(5);
|
|
102
|
+
|
|
103
|
+
if (fixError) {
|
|
104
|
+
throw new Error(`Failed to load execution log: ${fixError.message}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const fixes = (fixData ?? []).map((fix) => ({
|
|
108
|
+
problem: fix.problem,
|
|
109
|
+
solution: fix.solution ?? "pending",
|
|
110
|
+
}));
|
|
111
|
+
|
|
95
112
|
if (budgetedMemories.length > 0) {
|
|
96
113
|
const incrementResults = await Promise.all(
|
|
97
114
|
budgetedMemories.map((memory) =>
|
|
@@ -116,6 +133,7 @@ server.registerTool(
|
|
|
116
133
|
content: [{ type: "text", text: budgetText }],
|
|
117
134
|
structuredContent: {
|
|
118
135
|
memories: memoriesWithLinks,
|
|
136
|
+
fixes,
|
|
119
137
|
context_budget: {
|
|
120
138
|
budget_tokens: CONTEXT_BUDGET_TOKENS,
|
|
121
139
|
tokens_used: tokensUsed,
|
package/src/scoring.ts
CHANGED
|
@@ -79,6 +79,12 @@ function containsNegationWord(text: string): boolean {
|
|
|
79
79
|
return NEGATION_WORDS.some((word) => lower.includes(word));
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// Hook-generated dependency-change templates (e.g. "removed dependency: X")
|
|
83
|
+
// are structural facts, not decisions — "removed" trips the negation-word
|
|
84
|
+
// check below, but there's nothing for them to supersede/contradict, so
|
|
85
|
+
// they're exempted up front rather than ever entering the negation branch.
|
|
86
|
+
const DEPENDENCY_TEMPLATE_RE = /^(removed|added) dependency:/i;
|
|
87
|
+
|
|
82
88
|
export type SaveAction =
|
|
83
89
|
| { action: "duplicate"; matchedId: string }
|
|
84
90
|
| { action: "superseded"; oldId: string }
|
|
@@ -97,7 +103,7 @@ export function decideSaveAction(
|
|
|
97
103
|
existingMemories: ExistingMemory[]
|
|
98
104
|
): SaveAction {
|
|
99
105
|
const newEntities = extractEntities(newContent);
|
|
100
|
-
const hasNegation = containsNegationWord(newContent);
|
|
106
|
+
const hasNegation = DEPENDENCY_TEMPLATE_RE.test(newContent) ? false : containsNegationWord(newContent);
|
|
101
107
|
|
|
102
108
|
let bestDuplicate: { id: string; score: number } | null = null;
|
|
103
109
|
let bestSupersede: { id: string; score: number } | null = null;
|