moncefem Claude Opus 5 commited on
Commit
930bb27
·
1 Parent(s): cf42de0

Clean the model mirror

Browse files

Removes ~11.6GB of weights that should not be published:
- sixview_v1/v2 checkpoints. sixview_v2 is the pre-standardisation head that
scored WORSE than applying no adapter (and worse than random noise); leaving
it downloadable invites someone to use it. Their metrics.jsonl stay for
provenance.
- duplicate all_lora/head.best.pt (same bytes as all_lora_best_cpt.pth) and a
stray h200_best/ copy.
- 49 files of snapshot_download bookkeeping under data/**/.cache/.

Keeps the two checkpoints worth having: all_lora_best_cpt.pth (merged corpus,
best) and h200_run/head.best.pt (prose-only, fallback).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +3 -0
  2. app/engine/generate_and_merge.py +27 -1
  3. app/engine/serve_fallback.py +37 -21
  4. app/src/app/api/jobs/[jobId]/route.ts +41 -0
  5. app/src/app/api/jobs/[jobId]/server/route.ts +118 -0
  6. app/src/app/compare/page.tsx +3 -268
  7. app/src/app/globals.css +17 -0
  8. app/src/app/page.tsx +321 -97
  9. app/src/app/serve/page.tsx +161 -0
  10. app/src/app/v1/[...path]/route.ts +12 -3
  11. data/real_code2lora/code2lora-evo/.cache/huggingface/.gitignore +0 -1
  12. data/real_code2lora/code2lora-evo/.cache/huggingface/CACHEDIR.TAG +0 -4
  13. data/real_code2lora/code2lora-evo/.cache/huggingface/download/.gitattributes.metadata +0 -3
  14. data/real_code2lora/code2lora-evo/.cache/huggingface/download/README.md.metadata +0 -3
  15. data/real_code2lora/code2lora-evo/.cache/huggingface/download/commits/cr_test.parquet.metadata +0 -3
  16. data/real_code2lora/code2lora-evo/.cache/huggingface/download/commits/cr_val.parquet.metadata +0 -3
  17. data/real_code2lora/code2lora-evo/.cache/huggingface/download/commits/train.parquet.metadata +0 -3
  18. data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/cr_test.parquet.metadata +0 -3
  19. data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/cr_val.parquet.metadata +0 -3
  20. data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/ir_test.parquet.metadata +0 -3
  21. data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/ir_val.parquet.metadata +0 -3
  22. data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/train.parquet.metadata +0 -3
  23. data/real_code2lora/code2lora-evo/.cache/huggingface/trees/93a9e8240b9482092ecc768b804cc62bae1e875a.json +0 -69
  24. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/.gitignore +0 -1
  25. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/CACHEDIR.TAG +0 -4
  26. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/.gitattributes.metadata +0 -3
  27. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/README.md.metadata +0 -3
  28. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/cr_test.parquet.metadata +0 -3
  29. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/cr_val.parquet.metadata +0 -3
  30. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/ir_test.parquet.metadata +0 -3
  31. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/ir_val.parquet.metadata +0 -3
  32. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/train.parquet.metadata +0 -3
  33. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/cr_test.parquet.metadata +0 -3
  34. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/cr_val.parquet.metadata +0 -3
  35. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/ir_test.parquet.metadata +0 -3
  36. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/ir_val.parquet.metadata +0 -3
  37. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/train.parquet.metadata +0 -3
  38. data/real_code2lora/code2lora-static-anchor/.cache/huggingface/trees/65b7c77eed9398fc656052d058e9af7c2d432177.json +0 -83
  39. data/real_code2lora/code2lora-static/.cache/huggingface/.gitignore +0 -1
  40. data/real_code2lora/code2lora-static/.cache/huggingface/CACHEDIR.TAG +0 -4
  41. data/real_code2lora/code2lora-static/.cache/huggingface/download/.gitattributes.metadata +0 -3
  42. data/real_code2lora/code2lora-static/.cache/huggingface/download/README.md.metadata +0 -3
  43. data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/cr_test.parquet.metadata +0 -3
  44. data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/cr_val.parquet.metadata +0 -3
  45. data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/ir_test.parquet.metadata +0 -3
  46. data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/ir_val.parquet.metadata +0 -3
  47. data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/train.parquet.metadata +0 -3
  48. data/real_code2lora/code2lora-static/.cache/huggingface/download/repos/cr_test.parquet.metadata +0 -3
  49. data/real_code2lora/code2lora-static/.cache/huggingface/download/repos/cr_val.parquet.metadata +0 -3
  50. data/real_code2lora/code2lora-static/.cache/huggingface/download/repos/train.parquet.metadata +0 -3
.gitignore CHANGED
@@ -63,3 +63,6 @@ app/next-env.d.ts
63
  # Local scratch training run (checkpoint rewritten every step — never commit)
64
  runs/local_stdfix/
65
  runs/stdfix_test/
 
 
 
 
63
  # Local scratch training run (checkpoint rewritten every step — never commit)
64
  runs/local_stdfix/
65
  runs/stdfix_test/
66
+
67
+ # HF-mirror hygiene: snapshot_download bookkeeping, never useful to publish
68
+ data/**/.cache/
app/engine/generate_and_merge.py CHANGED
@@ -45,8 +45,34 @@ _DTYPES = {"bfloat16": torch.bfloat16, "float16": torch.float16,
45
  "float32": torch.float32}
46
 
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  def load_head(checkpoint: Path):
49
- ckpt = torch.load(checkpoint, map_location="cpu")
 
 
 
 
 
50
  cfg = ckpt["config"]
51
  head = MemoryLoRAHead(
52
  input_dim=cfg["input_dim"],
 
45
  "float32": torch.float32}
46
 
47
 
48
+ def _assert_real_checkpoint(path: Path) -> None:
49
+ """Fail with an actionable message when the file is a git-LFS pointer.
50
+
51
+ A pointer is ~130 bytes of text starting "version https://git-lfs...".
52
+ Handed to torch.load it surfaces as `Unsupported operand 118` or
53
+ `invalid load key, 'v'` -- opcode 'v', the first byte of "version" -- which
54
+ reads like a corrupt checkpoint rather than a file that was never fetched.
55
+ Any `GIT_LFS_SKIP_SMUDGE=1` clone or pull leaves checkpoints in this state.
56
+ """
57
+ if not path.exists():
58
+ raise FileNotFoundError(f"checkpoint not found: {path}")
59
+ if path.stat().st_size < 5000:
60
+ head = path.read_bytes()[:64]
61
+ if head.startswith(b"version https://git-lfs"):
62
+ raise RuntimeError(
63
+ f"{path} is a git-LFS pointer, not the checkpoint "
64
+ f"({path.stat().st_size} bytes). Fetch it with:\n"
65
+ f" git lfs pull --include=\"{path}\""
66
+ )
67
+
68
+
69
  def load_head(checkpoint: Path):
70
+ _assert_real_checkpoint(Path(checkpoint))
71
+ # weights_only=False: these checkpoints carry the run's config/args dicts,
72
+ # not just tensors, and torch>=2.6 defaults the strict unpickler on --
73
+ # which rejects them ("Unsupported operand"). They are produced by this
74
+ # project's own training script, so loading them fully is intended.
75
+ ckpt = torch.load(checkpoint, map_location="cpu", weights_only=False)
76
  cfg = ckpt["config"]
