@kenkaiiii/ggcoder 4.14.3 → 4.15.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/dist/core/code-retrieval.d.ts +13 -0
- package/dist/core/code-retrieval.d.ts.map +1 -0
- package/dist/core/code-retrieval.js +87 -0
- package/dist/core/code-retrieval.js.map +1 -0
- package/dist/core/hashline-edit-benchmark.d.ts +55 -0
- package/dist/core/hashline-edit-benchmark.d.ts.map +1 -0
- package/dist/core/hashline-edit-benchmark.js +342 -0
- package/dist/core/hashline-edit-benchmark.js.map +1 -0
- package/dist/core/hashline-edit-benchmark.test.d.ts +2 -0
- package/dist/core/hashline-edit-benchmark.test.d.ts.map +1 -0
- package/dist/core/hashline-edit-benchmark.test.js +141 -0
- package/dist/core/hashline-edit-benchmark.test.js.map +1 -0
- package/dist/core/hashline.d.ts +50 -0
- package/dist/core/hashline.d.ts.map +1 -0
- package/dist/core/hashline.js +76 -0
- package/dist/core/hashline.js.map +1 -0
- package/dist/core/semantic-search-benchmark.d.ts +37 -0
- package/dist/core/semantic-search-benchmark.d.ts.map +1 -0
- package/dist/core/semantic-search-benchmark.js +211 -0
- package/dist/core/semantic-search-benchmark.js.map +1 -0
- package/dist/core/semantic-search-benchmark.test.d.ts +2 -0
- package/dist/core/semantic-search-benchmark.test.d.ts.map +1 -0
- package/dist/core/semantic-search-benchmark.test.js +89 -0
- package/dist/core/semantic-search-benchmark.test.js.map +1 -0
- package/dist/tools/edit.d.ts +6 -0
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +34 -2
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/edit.test.js +112 -0
- package/dist/tools/edit.test.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +8 -0
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read.d.ts +1 -0
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +14 -3
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/read.test.js +40 -0
- package/dist/tools/read.test.js.map +1 -1
- package/dist/tools/search-code.d.ts +11 -0
- package/dist/tools/search-code.d.ts.map +1 -0
- package/dist/tools/search-code.js +95 -0
- package/dist/tools/search-code.js.map +1 -0
- package/dist/tools/search-code.test.d.ts +2 -0
- package/dist/tools/search-code.test.d.ts.map +1 -0
- package/dist/tools/search-code.test.js +77 -0
- package/dist/tools/search-code.test.js.map +1 -0
- package/package.json +6 -4
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { lineHash, anchorFile } from "./hashline.js";
|
|
3
|
+
import { applyBaseline, applyHashline, checkAnchors, stripFence, genFile, buildTasks, } from "./hashline-edit-benchmark.js";
|
|
4
|
+
/**
|
|
5
|
+
* These tests prove the DETERMINISTIC half of the hashline benchmark — the
|
|
6
|
+
* apply + grading logic that decides OK / FAIL / corruption. The live-model
|
|
7
|
+
* numbers are only trustworthy if this logic is correct, so we exercise it from
|
|
8
|
+
* every angle: anchor uniqueness, corruption-avoidance, multi-edit ordering,
|
|
9
|
+
* malformed input, and the string-match baseline's ambiguity handling.
|
|
10
|
+
*/
|
|
11
|
+
/** Build a minimal EditTask around a hand-written file for precise assertions. */
|
|
12
|
+
function taskFor(file, mustContain, mustPreserve) {
|
|
13
|
+
return {
|
|
14
|
+
name: "t",
|
|
15
|
+
approxLines: file.split("\n").length,
|
|
16
|
+
file,
|
|
17
|
+
instruction: "",
|
|
18
|
+
mustContain,
|
|
19
|
+
mustPreserve,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const FN_FILE = [
|
|
23
|
+
"export function computeTimeout(cfg: Config): number {",
|
|
24
|
+
" return cfg.timeoutMs > 0 ? cfg.timeoutMs : DEFAULT_TIMEOUT;",
|
|
25
|
+
"}",
|
|
26
|
+
].join("\n");
|
|
27
|
+
/** The anchor for a given 0-based line index of a file. */
|
|
28
|
+
function anchorAt(file, index) {
|
|
29
|
+
return lineHash(file.split("\n")[index], index);
|
|
30
|
+
}
|
|
31
|
+
describe("hashline anchoring", () => {
|
|
32
|
+
it("1. folds line position into the hash so identical lines get distinct anchors", () => {
|
|
33
|
+
// Two identical lines at different positions must NOT collide.
|
|
34
|
+
expect(lineHash(" return x;", 3)).not.toBe(lineHash(" return x;", 9));
|
|
35
|
+
// Same content + same position is stable (deterministic).
|
|
36
|
+
expect(lineHash(" return x;", 3)).toBe(lineHash(" return x;", 3));
|
|
37
|
+
});
|
|
38
|
+
it("2. gives every line a unique resolvable anchor — even repeated blank lines", () => {
|
|
39
|
+
const file = ["a", "", "b", "", "c"].join("\n"); // two blank lines
|
|
40
|
+
const a = anchorFile(file);
|
|
41
|
+
expect(a.ambiguous.size).toBe(0);
|
|
42
|
+
expect(a.anchorToIndex.size).toBe(5);
|
|
43
|
+
expect([...a.anchorToIndex.values()].sort((x, y) => x - y)).toEqual([0, 1, 2, 3, 4]);
|
|
44
|
+
});
|
|
45
|
+
it("3. renders as `anchor│line` and the line column reconstructs the file", () => {
|
|
46
|
+
const a = anchorFile(FN_FILE);
|
|
47
|
+
const stripped = a.rendered
|
|
48
|
+
.split("\n")
|
|
49
|
+
.map((l) => l.slice(l.indexOf("│") + 1))
|
|
50
|
+
.join("\n");
|
|
51
|
+
expect(stripped).toBe(FN_FILE);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe("applyHashline (proposed)", () => {
|
|
55
|
+
it("4. applies a valid single-line edit and grades it correct", () => {
|
|
56
|
+
const anchored = anchorFile(FN_FILE);
|
|
57
|
+
const anchor = anchorAt(FN_FILE, 1); // the `return ...` line
|
|
58
|
+
const raw = JSON.stringify({
|
|
59
|
+
edits: [
|
|
60
|
+
{
|
|
61
|
+
from: anchor,
|
|
62
|
+
to: anchor,
|
|
63
|
+
lines: [
|
|
64
|
+
" return cfg.retries > 0 ? Math.min(cfg.timeoutMs * cfg.retries, 30000) : (cfg.timeoutMs > 0 ? cfg.timeoutMs : DEFAULT_TIMEOUT);",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
const task = taskFor(FN_FILE, ["cfg.timeoutMs * cfg.retries", "30000"], ["computeTimeout", "DEFAULT_TIMEOUT"]);
|
|
70
|
+
const out = applyHashline(raw, task, anchored);
|
|
71
|
+
expect(out.applied).toBe(true);
|
|
72
|
+
expect(out.correct).toBe(true);
|
|
73
|
+
expect(out.ambiguousEdits).toBe(0);
|
|
74
|
+
});
|
|
75
|
+
it("5. rejects an edit whose anchor is not in the file — never corrupts", () => {
|
|
76
|
+
const anchored = anchorFile(FN_FILE);
|
|
77
|
+
const raw = JSON.stringify({ edits: [{ from: "0000", to: "0000", lines: ["// hijacked"] }] });
|
|
78
|
+
const task = taskFor(FN_FILE, [], ["computeTimeout"]);
|
|
79
|
+
const out = applyHashline(raw, task, anchored);
|
|
80
|
+
expect(out.applied).toBe(false);
|
|
81
|
+
expect(out.correct).toBe(false);
|
|
82
|
+
expect(out.ambiguousEdits).toBe(1);
|
|
83
|
+
});
|
|
84
|
+
it("6. rejects a reversed range (from after to)", () => {
|
|
85
|
+
const anchored = anchorFile(FN_FILE);
|
|
86
|
+
const raw = JSON.stringify({
|
|
87
|
+
edits: [{ from: anchorAt(FN_FILE, 2), to: anchorAt(FN_FILE, 0), lines: ["x"] }],
|
|
88
|
+
});
|
|
89
|
+
const out = applyHashline(raw, taskFor(FN_FILE, [], []), anchored);
|
|
90
|
+
expect(out.applied).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
it("7. applies multiple edits bottom-up so earlier indices stay valid", () => {
|
|
93
|
+
const file = ["const a = 1;", "const b = 2;", "const c = 3;"].join("\n");
|
|
94
|
+
const anchored = anchorFile(file);
|
|
95
|
+
const raw = JSON.stringify({
|
|
96
|
+
edits: [
|
|
97
|
+
{ from: anchorAt(file, 0), to: anchorAt(file, 0), lines: ["const a = 10;"] },
|
|
98
|
+
{ from: anchorAt(file, 2), to: anchorAt(file, 2), lines: ["const c = 30;"] },
|
|
99
|
+
],
|
|
100
|
+
});
|
|
101
|
+
const out = applyHashline(raw, taskFor(file, ["const a = 10;", "const c = 30;"], ["const b = 2;"]), anchored);
|
|
102
|
+
expect(out.applied).toBe(true);
|
|
103
|
+
expect(out.correct).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
it("8. returns a clean failure on malformed JSON instead of throwing", () => {
|
|
106
|
+
const anchored = anchorFile(FN_FILE);
|
|
107
|
+
expect(() => applyHashline("not json {", taskFor(FN_FILE, [], []), anchored)).not.toThrow();
|
|
108
|
+
const out = applyHashline("not json {", taskFor(FN_FILE, [], []), anchored);
|
|
109
|
+
expect(out.applied).toBe(false);
|
|
110
|
+
expect(out.parsedEdits).toBe(0);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe("applyBaseline (current string-match) + helpers", () => {
|
|
114
|
+
it("9. applies a unique old_text but rejects a non-unique one", () => {
|
|
115
|
+
const unique = taskFor("const x = 1;\nconst y = 2;\n", ["const x = 100;"], ["const y = 2;"]);
|
|
116
|
+
const okRaw = JSON.stringify({
|
|
117
|
+
edits: [{ old_text: "const x = 1;", new_text: "const x = 100;" }],
|
|
118
|
+
});
|
|
119
|
+
expect(applyBaseline(okRaw, unique).applied).toBe(true);
|
|
120
|
+
// Same literal appears twice → the real edit tool refuses; so must we.
|
|
121
|
+
const dup = taskFor("const x = 1;\nconst y = 2;\nconst x = 1;\n", [], []);
|
|
122
|
+
const dupRaw = JSON.stringify({
|
|
123
|
+
edits: [{ old_text: "const x = 1;", new_text: "const x = 9;" }],
|
|
124
|
+
});
|
|
125
|
+
const out = applyBaseline(dupRaw, dup);
|
|
126
|
+
expect(out.applied).toBe(false);
|
|
127
|
+
expect(out.ambiguousEdits).toBe(1);
|
|
128
|
+
});
|
|
129
|
+
it("10. flags not-found old_text, strips code fences, and grades generated tasks", () => {
|
|
130
|
+
// Paraphrased / drifted old_text that isn't in the file → rejected.
|
|
131
|
+
const notFound = JSON.stringify({ edits: [{ old_text: "const z = 0;", new_text: "x" }] });
|
|
132
|
+
expect(applyBaseline(notFound, taskFor("const a = 1;\n", [], [])).applied).toBe(false);
|
|
133
|
+
// stripFence removes ```ts ... ``` wrappers the model sometimes adds.
|
|
134
|
+
expect(stripFence('```ts\n{"edits":[]}\n```')).toBe('{"edits":[]}');
|
|
135
|
+
// The generator + grader agree: a freshly generated file preserves its anchors.
|
|
136
|
+
const task = buildTasks()[0];
|
|
137
|
+
expect(genFile(task.approxLines)).toContain("computeTimeout");
|
|
138
|
+
expect(checkAnchors(task.file, taskFor(task.file, [], task.mustPreserve))).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=hashline-edit-benchmark.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline-edit-benchmark.test.js","sourceRoot":"","sources":["../../src/core/hashline-edit-benchmark.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 4-hex-char anchor for a line. Position is folded into the hash so anchors are
|
|
3
|
+
* UNIQUE by construction (blank lines and repeated lines no longer collide).
|
|
4
|
+
* Resolution stays O(1) via a lookup map. `index` is the 0-based line index.
|
|
5
|
+
*/
|
|
6
|
+
export declare function lineHash(line: string, index: number): string;
|
|
7
|
+
/** File rendered with `anchor│line` prefixes for the model to read. */
|
|
8
|
+
export declare function renderWithAnchors(file: string): string;
|
|
9
|
+
export interface AnchoredFile {
|
|
10
|
+
/** File rendered with `anchor│line` prefixes for the model to read. */
|
|
11
|
+
rendered: string;
|
|
12
|
+
/** anchor → line index (0-based). Only UNIQUE anchors are resolvable. */
|
|
13
|
+
anchorToIndex: Map<string, number>;
|
|
14
|
+
/** anchors that collided (ambiguous → unresolvable, like a stale-file reject). */
|
|
15
|
+
ambiguous: Set<string>;
|
|
16
|
+
lines: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function anchorFile(file: string): AnchoredFile;
|
|
19
|
+
/**
|
|
20
|
+
* True when the line at `index` (0-based) still hashes to `hash`. Out-of-range
|
|
21
|
+
* indices return false. This is the staleness gate the edit tool uses.
|
|
22
|
+
*/
|
|
23
|
+
export declare function verifyAnchor(lines: string[], index: number, hash: string): boolean;
|
|
24
|
+
/** Optional per-edit anchor guard: pin both endpoints of an edit by line+hash. */
|
|
25
|
+
export interface EditAnchor {
|
|
26
|
+
/** 1-based line number of the first line of the edited span. */
|
|
27
|
+
start_line: number;
|
|
28
|
+
/** Content anchor of the first line (from a `read` with `anchors: true`). */
|
|
29
|
+
start_hash: string;
|
|
30
|
+
/** 1-based line number of the last line of the edited span. */
|
|
31
|
+
end_line: number;
|
|
32
|
+
/** Content anchor of the last line. */
|
|
33
|
+
end_hash: string;
|
|
34
|
+
}
|
|
35
|
+
export type AnchorFailure = "out_of_range" | "hash_mismatch" | "reversed";
|
|
36
|
+
export interface AnchorResolution {
|
|
37
|
+
ok: boolean;
|
|
38
|
+
/** 0-based index of the first line (only when ok). */
|
|
39
|
+
startIndex?: number;
|
|
40
|
+
/** 0-based index of the last line (only when ok). */
|
|
41
|
+
endIndex?: number;
|
|
42
|
+
reason?: AnchorFailure;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve an anchor against the current file lines (0-based). Rejects the edit
|
|
46
|
+
* if either endpoint is out of range, the range is reversed, or either hash no
|
|
47
|
+
* longer matches — the corruption-avoidance property.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveAnchoredEdit(lines: string[], anchor: EditAnchor): AnchorResolution;
|
|
50
|
+
//# sourceMappingURL=hashline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline.d.ts","sourceRoot":"","sources":["../../src/core/hashline.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,kFAAkF;IAClF,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAiBrD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGlF;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,eAAe,GAAG,UAAU,CAAC;AAE1E,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,UAAU,GAAG,gBAAgB,CAgBzF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash-anchored line addressing — the pure, UI-free core shared by the hashline
|
|
3
|
+
* benchmark and the opt-in anchor guard in the read/edit tools.
|
|
4
|
+
*
|
|
5
|
+
* Every line gets a short content+position hash. Anchors are UNIQUE by
|
|
6
|
+
* construction (the line's index is folded into the hash, so blank/repeated
|
|
7
|
+
* lines never collide), which is what lets an edit either resolve to exactly one
|
|
8
|
+
* location or be rejected — never silently corrupt a file that drifted since the
|
|
9
|
+
* model last read it.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
/**
|
|
13
|
+
* 4-hex-char anchor for a line. Position is folded into the hash so anchors are
|
|
14
|
+
* UNIQUE by construction (blank lines and repeated lines no longer collide).
|
|
15
|
+
* Resolution stays O(1) via a lookup map. `index` is the 0-based line index.
|
|
16
|
+
*/
|
|
17
|
+
export function lineHash(line, index) {
|
|
18
|
+
return createHash("sha1").update(`${index}:${line.trim()}`).digest("hex").slice(0, 4);
|
|
19
|
+
}
|
|
20
|
+
/** File rendered with `anchor│line` prefixes for the model to read. */
|
|
21
|
+
export function renderWithAnchors(file) {
|
|
22
|
+
return file
|
|
23
|
+
.split("\n")
|
|
24
|
+
.map((l, i) => `${lineHash(l, i)}│${l}`)
|
|
25
|
+
.join("\n");
|
|
26
|
+
}
|
|
27
|
+
export function anchorFile(file) {
|
|
28
|
+
const lines = file.split("\n");
|
|
29
|
+
const counts = new Map();
|
|
30
|
+
lines.forEach((l, i) => {
|
|
31
|
+
const h = lineHash(l, i);
|
|
32
|
+
const arr = counts.get(h) ?? [];
|
|
33
|
+
arr.push(i);
|
|
34
|
+
counts.set(h, arr);
|
|
35
|
+
});
|
|
36
|
+
const anchorToIndex = new Map();
|
|
37
|
+
const ambiguous = new Set();
|
|
38
|
+
for (const [h, idxs] of counts) {
|
|
39
|
+
// Position-folded anchors are unique unless sha1 itself collides in 16 bits.
|
|
40
|
+
if (idxs.length === 1)
|
|
41
|
+
anchorToIndex.set(h, idxs[0]);
|
|
42
|
+
else
|
|
43
|
+
ambiguous.add(h);
|
|
44
|
+
}
|
|
45
|
+
return { rendered: renderWithAnchors(file), anchorToIndex, ambiguous, lines };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* True when the line at `index` (0-based) still hashes to `hash`. Out-of-range
|
|
49
|
+
* indices return false. This is the staleness gate the edit tool uses.
|
|
50
|
+
*/
|
|
51
|
+
export function verifyAnchor(lines, index, hash) {
|
|
52
|
+
if (index < 0 || index >= lines.length)
|
|
53
|
+
return false;
|
|
54
|
+
return lineHash(lines[index], index) === hash;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolve an anchor against the current file lines (0-based). Rejects the edit
|
|
58
|
+
* if either endpoint is out of range, the range is reversed, or either hash no
|
|
59
|
+
* longer matches — the corruption-avoidance property.
|
|
60
|
+
*/
|
|
61
|
+
export function resolveAnchoredEdit(lines, anchor) {
|
|
62
|
+
const startIndex = anchor.start_line - 1;
|
|
63
|
+
const endIndex = anchor.end_line - 1;
|
|
64
|
+
if (startIndex < 0 || endIndex < 0 || startIndex >= lines.length || endIndex >= lines.length) {
|
|
65
|
+
return { ok: false, reason: "out_of_range" };
|
|
66
|
+
}
|
|
67
|
+
if (startIndex > endIndex) {
|
|
68
|
+
return { ok: false, reason: "reversed" };
|
|
69
|
+
}
|
|
70
|
+
if (!verifyAnchor(lines, startIndex, anchor.start_hash) ||
|
|
71
|
+
!verifyAnchor(lines, endIndex, anchor.end_hash)) {
|
|
72
|
+
return { ok: false, reason: "hash_mismatch" };
|
|
73
|
+
}
|
|
74
|
+
return { ok: true, startIndex, endIndex };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=hashline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashline.js","sourceRoot":"","sources":["../../src/core/hashline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic AST-chunk retrieval vs whole-file reads — real-API measurement of
|
|
3
|
+
* whether Feature #3 is worth building.
|
|
4
|
+
*
|
|
5
|
+
* The claim (cocoindex-code / oh-my-pi): replacing "grep then read whole files"
|
|
6
|
+
* with "retrieve only the relevant AST chunks" cuts ~70% of the tokens an agent
|
|
7
|
+
* spends locating code, with no loss of answer quality. We test that directly on
|
|
8
|
+
* OUR OWN repo against a live model.
|
|
9
|
+
*
|
|
10
|
+
* For a set of natural-language questions about real files in this repo, we build
|
|
11
|
+
* three context strategies and ask the model the same question with each:
|
|
12
|
+
*
|
|
13
|
+
* BASELINE (whole-file): deliver the FULL text of the top files a lexical
|
|
14
|
+
* grep would surface — this is what the agent reads today (read + grep).
|
|
15
|
+
*
|
|
16
|
+
* SEMANTIC (AST chunks): parse every file into top-level declarations
|
|
17
|
+
* (functions / classes / interfaces / consts), rank chunks with a real BM25
|
|
18
|
+
* retriever, and deliver only the top-k chunks. No embedding model needed; a
|
|
19
|
+
* learned embedding retriever would land between BM25 and ORACLE.
|
|
20
|
+
*
|
|
21
|
+
* ORACLE (upper bound): deliver only the hand-labelled answer chunk(s) — the
|
|
22
|
+
* best case any retriever could achieve.
|
|
23
|
+
*
|
|
24
|
+
* We measure, per question and strategy: INPUT tokens delivered (the headline
|
|
25
|
+
* cost) and whether the model's answer was correct (deterministic keyword grade).
|
|
26
|
+
* The verdict: does SEMANTIC reach BASELINE-level correctness at a fraction of
|
|
27
|
+
* the input tokens?
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* npx tsx src/core/semantic-search-benchmark.ts
|
|
31
|
+
*
|
|
32
|
+
* Env overrides:
|
|
33
|
+
* GG_SS_PROVIDER / GG_SS_MODEL (default openai / gpt-5.5)
|
|
34
|
+
* GG_SS_TOPK (chunks/files delivered, default 3)
|
|
35
|
+
*/
|
|
36
|
+
export declare function grade(answer: string, mustInclude: string[]): boolean;
|
|
37
|
+
//# sourceMappingURL=semantic-search-benchmark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-search-benchmark.d.ts","sourceRoot":"","sources":["../../src/core/semantic-search-benchmark.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAwHH,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAGpE"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic AST-chunk retrieval vs whole-file reads — real-API measurement of
|
|
3
|
+
* whether Feature #3 is worth building.
|
|
4
|
+
*
|
|
5
|
+
* The claim (cocoindex-code / oh-my-pi): replacing "grep then read whole files"
|
|
6
|
+
* with "retrieve only the relevant AST chunks" cuts ~70% of the tokens an agent
|
|
7
|
+
* spends locating code, with no loss of answer quality. We test that directly on
|
|
8
|
+
* OUR OWN repo against a live model.
|
|
9
|
+
*
|
|
10
|
+
* For a set of natural-language questions about real files in this repo, we build
|
|
11
|
+
* three context strategies and ask the model the same question with each:
|
|
12
|
+
*
|
|
13
|
+
* BASELINE (whole-file): deliver the FULL text of the top files a lexical
|
|
14
|
+
* grep would surface — this is what the agent reads today (read + grep).
|
|
15
|
+
*
|
|
16
|
+
* SEMANTIC (AST chunks): parse every file into top-level declarations
|
|
17
|
+
* (functions / classes / interfaces / consts), rank chunks with a real BM25
|
|
18
|
+
* retriever, and deliver only the top-k chunks. No embedding model needed; a
|
|
19
|
+
* learned embedding retriever would land between BM25 and ORACLE.
|
|
20
|
+
*
|
|
21
|
+
* ORACLE (upper bound): deliver only the hand-labelled answer chunk(s) — the
|
|
22
|
+
* best case any retriever could achieve.
|
|
23
|
+
*
|
|
24
|
+
* We measure, per question and strategy: INPUT tokens delivered (the headline
|
|
25
|
+
* cost) and whether the model's answer was correct (deterministic keyword grade).
|
|
26
|
+
* The verdict: does SEMANTIC reach BASELINE-level correctness at a fraction of
|
|
27
|
+
* the input tokens?
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* npx tsx src/core/semantic-search-benchmark.ts
|
|
31
|
+
*
|
|
32
|
+
* Env overrides:
|
|
33
|
+
* GG_SS_PROVIDER / GG_SS_MODEL (default openai / gpt-5.5)
|
|
34
|
+
* GG_SS_TOPK (chunks/files delivered, default 3)
|
|
35
|
+
*/
|
|
36
|
+
import fs from "node:fs";
|
|
37
|
+
import path from "node:path";
|
|
38
|
+
import { fileURLToPath } from "node:url";
|
|
39
|
+
import { stream } from "@kenkaiiii/gg-ai";
|
|
40
|
+
import { AuthStorage } from "./auth-storage.js";
|
|
41
|
+
import { chunkFile, bm25Rank, rankFiles } from "./code-retrieval.js";
|
|
42
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
43
|
+
const SRC = path.resolve(HERE, ".."); // packages/ggcoder/src
|
|
44
|
+
const QUESTIONS = [
|
|
45
|
+
{
|
|
46
|
+
q: "Which method resolves provider credentials and auto-refreshes expired OAuth tokens, and what happens if it is not logged in?",
|
|
47
|
+
files: ["core/auth-storage.ts", "core/loop-breaker.ts", "tools/edit-diff.ts"],
|
|
48
|
+
oracle: { file: "core/auth-storage.ts", symbol: "resolveCredentials" },
|
|
49
|
+
mustInclude: ["resolvecredentials", "refresh"],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
q: "What function performs fuzzy text matching for the edit tool, and how does it tolerate indentation drift?",
|
|
53
|
+
files: ["tools/edit-diff.ts", "core/auth-storage.ts", "core/checkpoint-store.ts"],
|
|
54
|
+
oracle: { file: "tools/edit-diff.ts", symbol: "fuzzyFindText" },
|
|
55
|
+
mustInclude: ["fuzzyfindtext", "indent"],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
q: "What restore modes does the checkpoint / rewind system support?",
|
|
59
|
+
files: ["core/checkpoint-store.ts", "core/loop-breaker.ts", "tools/edit-diff.ts"],
|
|
60
|
+
oracle: { file: "core/checkpoint-store.ts", symbol: "RestoreMode" },
|
|
61
|
+
mustInclude: ["code", "conversation", "both"],
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
function sleep(ms) {
|
|
65
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
66
|
+
}
|
|
67
|
+
async function ask(provider, model, c, context, question) {
|
|
68
|
+
const messages = [
|
|
69
|
+
{
|
|
70
|
+
role: "system",
|
|
71
|
+
content: "You answer questions about a codebase using ONLY the provided context. " +
|
|
72
|
+
"Be specific: name the exact functions/types involved. If the context is insufficient, say so. " +
|
|
73
|
+
"Answer in 1-3 sentences.",
|
|
74
|
+
},
|
|
75
|
+
{ role: "user", content: `CONTEXT:\n${context}\n\nQUESTION: ${question}` },
|
|
76
|
+
];
|
|
77
|
+
let lastErr;
|
|
78
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
79
|
+
try {
|
|
80
|
+
let text = "";
|
|
81
|
+
const result = stream({
|
|
82
|
+
provider: provider,
|
|
83
|
+
model,
|
|
84
|
+
messages,
|
|
85
|
+
maxTokens: 512,
|
|
86
|
+
apiKey: c.apiKey,
|
|
87
|
+
baseUrl: c.baseUrl,
|
|
88
|
+
accountId: c.accountId,
|
|
89
|
+
});
|
|
90
|
+
for await (const event of result) {
|
|
91
|
+
if (event.type === "text_delta")
|
|
92
|
+
text += event.text;
|
|
93
|
+
}
|
|
94
|
+
const response = await result.response;
|
|
95
|
+
const content = response.message.content;
|
|
96
|
+
const finalText = typeof content === "string"
|
|
97
|
+
? content
|
|
98
|
+
: content
|
|
99
|
+
.filter((p) => p.type === "text")
|
|
100
|
+
.map((p) => p.text ?? "")
|
|
101
|
+
.join("");
|
|
102
|
+
return {
|
|
103
|
+
text: finalText || text,
|
|
104
|
+
inputTokens: response.usage.inputTokens,
|
|
105
|
+
outputTokens: response.usage.outputTokens,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
lastErr = err;
|
|
110
|
+
await sleep(2000 * (attempt + 1));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
throw lastErr;
|
|
114
|
+
}
|
|
115
|
+
export function grade(answer, mustInclude) {
|
|
116
|
+
const a = answer.toLowerCase();
|
|
117
|
+
return mustInclude.every((t) => a.includes(t));
|
|
118
|
+
}
|
|
119
|
+
async function main() {
|
|
120
|
+
const provider = process.env.GG_SS_PROVIDER ?? "openai";
|
|
121
|
+
const model = process.env.GG_SS_MODEL ?? "gpt-5.5";
|
|
122
|
+
const topK = Math.max(1, parseInt(process.env.GG_SS_TOPK ?? "3", 10));
|
|
123
|
+
const auth = new AuthStorage();
|
|
124
|
+
await auth.load();
|
|
125
|
+
const cr = await auth.resolveCredentials(provider);
|
|
126
|
+
const creds = { apiKey: cr.accessToken, baseUrl: cr.baseUrl, accountId: cr.accountId };
|
|
127
|
+
console.log(`\n🔎 Semantic-search benchmark — ${provider}/${model} (top-${topK})\n`);
|
|
128
|
+
const rows = [];
|
|
129
|
+
for (const q of QUESTIONS) {
|
|
130
|
+
// Load the real corpus files; skip the question if any are missing/moved.
|
|
131
|
+
const files = new Map();
|
|
132
|
+
let missing = false;
|
|
133
|
+
for (const rel of q.files) {
|
|
134
|
+
const abs = path.join(SRC, rel);
|
|
135
|
+
if (!fs.existsSync(abs)) {
|
|
136
|
+
console.log(` ⚠ skipping question — missing ${rel}`);
|
|
137
|
+
missing = true;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
files.set(rel, fs.readFileSync(abs, "utf-8"));
|
|
141
|
+
}
|
|
142
|
+
if (missing)
|
|
143
|
+
continue;
|
|
144
|
+
// BASELINE context: full text of the top-k files a grep would surface.
|
|
145
|
+
const baseFiles = rankFiles(q.q, files, topK);
|
|
146
|
+
const baseContext = baseFiles.map((f) => `// FILE: ${f}\n${files.get(f)}`).join("\n\n");
|
|
147
|
+
// SEMANTIC context: top-k AST chunks across all corpus files.
|
|
148
|
+
const allChunks = [...files].flatMap(([rel, src]) => chunkFile(rel, src));
|
|
149
|
+
const semChunks = bm25Rank(q.q, allChunks, topK);
|
|
150
|
+
const semContext = semChunks.map((c) => `// ${c.file} → ${c.symbol}\n${c.text}`).join("\n\n");
|
|
151
|
+
// ORACLE context: just the labelled answer chunk.
|
|
152
|
+
const oracleChunk = allChunks.find((c) => c.file === q.oracle.file && c.symbol === q.oracle.symbol);
|
|
153
|
+
const oracleContext = oracleChunk
|
|
154
|
+
? `// ${oracleChunk.file} → ${oracleChunk.symbol}\n${oracleChunk.text}`
|
|
155
|
+
: semContext;
|
|
156
|
+
process.stdout.write(`▶ ${q.q.slice(0, 64)}…\n`);
|
|
157
|
+
await sleep(1200);
|
|
158
|
+
const base = await ask(provider, model, creds, baseContext, q.q);
|
|
159
|
+
await sleep(1200);
|
|
160
|
+
const sem = await ask(provider, model, creds, semContext, q.q);
|
|
161
|
+
await sleep(1200);
|
|
162
|
+
const oracle = await ask(provider, model, creds, oracleContext, q.q);
|
|
163
|
+
const row = {
|
|
164
|
+
q: q.q.slice(0, 40),
|
|
165
|
+
baseInTok: base.inputTokens,
|
|
166
|
+
baseOk: grade(base.text, q.mustInclude),
|
|
167
|
+
semInTok: sem.inputTokens,
|
|
168
|
+
semOk: grade(sem.text, q.mustInclude),
|
|
169
|
+
oracleInTok: oracle.inputTokens,
|
|
170
|
+
oracleOk: grade(oracle.text, q.mustInclude),
|
|
171
|
+
};
|
|
172
|
+
rows.push(row);
|
|
173
|
+
process.stdout.write(` baseline ${row.baseInTok} in tok ${row.baseOk ? "OK" : "FAIL"} | ` +
|
|
174
|
+
`semantic ${row.semInTok} in tok ${row.semOk ? "OK" : "FAIL"} | ` +
|
|
175
|
+
`oracle ${row.oracleInTok} in tok ${row.oracleOk ? "OK" : "FAIL"}\n\n`);
|
|
176
|
+
}
|
|
177
|
+
if (rows.length === 0) {
|
|
178
|
+
console.log("No questions ran (corpus files not found).");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// ── Report ──
|
|
182
|
+
console.log("══════════════════════ RESULTS ══════════════════════\n");
|
|
183
|
+
console.log("Question | base in-tok | sem in-tok | oracle | ok b/s/o");
|
|
184
|
+
for (const r of rows) {
|
|
185
|
+
console.log(`${r.q.padEnd(40)} | ${String(r.baseInTok).padStart(11)} | ${String(r.semInTok).padStart(10)} | ` +
|
|
186
|
+
`${String(r.oracleInTok).padStart(6)} | ${r.baseOk ? "1" : "0"}/${r.semOk ? "1" : "0"}/${r.oracleOk ? "1" : "0"}`);
|
|
187
|
+
}
|
|
188
|
+
const sum = (f) => rows.reduce((s, r) => s + f(r), 0);
|
|
189
|
+
const baseIn = sum((r) => r.baseInTok);
|
|
190
|
+
const semIn = sum((r) => r.semInTok);
|
|
191
|
+
const oracleIn = sum((r) => r.oracleInTok);
|
|
192
|
+
console.log(`\nInput tokens to answer: baseline ${baseIn} | semantic ${semIn} ` +
|
|
193
|
+
`(${(((baseIn - semIn) / baseIn) * 100).toFixed(0)}% fewer) | oracle ${oracleIn} ` +
|
|
194
|
+
`(${(((baseIn - oracleIn) / baseIn) * 100).toFixed(0)}% fewer)`);
|
|
195
|
+
console.log(`Correctness: baseline ${rows.filter((r) => r.baseOk).length}/${rows.length} | ` +
|
|
196
|
+
`semantic ${rows.filter((r) => r.semOk).length}/${rows.length} | ` +
|
|
197
|
+
`oracle ${rows.filter((r) => r.oracleOk).length}/${rows.length}`);
|
|
198
|
+
console.log(`\nVerdict: worth building if SEMANTIC keeps correctness ≈ baseline while cutting input tokens. ` +
|
|
199
|
+
`cocoindex claims ~70% fewer; ORACLE shows the ceiling a better (embedding) retriever could reach.\n`);
|
|
200
|
+
}
|
|
201
|
+
// Run when executed directly (not when imported by tests).
|
|
202
|
+
const isDirectRun = process.argv[1]?.endsWith("semantic-search-benchmark.ts") ||
|
|
203
|
+
process.argv[1]?.endsWith("semantic-search-benchmark.js") ||
|
|
204
|
+
process.argv[1]?.endsWith("semantic-search-benchmark");
|
|
205
|
+
if (isDirectRun) {
|
|
206
|
+
main().catch((err) => {
|
|
207
|
+
console.error("Benchmark failed:", err);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=semantic-search-benchmark.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-search-benchmark.js","sourceRoot":"","sources":["../../src/core/semantic-search-benchmark.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-search-benchmark.test.d.ts","sourceRoot":"","sources":["../../src/core/semantic-search-benchmark.test.ts"],"names":[],"mappings":""}
|