77
  head = MemoryLoRAHead(
78
  input_dim=cfg["input_dim"],
app/engine/serve_fallback.py CHANGED
@@ -155,6 +155,16 @@ class Engine:
155
  def stream(self, prompt: str, max_new_tokens: int, temperature: float,
156
  top_p: float, stop: list[str] | None = None,
157
  use_adapter: bool = True):
 
 
 
 
 
 
 
 
 
 
158
  from transformers import TextIteratorStreamer
159
  enc = self.tok(prompt, return_tensors="pt").to(self.device)
160
  streamer = TextIteratorStreamer(
@@ -167,29 +177,35 @@ class Engine:
167
  pad_token_id=self.tok.pad_token_id or self.tok.eos_token_id,
168
  streamer=streamer,
169
  )
170
- def _run():
171
- with self._maybe_off(use_adapter):
172
- self.model.generate(**kwargs)
173
- threading.Thread(target=_run, daemon=True).start()
174
-
175
  stops = self._stops(stop)
176
- # A stop sequence can straddle two streamed pieces, so emit only the
177
- # part of the buffer that can no longer become part of a stop string.
178
  hold = max(len(s) for s in stops)
179
- buf, emitted = "", 0
180
- for piece in streamer:
181
- buf += piece
182
- cut, hit = self._truncate_at_stop(buf, stops)
183
- if hit:
184
- if len(cut) > emitted:
185
- yield cut[emitted:]
186
- return
187
- safe = max(0, len(buf) - hold)
188
- if safe > emitted:
189
- yield buf[emitted:safe]
190
- emitted = safe
191
- if len(buf) > emitted:
192
- yield buf[emitted:]
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
 
195
  ENGINE: Engine | None = None
 
155
  def stream(self, prompt: str, max_new_tokens: int, temperature: float,
156
  top_p: float, stop: list[str] | None = None,
157
  use_adapter: bool = True):
158
+ """Stream tokens, with the adapter toggled for the WHOLE operation.
159
+
160
+ The enable/disable must wrap the entire generator -- both the worker
161
+ thread and the consumption of the streamer -- and the thread must be
162
+ joined before the context exits. PEFT's disable_adapter() flips state on
163
+ the shared model, so if the context closed while the next request was
164
+ already starting, that request would silently run with the wrong
165
+ adapter state. Putting the context inside the worker thread did exactly
166
+ that: base and adapted both came back as base.
167
+ """
168
  from transformers import TextIteratorStreamer
169
  enc = self.tok(prompt, return_tensors="pt").to(self.device)
170
  streamer = TextIteratorStreamer(
 
177
  pad_token_id=self.tok.pad_token_id or self.tok.eos_token_id,
178
  streamer=streamer,
179
  )
 
 
 
 
 
180
  stops = self._stops(stop)
 
 
181
  hold = max(len(s) for s in stops)
182
+
183
+ with self._maybe_off(use_adapter):
184
+ worker = threading.Thread(
185
+ target=self.model.generate, kwargs=kwargs, daemon=True)
186
+ worker.start()
187
+ try:
188
+ # A stop sequence can straddle two streamed pieces, so emit only
189
+ # the part of the buffer that can no longer become part of one.
190
+ buf, emitted, hit = "", 0, False
191
+ for piece in streamer:
192
+ buf += piece
193
+ cut, hit = self._truncate_at_stop(buf, stops)
194
+ if hit:
195
+ if len(cut) > emitted:
196
+ yield cut[emitted:]
197
+ break
198
+ safe = max(0, len(buf) - hold)
199
+ if safe > emitted:
200
+ yield buf[emitted:safe]
201
+ emitted = safe
202
+ if not hit and len(buf) > emitted:
203
+ yield buf[emitted:]
204
+ finally:
205
+ # Drain and join so the model is idle before adapter state flips.
206
+ for _ in streamer:
207
+ pass
208
+ worker.join(timeout=120)
209
 
210
 
211
  ENGINE: Engine | None = None
app/src/app/api/jobs/[jobId]/route.ts ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import { readStatus } from "@/lib/jobs";
3
+ import { rmSync, existsSync } from "node:fs";
4
+ import path from "node:path";
5
+
6
+ export const dynamic = "force-dynamic";
7
+
8
+ const WORKSPACES_DIR = path.join(process.cwd(), ".workspaces");
9
+
10
+ /** Delete a build: stop its inference server, then remove its workspace. */
11
+ export async function DELETE(
12
+ _req: NextRequest,
13
+ { params }: { params: Promise<{ jobId: string }> }
14
+ ) {
15
+ const { jobId } = await params;
16
+ // Reject anything that could escape the workspaces directory.
17
+ if (!/^[a-f0-9]{6,32}$/i.test(jobId)) {
18
+ return NextResponse.json({ error: "invalid job id" }, { status: 400 });
19
+ }
20
+ const dir = path.join(WORKSPACES_DIR, jobId);
21
+ if (!existsSync(dir)) {
22
+ return NextResponse.json({ error: "not found" }, { status: 404 });
23
+ }
24
+
25
+ // Free the ~10GB the server holds before removing the adapter it loaded.
26
+ const status = readStatus(jobId);
27
+ const pid = status?.server?.pid;
28
+ if (pid) {
29
+ try {
30
+ process.kill(pid, "SIGTERM");
31
+ } catch {
32
+ /* already gone */
33
+ }
34
+ }
35
+ try {
36
+ rmSync(dir, { recursive: true, force: true });
37
+ } catch (e) {
38
+ return NextResponse.json({ error: String(e) }, { status: 500 });
39
+ }
40
+ return NextResponse.json({ ok: true, jobId });
41
+ }
app/src/app/api/jobs/[jobId]/server/route.ts ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import { readStatus } from "@/lib/jobs";
3
+ import { spawn } from "node:child_process";
4
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
5
+ import path from "node:path";
6
+
7
+ export const dynamic = "force-dynamic";
8
+
9
+ const APP_DIR = path.resolve(process.cwd());
10
+ const ENGINE_DIR = path.join(APP_DIR, "engine");
11
+ const WORKSPACES_DIR = path.join(APP_DIR, ".workspaces");
12
+ const PYTHON = process.env.MLORA_PYTHON || "python3";
13
+
14
+ function statusPath(jobId: string) {
15
+ return path.join(WORKSPACES_DIR, jobId, "status.json");
16
+ }
17
+
18
+ /**
19
+ * Stop or restart a job's inference server.
20
+ *
21
+ * A transformers server that has been generating for a while slows down badly
22
+ * (MPS allocator churn, accumulated KV state), and the only reliable cure is a
23
+ * fresh process. Restarting reloads the same base+adapter, so the endpoint
24
+ * comes back on the same port with identical behaviour — no rebuild needed.
25
+ */
26
+ export async function POST(
27
+ req: NextRequest,
28
+ { params }: { params: Promise<{ jobId: string }> }
29
+ ) {
30
+ const { jobId } = await params;
31
+ if (!/^[a-f0-9]{6,32}$/i.test(jobId)) {
32
+ return NextResponse.json({ error: "invalid job id" }, { status: 400 });
33
+ }
34
+ const dir = path.join(WORKSPACES_DIR, jobId);
35
+ if (!existsSync(dir)) {
36
+ return NextResponse.json({ error: "not found" }, { status: 404 });
37
+ }
38
+
39
+ let action = "restart";
40
+ try {
41
+ action = (await req.json())?.action || "restart";
42
+ } catch {
43
+ /* default */
44
+ }
45
+
46
+ const status = readStatus(jobId);
47
+ const oldPid = status?.server?.pid;
48
+
49
+ // Kill first in both cases — a restart must not leave two processes fighting
50
+ // over the same port.
51
+ if (oldPid) {
52
+ try {
53
+ process.kill(oldPid, "SIGTERM");
54
+ } catch {
55
+ /* already gone */
56
+ }
57
+ await new Promise((r) => setTimeout(r, 1200));
58
+ try {
59
+ process.kill(oldPid, 0);
60
+ process.kill(oldPid, "SIGKILL"); // still alive: force it
61
+ } catch {
62
+ /* exited cleanly */
63
+ }
64
+ }
65
+
66
+ const raw = existsSync(statusPath(jobId))
67
+ ? JSON.parse(readFileSync(statusPath(jobId), "utf8"))
68
+ : {};
69
+
70
+ if (action === "stop") {
71
+ raw.state = "error";
72
+ raw.error = "server stopped — press Restart to bring it back";
73
+ raw.updated_at = Date.now() / 1000;
74
+ writeFileSync(statusPath(jobId), JSON.stringify(raw, null, 2));
75
+ return NextResponse.json({ ok: true, action: "stop" });
76
+ }
77
+
78
+ const port = status?.server?.port || 8000;
79
+ const adapter = path.join(dir, "adapter");
80
+ const merged = path.join(dir, "merged");
81
+ const args = [
82
+ path.join(ENGINE_DIR, "serve_fallback.py"),
83
+ "--port", String(port),
84
+ "--served-name", "memory-lora",
85
+ "--job", jobId,
86
+ ];
87
+ if (existsSync(adapter)) {
88
+ args.push("--adapter", adapter);
89
+ } else if (existsSync(merged)) {
90
+ args.push("--model", merged);
91
+ } else {
92
+ return NextResponse.json(
93
+ { error: "no adapter or merged model in this workspace" },
94
+ { status: 409 }
95
+ );
96
+ }
97
+ if (process.env.MLORA_DEVICE) args.push("--device", process.env.MLORA_DEVICE);
98
+
99
+ const child = spawn(PYTHON, args, {
100
+ cwd: ENGINE_DIR,
101
+ detached: true,
102
+ stdio: "ignore",
103
+ env: { ...process.env, MLORA_WORKSPACES: WORKSPACES_DIR },
104
+ });
105
+ child.unref();
106
+
107
+ // serve_fallback --job rewrites status.json with its own pid once the model
108
+ // is loaded; mark it as loading meanwhile so the UI doesn't claim it's ready.
109
+ raw.state = "running";
110
+ raw.stage = "serve";
111
+ raw.error = null;
112
+ raw.server = { backend: "fallback", pid: child.pid, port, mode: "lora" };
113
+ raw.pipeline_pid = child.pid;
114
+ raw.updated_at = Date.now() / 1000;
115
+ writeFileSync(statusPath(jobId), JSON.stringify(raw, null, 2));
116
+
117
+ return NextResponse.json({ ok: true, action: "restart", pid: child.pid, port });
118
+ }
app/src/app/compare/page.tsx CHANGED
@@ -1,270 +1,5 @@
1
  "use client";
2
 
3
- import { useEffect, useRef, useState } from "react";
4
-
5
- type Job = {
6
- job_id: string;
7
- repo_url: string;
8
- stages: string[];
9
- stage: string;
10
- state: "running" | "ready" | "error";
11
- error?: string | null;
12
- server?: { backend: string; port: number; mode?: string };
13
- };
14
-
15
- type Turn = { role: "user" | "assistant"; base?: string; adapted?: string };
16
-
17
- const STAGE_LABEL: Record<string, string> = {
18
- clone: "clone",
19
- embed: "embed",
20
- model: "base model",
21
- generate: "adapter",
22
- merge: "merge",
23
- serve: "serve",
24
- ready: "ready",
25
- };
26
-
27
- // Questions that expose repo knowledge rather than general fluency — the base
28
- // model can bluff a plausible answer to all of them, which is the point.
29
- const SUGGESTED = [
30
- "What is the core purpose of this repository?",
31
- "What testing framework does this repository use?",
32
- "How is this project built and packaged?",
33
- "What are the main modules and how do they fit together?",
34
- ];
35
-
36
- export default function Compare() {
37
- const [url, setUrl] = useState("");
38
- const [job, setJob] = useState<Job | null>(null);
39
- const [jobs, setJobs] = useState<Job[]>([]);
40
- const [turns, setTurns] = useState<Turn[]>([]);
41
- const [q, setQ] = useState("");
42
- const [busy, setBusy] = useState(false);
43
- const scroller = useRef<HTMLDivElement>(null);
44
-
45
- useEffect(() => {
46
- const poll = async () => {
47
- try {
48
- const r = await fetch("/api/build");
49
- const d = await r.json();
50
- setJobs(d.jobs || []);
51
- setJob((cur) =>
52
- cur ? (d.jobs || []).find((j: Job) => j.job_id === cur.job_id) || cur : cur
53
- );
54
- } catch {
55
- /* ignore */
56
- }
57
- };
58
- poll();
59
- const t = setInterval(poll, 2000);
60
- return () => clearInterval(t);
61
- }, []);
62
-
63
- useEffect(() => {
64
- scroller.current?.scrollTo({ top: scroller.current.scrollHeight, behavior: "smooth" });
65
- }, [turns]);
66
-
67
- const build = async () => {
68
- if (!url.trim()) return;
69
- setBusy(true);
70
- try {
71
- const r = await fetch("/api/build", {
72
- method: "POST",
73
- headers: { "content-type": "application/json" },
74
- body: JSON.stringify({ repoUrl: url.trim() }),
75
- });
76
- const d = await r.json();
77
- setJob({
78
- job_id: d.jobId,
79
- repo_url: url.trim(),
80
- stages: ["clone", "embed", "model", "generate", "serve", "ready"],
81
- stage: "clone",
82
- state: "running",
83
- });
84
- setTurns([]);
85
- setUrl("");
86
- } finally {
87
- setBusy(false);
88
- }
89
- };
90
-
91
- // Both sides hit the same server; only the model id differs, so the
92
- // comparison is the adapter and nothing else.
93
- const askOne = async (model: string, question: string): Promise<string> => {
94
- const r = await fetch("/v1/chat/completions", {
95
- method: "POST",
96
- headers: { "content-type": "application/json", "x-mlora-job": job!.job_id },
97
- body: JSON.stringify({
98
- model,
99
- max_tokens: 160,
100
- messages: [{ role: "user", content: question }],
101
- }),
102
- });
103
- if (!r.ok) return `[error ${r.status}]`;
104
- const d = await r.json();
105
- return d.choices?.[0]?.message?.content?.trim() || "[empty]";
106
- };
107
-
108
- const ask = async (question?: string) => {
109
- const text = (question ?? q).trim();
110
- if (!text || !job || job.state !== "ready" || busy) return;
111
- setBusy(true);
112
- setQ("");
113
- setTurns((t) => [...t, { role: "user", base: text }, { role: "assistant" }]);
114
- try {
115
- const [base, adapted] = await Promise.all([
116
- askOne("base", text),
117
- askOne(`memory-lora:${job.job_id}`, text),
118
- ]);
119
- setTurns((t) => {
120
- const c = [...t];
121
- c[c.length - 1] = { role: "assistant", base, adapted };
122
- return c;
123
- });
124
- } finally {
125
- setBusy(false);
126
- }
127
- };
128
-
129
- const ready = job?.state === "ready";
130
- const idx = job ? job.stages?.indexOf(job.stage) ?? 0 : 0;
131
-
132
- return (
133
- <div className="cmp">
134
- <header className="cmp-head">
135
- <div>
136
- <div className="eyebrow">Memory-LoRA · live comparison</div>
137
- <h1>Same model. Same prompt. One has read your repo.</h1>
138
- </div>
139
- {job && (
140
- <span className={`badge ${job.state}`}>
141
- {job.state === "ready" ? "endpoint live" : job.state}
142
- </span>
143
- )}
144
- </header>
145
-
146
- <div className="bar">
147
- <input
148
- type="text"
149
- placeholder="https://github.com/owner/repo"
150
- value={url}
151
- onChange={(e) => setUrl(e.target.value)}
152
- onKeyDown={(e) => e.key === "Enter" && build()}
153
- />
154
- <button onClick={build} disabled={busy || !url.trim()}>
155
- {busy ? "Starting…" : "Build adapter"}
156
- </button>
157
- </div>
158
-
159
- {jobs.length > 0 && (
160
- <div className="recent">
161
- <span className="eyebrow">Ready</span>
162
- {jobs
163
- .filter((j) => j.state === "ready")
164
- .slice(0, 4)
165
- .map((j) => (
166
- <button
167
- key={j.job_id}
168
- className={`chip ${job?.job_id === j.job_id ? "on" : ""}`}
169
- onClick={() => {
170
- setJob(j);
171
- setTurns([]);
172
- }}
173
- >
174
- {j.repo_url.replace("https://github.com/", "")}
175
- </button>
176
- ))}
177
- </div>
178
- )}
179
-
180
- {job && !ready && (
181
- <div className="progress">
182
- <div className="stages">
183
- {(job.stages || []).map((s, i) => (
184
- <span
185
- key={s}
186
- className={`stage ${i < idx ? "done" : ""} ${
187
- i === idx && job.state === "running" ? "active" : ""
188
- }`}
189
- >
190
- {STAGE_LABEL[s] || s}
191
- </span>
192
- ))}
193
- </div>
194
- {job.state === "error" ? (
195
- <p className="err">✗ {job.error}</p>
196
- ) : (
197
- <p className="hint">
198
- Cloning, embedding six views, and generating a LoRA adapter — about a minute.
199
- </p>
200
- )}
201
- </div>
202
- )}
203
-
204
- {ready && (
205
- <>
206
- <div className="panes">
207
- <div className="pane-head base">
208
- <span className="dot" /> Frozen Gemma-4-E2B
209
- <em>no repo knowledge</em>
210
- </div>
211
- <div className="pane-head adapted">
212
- <span className="dot" /> + generated adapter
213
- <em>{job!.repo_url.replace("https://github.com/", "")}</em>
214
- </div>
215
- </div>
216
-
217
- <div className="scroll" ref={scroller}>
218
- {turns.length === 0 && (
219
- <div className="empty">
220
- <p>Ask something only this repository can answer.</p>
221
- <div className="suggest">
222
- {SUGGESTED.map((s) => (
223
- <button key={s} onClick={() => ask(s)} disabled={busy}>
224
- {s}
225
- </button>
226
- ))}
227
- </div>
228
- </div>
229
- )}
230
- {turns.map((t, i) =>
231
- t.role === "user" ? (
232
- <div key={i} className="q">
233
- {t.base}
234
- </div>
235
- ) : (
236
- <div key={i} className="answers">
237
- <div className="ans base">
238
- {t.base ?? <span className="think">thinking…</span>}
239
- </div>
240
- <div className="ans adapted">
241
- {t.adapted ?? <span className="think">thinking…</span>}
242
- </div>
243
- </div>
244
- )
245
- )}
246
- </div>
247
-
248
- <div className="ask">
249
- <input
250
- type="text"
251
- placeholder="Ask about this repository…"
252
- value={q}
253
- onChange={(e) => setQ(e.target.value)}
254
- onKeyDown={(e) => e.key === "Enter" && ask()}
255
- disabled={busy}
256
- />
257
- <button onClick={() => ask()} disabled={busy || !q.trim()}>
258
- {busy ? "…" : "Ask both"}
259
- </button>
260
- </div>
261
- <p className="foot">
262
- Both answers come from one resident model on the same server — the only
263
- difference is whether the generated adapter is switched on. No repository
264
- text is in either prompt.
265
- </p>
266
- </>
267
- )}
268
- </div>
269
- );
270
- }
 
1
  "use client";
2
 
3
+ // The demo lives at "/" this keeps "/compare" working too, so either URL
4
+ // lands on the side-by-side comparison instead of a 404.
5
+ export { default } from "../page";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/src/app/globals.css CHANGED
@@ -162,3 +162,20 @@ label.small { color: var(--muted); font-size: 13px; }
162
  border-radius: 10px; color: var(--text); padding: 13px 15px; font-size: 15px; }
163
  .ask input:focus { outline: none; border-color: var(--accent); }
164
  .foot { color: var(--muted); font-size: 12.5px; margin: 12px 0 0; text-align: center; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  border-radius: 10px; color: var(--text); padding: 13px 15px; font-size: 15px; }
163
  .ask input:focus { outline: none; border-color: var(--accent); }
164
  .foot { color: var(--muted); font-size: 12.5px; margin: 12px 0 0; text-align: center; }
165
+ .chip { display: inline-flex; align-items: center; gap: 0; padding: 0; overflow: hidden; }
166
+ .chip-main { background: none; border: none; color: inherit; font: inherit;
167
+ padding: 5px 6px 5px 12px; cursor: pointer; font-family: var(--mono); }
168
+ .chip-main em { font-style: normal; color: var(--muted); }
169
+ .chip-x { background: none; border: none; color: var(--muted); cursor: pointer;
170
+ font-size: 15px; line-height: 1; padding: 5px 10px 6px 4px; font-weight: 400; }
171
+ .chip-x:hover { color: var(--err); }
172
+ .clear-all { background: none; border: 1px solid var(--border); color: var(--muted);
173
+ border-radius: 999px; padding: 5px 12px; font-size: 12.5px; cursor: pointer;
174
+ font-weight: 400; }
175
+ .clear-all:hover { border-color: var(--err); color: var(--err); }
176
+ button.ghost { background: transparent; border: 1px solid var(--border);
177
+ color: var(--muted); font-weight: 400; }
178
+ button.ghost:hover:not(:disabled) { border-color: var(--accent); color: var(--text); }
179
+ .head-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
180
+ button.small { padding: 5px 12px; font-size: 12.5px; border-radius: 999px; }
181
+ button.ghost.danger:hover:not(:disabled) { border-color: var(--err); color: var(--err); }
app/src/app/page.tsx CHANGED
@@ -1,6 +1,6 @@
1
  "use client";
2
 
3
- import { useEffect, useState } from "react";
4
 
5
  type Job = {
6
  job_id: string;
@@ -9,10 +9,11 @@ type Job = {
9
  stage: string;
10
  state: "running" | "ready" | "error";
11
  error?: string | null;
12
- server?: { backend: string; port: number };
13
- endpoint?: string;
14
  };
15
 
 
 
16
  const STAGE_LABEL: Record<string, string> = {
17
  clone: "clone",
18
  embed: "embed",
@@ -23,80 +24,37 @@ const STAGE_LABEL: Record<string, string> = {
23
  ready: "ready",
24
  };
25
 
26
- function ConnectSnippets({ job, base }: { job: Job; base: string }) {
27
- const [tab, setTab] = useState<"claude" | "openai" | "curl">("claude");
28
- const model = `memory-lora:${job.job_id}`;
29
- const claude = `# Claude Code point it at this repo-personalized model
30
- export ANTHROPIC_BASE_URL="${base}"
31
- export ANTHROPIC_API_KEY="local-demo" # any non-empty value
32
- export ANTHROPIC_MODEL="${model}"
33
- claude`;
34
- const openai = `# vibe / aider / any OpenAI-compatible CLI
35
- export OPENAI_BASE_URL="${base}/v1"
36
- export OPENAI_API_KEY="local-demo"
37
- export OPENAI_MODEL="${model}"
38
- # e.g. aider --model openai/${model}
39
- # e.g. vibe --base-url $OPENAI_BASE_URL --model ${model}`;
40
- const curl = `curl ${base}/v1/chat/completions \\
41
- -H "content-type: application/json" \\
42
- -d '{"model":"${model}","messages":[{"role":"user","content":"What does this repo do?"}]}'`;
43
- const text = tab === "claude" ? claude : tab === "openai" ? openai : curl;
44
- return (
45
- <div style={{ marginTop: 14 }}>
46
- <div className="tabs">
47
- <div className={`tab ${tab === "claude" ? "on" : ""}`} onClick={() => setTab("claude")}>Claude Code</div>
48
- <div className={`tab ${tab === "openai" ? "on" : ""}`} onClick={() => setTab("openai")}>OpenAI CLIs</div>
49
- <div className={`tab ${tab === "curl" ? "on" : ""}`} onClick={() => setTab("curl")}>curl</div>
50
- </div>
51
- <pre>{text}</pre>
52
- <p className="hint">
53
- Endpoint served by {job.server?.backend || "engine"} on port {job.server?.port}. The app
54
- translates the Anthropic <code>/v1/messages</code> API to this model, so Claude Code works
55
- directly.
56
- </p>
57
- </div>
58
- );
59
- }
60
 
61
- function JobCard({ job, base }: { job: Job; base: string }) {
62
- const idx = job.stages?.indexOf(job.stage) ?? 0;
63
- return (
64
- <div className="card">
65
- <div className="jobhead">
66
- <span className="repo">{job.repo_url}</span>
67
- <span className={`badge ${job.state}`}>{job.state}</span>
68
- </div>
69
- <div className="stages">
70
- {(job.stages || []).map((s, i) => (
71
- <span
72
- key={s}
73
- className={`stage ${i < idx || job.state === "ready" ? "done" : ""} ${
74
- i === idx && job.state === "running" ? "active" : ""
75
- }`}
76
- >
77
- {STAGE_LABEL[s] || s}
78
- </span>
79
- ))}
80
- </div>
81
- {job.state === "error" && <div className="err">✗ {job.error}</div>}
82
- {job.state === "ready" && <ConnectSnippets job={job} base={base} />}
83
- </div>
84
- );
85
- }
86
 
87
- export default function Home() {
88
  const [url, setUrl] = useState("");
 
89
  const [jobs, setJobs] = useState<Job[]>([]);
 
 
90
  const [busy, setBusy] = useState(false);
91
- const [base, setBase] = useState("");
92
 
93
  useEffect(() => {
94
- setBase(window.location.origin);
95
  const poll = async () => {
96
  try {
97
  const r = await fetch("/api/build");
98
  const d = await r.json();
99
  setJobs(d.jobs || []);
 
 
 
100
  } catch {
101
  /* ignore */
102
  }
@@ -106,56 +64,322 @@ export default function Home() {
106
  return () => clearInterval(t);
107
  }, []);
108
 
109
- const submit = async () => {
 
 
 
 
110
  if (!url.trim()) return;
111
  setBusy(true);
112
  try {
113
- await fetch("/api/build", {
114
  method: "POST",
115
  headers: { "content-type": "application/json" },
116
  body: JSON.stringify({ repoUrl: url.trim() }),
117
  });
 
 
 
 
 
 
 
 
 
118
  setUrl("");
119
  } finally {
120
  setBusy(false);
121
  }
122
  };
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  return (
125
- <div className="wrap">
126
- <h1>Memory-LoRA</h1>
127
- <p className="sub">
128
- Paste a git repository. A hypernetwork reads a 6-view embedding of the codebase and{" "}
129
- <b>emits a LoRA adapter</b> for Gemma in one forward pass — no fine-tuning. The adapter is
130
- merged into the base model and served behind an OpenAI + Anthropic compatible endpoint, so
131
- your coding CLI talks to a model that already knows this repo.
132
- </p>
133
-
134
- <div className="card">
135
- <div className="row">
136
- <input
137
- type="text"
138
- placeholder="https://github.com/owner/repo"
139
- value={url}
140
- onChange={(e) => setUrl(e.target.value)}
141
- onKeyDown={(e) => e.key === "Enter" && submit()}
142
- />
143
- <button onClick={submit} disabled={busy}>
144
- {busy ? "Starting…" : "Build & serve"}
145
- </button>
146
  </div>
147
- <p className="hint">
148
- First build downloads the base model (~10&nbsp;GB) and takes a few minutes; later builds
149
- reuse it.
150
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  </div>
152
 
153
- {jobs.length === 0 && (
154
- <p className="hint">No builds yet. Paste a repo URL above to start one.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  )}
156
- {jobs.map((j) => (
157
- <JobCard key={j.job_id} job={j} base={base} />
158
- ))}
159
  </div>
160
  );
161
  }
 
1
  "use client";
2
 
3
+ import { useEffect, useRef, useState } from "react";
4
 
5
  type Job = {
6
  job_id: string;
 
9
  stage: string;
10
  state: "running" | "ready" | "error";
11
  error?: string | null;
12
+ server?: { backend: string; port: number; mode?: string };
 
13
  };
14
 
15
+ type Turn = { role: "user" | "assistant"; base?: string; adapted?: string };
16
+
17
  const STAGE_LABEL: Record<string, string> = {
18
  clone: "clone",
19
  embed: "embed",
 
24
  ready: "ready",
25
  };
26
 
27
+ // Questions that expose repo knowledge rather than general fluency the base
28
+ // model can bluff a plausible answer to all of them, which is the point.
29
+ // Short answers keep the demo snappy; the server's stop sequences cut the
30
+ // response at the end of the answer anyway, so this rarely truncates.
31
+ const MAX_TOKENS = 72;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ const SUGGESTED = [
34
+ "What is the core purpose of this repository?",
35
+ "What testing framework does this repository use?",
36
+ "How is this project built and packaged?",
37
+ "What are the main modules and how do they fit together?",
38
+ ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ export default function Compare() {
41
  const [url, setUrl] = useState("");
42
+ const [job, setJob] = useState<Job | null>(null);
43
  const [jobs, setJobs] = useState<Job[]>([]);
44
+ const [turns, setTurns] = useState<Turn[]>([]);
45
+ const [q, setQ] = useState("");
46
  const [busy, setBusy] = useState(false);
47
+ const scroller = useRef<HTMLDivElement>(null);
48
 
49
  useEffect(() => {
 
50
  const poll = async () => {
51
  try {
52
  const r = await fetch("/api/build");
53
  const d = await r.json();
54
  setJobs(d.jobs || []);
55
+ setJob((cur) =>
56
+ cur ? (d.jobs || []).find((j: Job) => j.job_id === cur.job_id) || cur : cur
57
+ );
58
  } catch {
59
  /* ignore */
60
  }
 
64
  return () => clearInterval(t);
65
  }, []);
66
 
67
+ useEffect(() => {
68
+ scroller.current?.scrollTo({ top: scroller.current.scrollHeight, behavior: "smooth" });
69
+ }, [turns]);
70
+
71
+ const build = async () => {
72
  if (!url.trim()) return;
73
  setBusy(true);
74
  try {
75
+ const r = await fetch("/api/build", {
76
  method: "POST",
77
  headers: { "content-type": "application/json" },
78
  body: JSON.stringify({ repoUrl: url.trim() }),
79
  });
80
+ const d = await r.json();
81
+ setJob({
82
+ job_id: d.jobId,
83
+ repo_url: url.trim(),
84
+ stages: ["clone", "embed", "model", "generate", "serve", "ready"],
85
+ stage: "clone",
86
+ state: "running",
87
+ });
88
+ setTurns([]);
89
  setUrl("");
90
  } finally {
91
  setBusy(false);
92
  }
93
  };
94
 
95
+ // Both sides hit the same server; only the model id differs, so the
96
+ // comparison is the adapter and nothing else.
97
+ //
98
+ // Streamed, and deliberately sequential: one model serves both sides, so the
99
+ // server holds a lock and concurrent requests would queue anyway. Streaming
100
+ // is what makes it feel immediate -- tokens appear as they are produced
101
+ // instead of after the full answer.
102
+ const askOne = async (
103
+ model: string,
104
+ question: string,
105
+ onDelta: (chunk: string) => void
106
+ ): Promise<void> => {
107
+ const r = await fetch("/v1/chat/completions", {
108
+ method: "POST",
109
+ headers: { "content-type": "application/json", "x-mlora-job": job!.job_id },
110
+ body: JSON.stringify({
111
+ model,
112
+ max_tokens: MAX_TOKENS,
113
+ stream: true,
114
+ messages: [{ role: "user", content: question }],
115
+ }),
116
+ });
117
+ if (!r.ok || !r.body) {
118
+ onDelta(`[error ${r.status}]`);
119
+ return;
120
+ }
121
+ const reader = r.body.getReader();
122
+ const dec = new TextDecoder();
123
+ let buf = "";
124
+ for (;;) {
125
+ const { done, value } = await reader.read();
126
+ if (done) break;
127
+ buf += dec.decode(value, { stream: true });
128
+ const lines = buf.split("\n");
129
+ buf = lines.pop() || "";
130
+ for (const line of lines) {
131
+ const t = line.trim();
132
+ if (!t.startsWith("data:")) continue;
133
+ const payload = t.slice(5).trim();
134
+ if (payload === "[DONE]") continue;
135
+ try {
136
+ const d = JSON.parse(payload);
137
+ const piece = d.choices?.[0]?.delta?.content;
138
+ if (piece) onDelta(piece);
139
+ } catch {
140
+ /* partial frame */
141
+ }
142
+ }
143
+ }
144
+ };
145
+
146
+ const ask = async (question?: string) => {
147
+ const text = (question ?? q).trim();
148
+ if (!text || !job || job.state !== "ready" || busy) return;
149
+ setBusy(true);
150
+ setQ("");
151
+ setTurns((t) => [
152
+ ...t,
153
+ { role: "user", base: text },
154
+ { role: "assistant", base: "", adapted: "" },
155
+ ]);
156
+ const push = (side: "base" | "adapted") => (chunk: string) =>
157
+ setTurns((t) => {
158
+ const c = [...t];
159
+ const last = { ...c[c.length - 1] };
160
+ last[side] = (last[side] || "") + chunk;
161
+ c[c.length - 1] = last;
162
+ return c;
163
+ });
164
+ try {
165
+ await askOne("base", text, push("base"));
166
+ await askOne(`memory-lora:${job.job_id}`, text, push("adapted"));
167
+ } finally {
168
+ setBusy(false);
169
+ }
170
+ };
171
+
172
+ const clearChat = () => setTurns([]);
173
+
174
+ // A long-lived transformers server degrades badly (allocator churn on MPS);
175
+ // a fresh process reloads the same base+adapter on the same port.
176
+ const serverAction = async (action: "stop" | "restart") => {
177
+ if (!job) return;
178
+ setBusy(true);
179
+ try {
180
+ await fetch(`/api/jobs/${job.job_id}/server`, {
181
+ method: "POST",
182
+ headers: { "content-type": "application/json" },
183
+ body: JSON.stringify({ action }),
184
+ });
185
+ const r = await fetch("/api/build");
186
+ setJobs((await r.json()).jobs || []);
187
+ } finally {
188
+ setBusy(false);
189
+ }
190
+ };
191
+
192
+ const deleteBuild = async (jobId: string) => {
193
+ await fetch(`/api/jobs/${jobId}`, { method: "DELETE" });
194
+ if (job?.job_id === jobId) {
195
+ setJob(null);
196
+ setTurns([]);
197
+ }
198
+ const r = await fetch("/api/build");
199
+ setJobs((await r.json()).jobs || []);
200
+ };
201
+
202
+ const clearAll = async () => {
203
+ await Promise.all(jobs.map((j) => fetch(`/api/jobs/${j.job_id}`, { method: "DELETE" })));
204
+ setJob(null);
205
+ setTurns([]);
206
+ setJobs([]);
207
+ };
208
+
209
+ const ready = job?.state === "ready";
210
+ const idx = job ? job.stages?.indexOf(job.stage) ?? 0 : 0;
211
+
212
  return (
213
+ <div className="cmp">
214
+ <header className="cmp-head">
215
+ <div>
216
+ <div className="eyebrow">Memory-LoRA · live comparison</div>
217
+ <h1>Same model. Same prompt. One has read your repo.</h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  </div>
219
+ {job && (
220
+ <div className="head-actions">
221
+ <span className={`badge ${job.state}`}>
222
+ {job.state === "ready" ? "endpoint live" : job.state}
223
+ </span>
224
+ <button
225
+ className="ghost small"
226
+ onClick={() => serverAction("restart")}
227
+ disabled={busy}
228
+ title="Kill and reload the model process — fixes a server that has become slow"
229
+ >
230
+ Restart model
231
+ </button>
232
+ <button
233
+ className="ghost small danger"
234
+ onClick={() => serverAction("stop")}
235
+ disabled={busy || job.state !== "ready"}
236
+ title="Kill the model process and free its memory"
237
+ >
238
+ Kill
239
+ </button>
240
+ </div>
241
+ )}
242
+ </header>
243
+
244
+ <div className="bar">
245
+ <input
246
+ type="text"
247
+ placeholder="https://github.com/owner/repo"
248
+ value={url}
249
+ onChange={(e) => setUrl(e.target.value)}
250
+ onKeyDown={(e) => e.key === "Enter" && build()}
251
+ />
252
+ <button onClick={build} disabled={busy || !url.trim()}>
253
+ {busy ? "Starting…" : "Build adapter"}
254
+ </button>
255
  </div>
256
 
257
+ {jobs.length > 0 && (
258
+ <div className="recent">
259
+ <span className="eyebrow">Ready</span>
260
+ {jobs.slice(0, 5).map((j) => (
261
+ <span key={j.job_id} className={`chip ${job?.job_id === j.job_id ? "on" : ""}`}>
262
+ <button
263
+ className="chip-main"
264
+ onClick={() => {
265
+ setJob(j);
266
+ setTurns([]);
267
+ }}
268
+ >
269
+ {j.repo_url.replace("https://github.com/", "")}
270
+ {j.state !== "ready" && <em> · {j.state}</em>}
271
+ </button>
272
+ <button
273
+ className="chip-x"
274
+ title="Delete this build"
275
+ aria-label={`Delete ${j.repo_url}`}
276
+ onClick={() => deleteBuild(j.job_id)}
277
+ >
278
+ ×
279
+ </button>
280
+ </span>
281
+ ))}
282
+ {jobs.length > 0 && (
283
+ <button className="clear-all" onClick={clearAll}>
284
+ Clear all builds
285
+ </button>
286
+ )}
287
+ </div>
288
+ )}
289
+
290
+ {job && !ready && (
291
+ <div className="progress">
292
+ <div className="stages">
293
+ {(job.stages || []).map((s, i) => (
294
+ <span
295
+ key={s}
296
+ className={`stage ${i < idx ? "done" : ""} ${
297
+ i === idx && job.state === "running" ? "active" : ""
298
+ }`}
299
+ >
300
+ {STAGE_LABEL[s] || s}
301
+ </span>
302
+ ))}
303
+ </div>
304
+ {job.state === "error" ? (
305
+ <p className="err">✗ {job.error}</p>
306
+ ) : (
307
+ <p className="hint">
308
+ Cloning, embedding six views, and generating a LoRA adapter — about a minute.
309
+ </p>
310
+ )}
311
+ </div>
312
+ )}
313
+
314
+ {ready && (
315
+ <>
316
+ <div className="panes">
317
+ <div className="pane-head base">
318
+ <span className="dot" /> Frozen Gemma-4-E2B
319
+ <em>no repo knowledge</em>
320
+ </div>
321
+ <div className="pane-head adapted">
322
+ <span className="dot" /> + generated adapter
323
+ <em>{job!.repo_url.replace("https://github.com/", "")}</em>
324
+ </div>
325
+ </div>
326
+
327
+ <div className="scroll" ref={scroller}>
328
+ {turns.length === 0 && (
329
+ <div className="empty">
330
+ <p>Ask something only this repository can answer.</p>
331
+ <div className="suggest">
332
+ {SUGGESTED.map((s) => (
333
+ <button key={s} onClick={() => ask(s)} disabled={busy}>
334
+ {s}
335
+ </button>
336
+ ))}
337
+ </div>
338
+ </div>
339
+ )}
340
+ {turns.map((t, i) =>
341
+ t.role === "user" ? (
342
+ <div key={i} className="q">
343
+ {t.base}
344
+ </div>
345
+ ) : (
346
+ <div key={i} className="answers">
347
+ <div className="ans base">
348
+ {t.base ? t.base : <span className="think">…</span>}
349
+ </div>
350
+ <div className="ans adapted">
351
+ {t.adapted ? t.adapted : <span className="think">…</span>}
352
+ </div>
353
+ </div>
354
+ )
355
+ )}
356
+ </div>
357
+
358
+ <div className="ask">
359
+ <input
360
+ type="text"
361
+ placeholder="Ask about this repository…"
362
+ value={q}
363
+ onChange={(e) => setQ(e.target.value)}
364
+ onKeyDown={(e) => e.key === "Enter" && ask()}
365
+ disabled={busy}
366
+ />
367
+ <button onClick={() => ask()} disabled={busy || !q.trim()}>
368
+ {busy ? "…" : "Ask both"}
369
+ </button>
370
+ {turns.length > 0 && (
371
+ <button className="ghost" onClick={clearChat} disabled={busy}>
372
+ Clear chat
373
+ </button>
374
+ )}
375
+ </div>
376
+ <p className="foot">
377
+ Both answers come from one resident model on the same server — the only
378
+ difference is whether the generated adapter is switched on. No repository
379
+ text is in either prompt.
380
+ </p>
381
+ </>
382
  )}
 
 
 
383
  </div>
384
  );
385
  }
app/src/app/serve/page.tsx ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+
5
+ type Job = {
6
+ job_id: string;
7
+ repo_url: string;
8
+ stages: string[];
9
+ stage: string;
10
+ state: "running" | "ready" | "error";
11
+ error?: string | null;
12
+ server?: { backend: string; port: number };
13
+ endpoint?: string;
14
+ };
15
+
16
+ const STAGE_LABEL: Record<string, string> = {
17
+ clone: "clone",
18
+ embed: "embed",
19
+ model: "base model",
20
+ generate: "adapter",
21
+ merge: "merge",
22
+ serve: "serve",
23
+ ready: "ready",
24
+ };
25
+
26
+ function ConnectSnippets({ job, base }: { job: Job; base: string }) {
27
+ const [tab, setTab] = useState<"claude" | "openai" | "curl">("claude");
28
+ const model = `memory-lora:${job.job_id}`;
29
+ const claude = `# Claude Code — point it at this repo-personalized model
30
+ export ANTHROPIC_BASE_URL="${base}"
31
+ export ANTHROPIC_API_KEY="local-demo" # any non-empty value
32
+ export ANTHROPIC_MODEL="${model}"
33
+ claude`;
34
+ const openai = `# vibe / aider / any OpenAI-compatible CLI
35
+ export OPENAI_BASE_URL="${base}/v1"
36
+ export OPENAI_API_KEY="local-demo"
37
+ export OPENAI_MODEL="${model}"
38
+ # e.g. aider --model openai/${model}
39
+ # e.g. vibe --base-url $OPENAI_BASE_URL --model ${model}`;
40
+ const curl = `curl ${base}/v1/chat/completions \\
41
+ -H "content-type: application/json" \\
42
+ -d '{"model":"${model}","messages":[{"role":"user","content":"What does this repo do?"}]}'`;
43
+ const text = tab === "claude" ? claude : tab === "openai" ? openai : curl;
44
+ return (
45
+ <div style={{ marginTop: 14 }}>
46
+ <div className="tabs">
47
+ <div className={`tab ${tab === "claude" ? "on" : ""}`} onClick={() => setTab("claude")}>Claude Code</div>
48
+ <div className={`tab ${tab === "openai" ? "on" : ""}`} onClick={() => setTab("openai")}>OpenAI CLIs</div>
49
+ <div className={`tab ${tab === "curl" ? "on" : ""}`} onClick={() => setTab("curl")}>curl</div>
50
+ </div>
51
+ <pre>{text}</pre>
52
+ <p className="hint">
53
+ Endpoint served by {job.server?.backend || "engine"} on port {job.server?.port}. The app
54
+ translates the Anthropic <code>/v1/messages</code> API to this model, so Claude Code works
55
+ directly.
56
+ </p>
57
+ </div>
58
+ );
59
+ }
60
+
61
+ function JobCard({ job, base }: { job: Job; base: string }) {
62
+ const idx = job.stages?.indexOf(job.stage) ?? 0;
63
+ return (
64
+ <div className="card">
65
+ <div className="jobhead">
66
+ <span className="repo">{job.repo_url}</span>
67
+ <span className={`badge ${job.state}`}>{job.state}</span>
68
+ </div>
69
+ <div className="stages">
70
+ {(job.stages || []).map((s, i) => (
71
+ <span
72
+ key={s}
73
+ className={`stage ${i < idx || job.state === "ready" ? "done" : ""} ${
74
+ i === idx && job.state === "running" ? "active" : ""
75
+ }`}
76
+ >
77
+ {STAGE_LABEL[s] || s}
78
+ </span>
79
+ ))}
80
+ </div>
81
+ {job.state === "error" && <div className="err">✗ {job.error}</div>}
82
+ {job.state === "ready" && <ConnectSnippets job={job} base={base} />}
83
+ </div>
84
+ );
85
+ }
86
+
87
+ export default function Home() {
88
+ const [url, setUrl] = useState("");
89
+ const [jobs, setJobs] = useState<Job[]>([]);
90
+ const [busy, setBusy] = useState(false);
91
+ const [base, setBase] = useState("");
92
+
93
+ useEffect(() => {
94
+ setBase(window.location.origin);
95
+ const poll = async () => {
96
+ try {
97
+ const r = await fetch("/api/build");
98
+ const d = await r.json();
99
+ setJobs(d.jobs || []);
100
+ } catch {
101
+ /* ignore */
102
+ }
103
+ };
104
+ poll();
105
+ const t = setInterval(poll, 2000);
106
+ return () => clearInterval(t);
107
+ }, []);
108
+
109
+ const submit = async () => {
110
+ if (!url.trim()) return;
111
+ setBusy(true);
112
+ try {
113
+ await fetch("/api/build", {
114
+ method: "POST",
115
+ headers: { "content-type": "application/json" },
116
+ body: JSON.stringify({ repoUrl: url.trim() }),
117
+ });
118
+ setUrl("");
119
+ } finally {
120
+ setBusy(false);
121
+ }
122
+ };
123
+
124
+ return (
125
+ <div className="wrap">
126
+ <h1>Memory-LoRA</h1>
127
+ <p className="sub">
128
+ Paste a git repository. A hypernetwork reads a 6-view embedding of the codebase and{" "}
129
+ <b>emits a LoRA adapter</b> for Gemma in one forward pass — no fine-tuning. The adapter is
130
+ merged into the base model and served behind an OpenAI + Anthropic compatible endpoint, so
131
+ your coding CLI talks to a model that already knows this repo.
132
+ </p>
133
+
134
+ <div className="card">
135
+ <div className="row">
136
+ <input
137
+ type="text"
138
+ placeholder="https://github.com/owner/repo"
139
+ value={url}
140
+ onChange={(e) => setUrl(e.target.value)}
141
+ onKeyDown={(e) => e.key === "Enter" && submit()}
142
+ />
143
+ <button onClick={submit} disabled={busy}>
144
+ {busy ? "Starting…" : "Build & serve"}
145
+ </button>
146
+ </div>
147
+ <p className="hint">
148
+ First build downloads the base model (~10&nbsp;GB) and takes a few minutes; later builds
149
+ reuse it.
150
+ </p>
151
+ </div>
152
+
153
+ {jobs.length === 0 && (
154
+ <p className="hint">No builds yet. Paste a repo URL above to start one.</p>
155
+ )}
156
+ {jobs.map((j) => (
157
+ <JobCard key={j.job_id} job={j} base={base} />
158
+ ))}
159
+ </div>
160
+ );
161
+ }
app/src/app/v1/[...path]/route.ts CHANGED
@@ -11,6 +11,11 @@ export const dynamic = "force-dynamic";
11
  const SERVED_MODEL = "memory-lora";
12
  const API_KEY = process.env.MLORA_API_KEY || "";
13
 
 
 
 
 
 
14
  function authOk(req: NextRequest): boolean {
15
  if (!API_KEY) return true;
16
  const auth = req.headers.get("authorization");
@@ -53,12 +58,15 @@ async function proxyPassthrough(
53
  );
54
  }
55
 
56
- // Force the served model name so arbitrary client model strings work.
 
 
 
57
  let body = rawBody;
58
  if (rawBody) {
59
  try {
60
  const j = JSON.parse(rawBody);
61
- j.model = SERVED_MODEL;
62
  body = JSON.stringify(j);
63
  } catch {
64
  /* leave as-is */
@@ -96,7 +104,8 @@ async function handleMessages(req: NextRequest, rawBody: string): Promise<Respon
96
  );
97
  }
98
 
99
- const oaiReq = anthropicToOpenAI(body, SERVED_MODEL);
 
100
  const upstream = await fetch(`${target}/v1/chat/completions`, {
101
  method: "POST",
102
  headers: { "content-type": "application/json" },
 
11
  const SERVED_MODEL = "memory-lora";
12
  const API_KEY = process.env.MLORA_API_KEY || "";
13
 
14
+ /** True when the caller explicitly asked for the un-adapted base model. */
15
+ function isBaseModel(model: unknown): boolean {
16
+ return typeof model === "string" && model.trim().toLowerCase() === "base";
17
+ }
18
+
19
  function authOk(req: NextRequest): boolean {
20
  if (!API_KEY) return true;
21
  const auth = req.headers.get("authorization");
 
58
  );
59
  }
60
 
61
+ // Normalize the model field so arbitrary client model strings work — but
62
+ // NEVER collapse "base" into the served name. The upstream server selects
63
+ // frozen-vs-adapted from this field, so rewriting it unconditionally made the
64
+ // side-by-side comparison silently return the adapted model on BOTH sides.
65
  let body = rawBody;
66
  if (rawBody) {
67
  try {
68
  const j = JSON.parse(rawBody);
69
+ if (!isBaseModel(j.model)) j.model = SERVED_MODEL;
70
  body = JSON.stringify(j);
71
  } catch {
72
  /* leave as-is */
 
104
  );
105
  }
106
 
107
+ const oaiReq = anthropicToOpenAI(
108
+ body, isBaseModel(body.model) ? "base" : SERVED_MODEL);
109
  const upstream = await fetch(`${target}/v1/chat/completions`, {
110
  method: "POST",
111
  headers: { "content-type": "application/json" },
data/real_code2lora/code2lora-evo/.cache/huggingface/.gitignore DELETED
@@ -1 +0,0 @@
1
- *
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/CACHEDIR.TAG DELETED
@@ -1,4 +0,0 @@
1
- Signature: 8a477f597d28d172789f06886806bc55
2
- # This file is a cache directory tag created by huggingface_hub.
3
- # For information about cache directory tags, see:
4
- # https://bford.info/cachedir/
 
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/.gitattributes.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- bed0738c7eeb449bca98b5d2f33c89a1ee56349a
3
- 1784887206.240134
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/README.md.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- 12076d4a9bd34d0eed0b624159820e7c340ac3df
3
- 1784887206.477736
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/commits/cr_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- 1472bd42bed51428bf1bccbedc4c494db58bc9a6fffa72fc95f95a0613de2169
3
- 1784887250.161078
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/commits/cr_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- f73959d38ad7d479a3b6715d96ae22a42ea89c4e9b1830e3f9354ebada98877f
3
- 1784887281.485605
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/commits/train.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- 6dfca1e1791fde09c1f310f2be9273b762332f28563d203a2ed7f0136cb3590b
3
- 1784887367.7020202
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/cr_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- fc42611e215975824582df0da76984f6a65c3d5e29002a2b205fb5437cde907b
3
- 1784887229.2656882
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/cr_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- 3d76ca372ce366ab6f2b51765c9b5cbfbbfa33019b4e05d1dc05c25cacbea04f
3
- 1784887263.0436091
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/ir_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- af20fba7881a55b68efd82302b108615c6a5ae05be8e71d49c3455a7bbb124a4
3
- 1784887233.92661
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/ir_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- 6b830ddb82490f1c7b6c44104cdcbcd1a8c9ca5f31d3c04af0421d2f0825c6a3
3
- 1784887277.8217332
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/download/qna/train.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 93a9e8240b9482092ecc768b804cc62bae1e875a
2
- 519a092970f55750571c5223b1cfbcb0d36745a678cf41b48d4de6104c2a34e7
3
- 1784887371.999535
 
 
 
 
data/real_code2lora/code2lora-evo/.cache/huggingface/trees/93a9e8240b9482092ecc768b804cc62bae1e875a.json DELETED
@@ -1,69 +0,0 @@
1
- {
2
- "format_version": 1,
3
- "files": {
4
- ".gitattributes": {
5
- "size": 2504,
6
- "blob_id": "bed0738c7eeb449bca98b5d2f33c89a1ee56349a"
7
- },
8
- "README.md": {
9
- "size": 1735,
10
- "blob_id": "12076d4a9bd34d0eed0b624159820e7c340ac3df"
11
- },
12
- "commits/cr_test.parquet": {
13
- "size": 68411936,
14
- "blob_id": "1e2ac27253f7cf41412b4a38520e97531302d968",
15
- "lfs_sha256": "1472bd42bed51428bf1bccbedc4c494db58bc9a6fffa72fc95f95a0613de2169",
16
- "lfs_size": 68411936,
17
- "xet_hash": "6e8f60efddd8c7caa8df21b2abec0198eb76cf6f6a455bdca73db38493870f0d"
18
- },
19
- "commits/cr_val.parquet": {
20
- "size": 88017946,
21
- "blob_id": "75709b935d623b7edb5ccd83dc0282d1440ac580",
22
- "lfs_sha256": "f73959d38ad7d479a3b6715d96ae22a42ea89c4e9b1830e3f9354ebada98877f",
23
- "lfs_size": 88017946,
24
- "xet_hash": "471f20effb87b24b7cb2f743e483c2e8d0799df56f1d33ff029e45552e31bbfb"
25
- },
26
- "commits/train.parquet": {
27
- "size": 612508015,
28
- "blob_id": "ff02daf9b1c12e369523125b664706b7dba70169",
29
- "lfs_sha256": "6dfca1e1791fde09c1f310f2be9273b762332f28563d203a2ed7f0136cb3590b",
30
- "lfs_size": 612508015,
31
- "xet_hash": "3d5479420b6a2cd17c9556b3235df14df1caacc9f75eac1e530a76f9a8d1d28a"
32
- },
33
- "qna/cr_test.parquet": {
34
- "size": 16240753,
35
- "blob_id": "5d5e537f81519bb5fc611cffc1d2f3e6a643403d",
36
- "lfs_sha256": "fc42611e215975824582df0da76984f6a65c3d5e29002a2b205fb5437cde907b",
37
- "lfs_size": 16240753,
38
- "xet_hash": "8ee16b74836d3602cf10e960cba16f083e25443e7803da5f411c9af49b3b0b12"
39
- },
40
- "qna/cr_val.parquet": {
41
- "size": 23488346,
42
- "blob_id": "b979c9c6fc248831d906057a88aa7c123eede5b4",
43
- "lfs_sha256": "3d76ca372ce366ab6f2b51765c9b5cbfbbfa33019b4e05d1dc05c25cacbea04f",
44
- "lfs_size": 23488346,
45
- "xet_hash": "a7764c559c4dda09f842dd904c11d4c7ae340c3b3d941e15fb5e6706cacec1be"
46
- },
47
- "qna/ir_test.parquet": {
48
- "size": 22805812,
49
- "blob_id": "e997fa64278ff967d0c08c22bb9c7a5571c343d5",
50
- "lfs_sha256": "af20fba7881a55b68efd82302b108615c6a5ae05be8e71d49c3455a7bbb124a4",
51
- "lfs_size": 22805812,
52
- "xet_hash": "9c268ba844d32ab694baf09c446c689289b9e873e4de8f9b9d3cae5470380450"
53
- },
54
- "qna/ir_val.parquet": {
55
- "size": 20154479,
56
- "blob_id": "4936c3c5f14b99c30b094b696a7df5f566745ffb",
57
- "lfs_sha256": "6b830ddb82490f1c7b6c44104cdcbcd1a8c9ca5f31d3c04af0421d2f0825c6a3",
58
- "lfs_size": 20154479,
59
- "xet_hash": "d51d246ad2ee31868d3a7d16890466349427120f47ef7fc278181d8e1e3d879d"
60
- },
61
- "qna/train.parquet": {
62
- "size": 135352731,
63
- "blob_id": "647f3e27841055c9538eec4495520d63e30f8cb6",
64
- "lfs_sha256": "519a092970f55750571c5223b1cfbcb0d36745a678cf41b48d4de6104c2a34e7",
65
- "lfs_size": 135352731,
66
- "xet_hash": "2a1f2087a42350f3ab6f79cda6d7be87ef81f70f3b25f0ed717463812ccdb951"
67
- }
68
- }
69
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/.gitignore DELETED
@@ -1 +0,0 @@
1
- *
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/CACHEDIR.TAG DELETED
@@ -1,4 +0,0 @@
1
- Signature: 8a477f597d28d172789f06886806bc55
2
- # This file is a cache directory tag created by huggingface_hub.
3
- # For information about cache directory tags, see:
4
- # https://bford.info/cachedir/
 
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/.gitattributes.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- bed0738c7eeb449bca98b5d2f33c89a1ee56349a
3
- 1784887199.592155
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/README.md.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- 1ee8621fd5030865aab5bef7ac72820d1778810c
3
- 1784887199.592134
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/cr_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- 2f9f2dfd78618cbb7e39c73deaed6ff9508fccd2491c8aeb4f172797d26b41aa
3
- 1784887229.378752
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/cr_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- 281812bd8d81620a83fa8bac002dbbda6c71ebbfd6a47c1df5c623be41992591
3
- 1784887234.453962
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/ir_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- e0cffc06d2c2f5d42ad42f2ce1b6b32ec54dbde46691cc78bc1e2bd4bb5d02e2
3
- 1784887216.458067
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/ir_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- 1efa4e7298807fe75ecd81a099908a42e3378eed80cd568659c816f96ab19fa1
3
- 1784887206.041879
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/commits/train.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- e9af541dd34eaf8ec4287b06dfc1b3a5b29f90f1ce7499a51855695786d6a3d2
3
- 1784887202.258442
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/cr_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- fc42611e215975824582df0da76984f6a65c3d5e29002a2b205fb5437cde907b
3
- 1784887213.327064
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/cr_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- 3d76ca372ce366ab6f2b51765c9b5cbfbbfa33019b4e05d1dc05c25cacbea04f
3
- 1784887225.967221
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/ir_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- af20fba7881a55b68efd82302b108615c6a5ae05be8e71d49c3455a7bbb124a4
3
- 1784887241.1003609
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/ir_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- 6b830ddb82490f1c7b6c44104cdcbcd1a8c9ca5f31d3c04af0421d2f0825c6a3
3
- 1784887232.856902
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/download/qna/train.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 65b7c77eed9398fc656052d058e9af7c2d432177
2
- b2fbe5bcd7e916c8d750b654a5b0b7286578f938ed65985eca68cd2936fb5dd1
3
- 1784887223.748132
 
 
 
 
data/real_code2lora/code2lora-static-anchor/.cache/huggingface/trees/65b7c77eed9398fc656052d058e9af7c2d432177.json DELETED
@@ -1,83 +0,0 @@
1
- {
2
- "format_version": 1,
3
- "files": {
4
- ".gitattributes": {
5
- "size": 2504,
6
- "blob_id": "bed0738c7eeb449bca98b5d2f33c89a1ee56349a"
7
- },
8
- "README.md": {
9
- "size": 1798,
10
- "blob_id": "1ee8621fd5030865aab5bef7ac72820d1778810c"
11
- },
12
- "commits/cr_test.parquet": {
13
- "size": 20979060,
14
- "blob_id": "f1a4c3af961e9f98348e4d7ca9ee7fb9ecc07bbc",
15
- "lfs_sha256": "2f9f2dfd78618cbb7e39c73deaed6ff9508fccd2491c8aeb4f172797d26b41aa",
16
- "lfs_size": 20979060,
17
- "xet_hash": "dccd2b6b33cb58024aba877ce8638a79576dbe444b902e054c45d0cc0f873f3a"
18
- },
19
- "commits/cr_val.parquet": {
20
- "size": 26834450,
21
- "blob_id": "240e8431f81a6332c9b954f4254129e6bef363e4",
22
- "lfs_sha256": "281812bd8d81620a83fa8bac002dbbda6c71ebbfd6a47c1df5c623be41992591",
23
- "lfs_size": 26834450,
24
- "xet_hash": "bfcfcb58af8285525bc2e48a53fe34c40e8d0bb1ba0949e9f6bc8d3f1889211e"
25
- },
26
- "commits/ir_test.parquet": {
27
- "size": 18069075,
28
- "blob_id": "869388baf5ac4d1634bf743c988829540ba0318f",
29
- "lfs_sha256": "e0cffc06d2c2f5d42ad42f2ce1b6b32ec54dbde46691cc78bc1e2bd4bb5d02e2",
30
- "lfs_size": 18069075,
31
- "xet_hash": "182e622aa94cc1f257d5e8d43b30f54e4b2497dd66dfdd3d54884d42fc27f02a"
32
- },
33
- "commits/ir_val.parquet": {
34
- "size": 16741758,
35
- "blob_id": "4a0def30c7d746a5eead7de1a977131825ccfc49",
36
- "lfs_sha256": "1efa4e7298807fe75ecd81a099908a42e3378eed80cd568659c816f96ab19fa1",
37
- "lfs_size": 16741758,
38
- "xet_hash": "ba00255aaa6c3f1bd3e297fd8917868a79591eb66bbc2051d79626d3628df556"
39
- },
40
- "commits/train.parquet": {
41
- "size": 1608634,
42
- "blob_id": "ef5092d91d972ceafe29e6591c2cb145255cdfa9",
43
- "lfs_sha256": "e9af541dd34eaf8ec4287b06dfc1b3a5b29f90f1ce7499a51855695786d6a3d2",
44
- "lfs_size": 1608634,
45
- "xet_hash": "45120132a92dfd70678b173eb110756e934fc6567c1347e04d3272aa148b5c1c"
46
- },
47
- "qna/cr_test.parquet": {
48
- "size": 16240753,
49
- "blob_id": "5d5e537f81519bb5fc611cffc1d2f3e6a643403d",
50
- "lfs_sha256": "fc42611e215975824582df0da76984f6a65c3d5e29002a2b205fb5437cde907b",
51
- "lfs_size": 16240753,
52
- "xet_hash": "8ee16b74836d3602cf10e960cba16f083e25443e7803da5f411c9af49b3b0b12"
53
- },
54
- "qna/cr_val.parquet": {
55
- "size": 23488346,
56
- "blob_id": "b979c9c6fc248831d906057a88aa7c123eede5b4",
57
- "lfs_sha256": "3d76ca372ce366ab6f2b51765c9b5cbfbbfa33019b4e05d1dc05c25cacbea04f",
58
- "lfs_size": 23488346,
59
- "xet_hash": "a7764c559c4dda09f842dd904c11d4c7ae340c3b3d941e15fb5e6706cacec1be"
60
- },
61
- "qna/ir_test.parquet": {
62
- "size": 22805812,
63
- "blob_id": "e997fa64278ff967d0c08c22bb9c7a5571c343d5",
64
- "lfs_sha256": "af20fba7881a55b68efd82302b108615c6a5ae05be8e71d49c3455a7bbb124a4",
65
- "lfs_size": 22805812,
66
- "xet_hash": "9c268ba844d32ab694baf09c446c689289b9e873e4de8f9b9d3cae5470380450"
67
- },
68
- "qna/ir_val.parquet": {
69
- "size": 20154479,
70
- "blob_id": "4936c3c5f14b99c30b094b696a7df5f566745ffb",
71
- "lfs_sha256": "6b830ddb82490f1c7b6c44104cdcbcd1a8c9ca5f31d3c04af0421d2f0825c6a3",
72
- "lfs_size": 20154479,
73
- "xet_hash": "d51d246ad2ee31868d3a7d16890466349427120f47ef7fc278181d8e1e3d879d"
74
- },
75
- "qna/train.parquet": {
76
- "size": 7436646,
77
- "blob_id": "b2fcda6096ba240d7aa7bd6c1d8ab8ef1ef7eb2c",
78
- "lfs_sha256": "b2fbe5bcd7e916c8d750b654a5b0b7286578f938ed65985eca68cd2936fb5dd1",
79
- "lfs_size": 7436646,
80
- "xet_hash": "1a44ec7585045f24c0fe8a3eb42d7068e552d0bc74fc5c94af75cb66c74a1cdf"
81
- }
82
- }
83
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/.gitignore DELETED
@@ -1 +0,0 @@
1
- *
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/CACHEDIR.TAG DELETED
@@ -1,4 +0,0 @@
1
- Signature: 8a477f597d28d172789f06886806bc55
2
- # This file is a cache directory tag created by huggingface_hub.
3
- # For information about cache directory tags, see:
4
- # https://bford.info/cachedir/
 
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/.gitattributes.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- bed0738c7eeb449bca98b5d2f33c89a1ee56349a
3
- 1784887242.232571
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/README.md.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- 0a390fc9888809d1fa519fee1965c070112e15dd
3
- 1784887242.3327308
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/cr_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- 234545feb01789ccfd422d0a02eea7bb43e5587e6be3e90ceca24012b7e665d7
3
- 1784887249.4468322
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/cr_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- 9c05111449e596a1817f61f3b2d728f9ae11031a425bc46e565373897db49272
3
- 1784887248.887584
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/ir_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- 7e6261be02c00201b7ed61950cebbeb1297f19f1de92ede70a9e63943747476a
3
- 1784887255.800129
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/ir_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- 2a1ba08fee4af69d321c8278493a5c3256ea96861c7f35d785e7c90be4657ec6
3
- 1784887257.502165
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/qna/train.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- d5657224e62418a77187285fe55a650ebad1a264bb9edbdc20c7d1e132c9b523
3
- 1784887281.037739
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/repos/cr_test.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- 0d597c8a2462fd407394db40ab9025dc4f4ccc0697a2d4490fdd2a1eab91578f
3
- 1784887243.962303
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/repos/cr_val.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- 8ac1c2477884783356be16f4e2ec5c94c60823df8befb4a2d80813f40c84b794
3
- 1784887244.5128582
 
 
 
 
data/real_code2lora/code2lora-static/.cache/huggingface/download/repos/train.parquet.metadata DELETED
@@ -1,3 +0,0 @@
1
- 5ebfd4fabc36b4daf5fb2b056f48ce2d67d3a9d4
2
- ad382500d5bb420e0c8064e7f79d8a26fc12aa8e5b209c95b145a0b4a18dd8ba
3
- 1784887245.4021702