Spaces:
Running
Running
deploy space from main
Browse files- static/app.js +75 -1
- static/index.html +1 -1
static/app.js
CHANGED
|
@@ -138,7 +138,81 @@ document.addEventListener("click", (e) => {
|
|
| 138 |
document.body.classList.toggle("hide-noise", HIDE_NOISE);
|
| 139 |
}
|
| 140 |
});
|
| 141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
// Live-as-you-type: debounce, and only fire on a valid regex so partial patterns
|
| 143 |
// (e.g. an open paren mid-type) never clobber the last results with an error.
|
| 144 |
$("q").addEventListener("input", () => {
|
|
|
|
| 138 |
document.body.classList.toggle("hide-noise", HIDE_NOISE);
|
| 139 |
}
|
| 140 |
});
|
| 141 |
+
// ---- English -> regex (bring your own Anthropic key) ----
|
| 142 |
+
// The model compiles the question ONCE; matching stays deterministic grep on
|
| 143 |
+
// the server. The key lives in sessionStorage for this tab only and is sent
|
| 144 |
+
// only to api.anthropic.com. The compiled regex + its literal paraphrase are
|
| 145 |
+
// always shown so the translation can be checked before trusting counts.
|
| 146 |
+
const ATOM_WORDS = new Set(["localize","read_file","edit","run_test","search_repo","create_file",
|
| 147 |
+
"delete_file","submit","think","error","prompt_ai","version_control","package","lint","run_code","other"]);
|
| 148 |
+
function looksEnglish(v) {
|
| 149 |
+
const words = (v.match(/[a-z_]+/gi) || []).filter((w) => w.length > 1);
|
| 150 |
+
return words.length > 0 && words.some((w) => !ATOM_WORDS.has(w.toLowerCase()));
|
| 151 |
+
}
|
| 152 |
+
const ASK_SYSTEM = `You compile English questions about coding-agent behavior into a Python-compatible regex over a trace's space-joined atom sequence.
|
| 153 |
+
Atoms: ${[...ATOM_WORDS].sort().join(", ")}.
|
| 154 |
+
A trace is atoms joined by single spaces plus one trailing space. think/other interleave between actions, so adjacent-action idioms need skips like (?:think |other )?.
|
| 155 |
+
Idioms: streaks (edit (?:think |other )?){5,} · absence before an event ^(?:(?!run_test).)*submit · absence everywhere ^(?:(?!search_repo).)*$
|
| 156 |
+
Examples: "submitted without testing" -> ^(?:(?!run_test).)*submit · "stuck reading" -> (read_file (?:think )?){4,} · "edit streak of 5+" -> (edit (?:think |other )?){5,} · "recovered from an error" -> error (?:think |other )?edit
|
| 157 |
+
The regex layer CANNOT express temporal windows, variable binding, counts across gaps, or probabilistic thresholds: for those set expressible false and suggest the nearest expressible query in reason.
|
| 158 |
+
When expressible, also return a one-line paraphrase of what the regex LITERALLY matches.`;
|
| 159 |
+
async function askCompile(question) {
|
| 160 |
+
let key = sessionStorage.getItem("anthropic_key");
|
| 161 |
+
if (!key) {
|
| 162 |
+
key = window.prompt("Anthropic API key (kept in this tab's sessionStorage only; sent only to api.anthropic.com):");
|
| 163 |
+
if (!key) return;
|
| 164 |
+
sessionStorage.setItem("anthropic_key", key.trim());
|
| 165 |
+
key = key.trim();
|
| 166 |
+
}
|
| 167 |
+
$("res").innerHTML = '<span class="dim">compiling the question to a regex (one model call)…</span>';
|
| 168 |
+
let body;
|
| 169 |
+
try {
|
| 170 |
+
const resp = await fetch("https://api.anthropic.com/v1/messages", {
|
| 171 |
+
method: "POST",
|
| 172 |
+
headers: {
|
| 173 |
+
"x-api-key": key,
|
| 174 |
+
"anthropic-version": "2023-06-01",
|
| 175 |
+
"anthropic-dangerous-direct-browser-access": "true",
|
| 176 |
+
"content-type": "application/json",
|
| 177 |
+
},
|
| 178 |
+
body: JSON.stringify({
|
| 179 |
+
model: "claude-opus-5",
|
| 180 |
+
max_tokens: 16000,
|
| 181 |
+
system: ASK_SYSTEM,
|
| 182 |
+
output_config: { effort: "low", format: { type: "json_schema", schema: {
|
| 183 |
+
type: "object",
|
| 184 |
+
properties: { expressible: { type: "boolean" }, regex: { type: ["string", "null"] },
|
| 185 |
+
paraphrase: { type: ["string", "null"] }, reason: { type: ["string", "null"] } },
|
| 186 |
+
required: ["expressible", "regex", "paraphrase", "reason"], additionalProperties: false,
|
| 187 |
+
} } },
|
| 188 |
+
messages: [{ role: "user", content: question }],
|
| 189 |
+
}),
|
| 190 |
+
});
|
| 191 |
+
if (resp.status === 401) { sessionStorage.removeItem("anthropic_key"); throw new Error("invalid API key (cleared; retry to re-enter)"); }
|
| 192 |
+
if (!resp.ok) throw new Error(`API returned ${resp.status}`);
|
| 193 |
+
body = await resp.json();
|
| 194 |
+
} catch (e) {
|
| 195 |
+
$("res").innerHTML = `<span class="err">ask failed: ${e.message || e}</span>`;
|
| 196 |
+
return;
|
| 197 |
+
}
|
| 198 |
+
const text = (body.content || []).find((b) => b.type === "text");
|
| 199 |
+
let parsed;
|
| 200 |
+
try { parsed = JSON.parse(text.text); } catch { $("res").innerHTML = '<span class="err">ask failed: unparseable model reply</span>'; return; }
|
| 201 |
+
if (!parsed.expressible) {
|
| 202 |
+
$("res").innerHTML = `<div><b>not expressible</b> as a spine regex</div><div class="dim" style="margin-top:6px">${parsed.reason || ""}</div>`;
|
| 203 |
+
return;
|
| 204 |
+
}
|
| 205 |
+
try { new RegExp(parsed.regex); } catch { $("res").innerHTML = '<span class="err">ask failed: model returned an invalid regex</span>'; return; }
|
| 206 |
+
await run(parsed.regex);
|
| 207 |
+
$("res").insertAdjacentHTML("afterbegin",
|
| 208 |
+
`<div class="dim" style="margin-bottom:8px">“${question}” compiled to <b>/${parsed.regex}/</b> · matches: ${parsed.paraphrase || "?"} · check the translation before trusting counts</div>`);
|
| 209 |
+
}
|
| 210 |
+
$("q").addEventListener("keydown", (e) => {
|
| 211 |
+
if (e.key !== "Enter") return;
|
| 212 |
+
clearTimeout(QTIMER);
|
| 213 |
+
const v = $("q").value.trim();
|
| 214 |
+
if (looksEnglish(v)) askCompile(v); else run(v);
|
| 215 |
+
});
|
| 216 |
// Live-as-you-type: debounce, and only fire on a valid regex so partial patterns
|
| 217 |
// (e.g. an open paren mid-type) never clobber the last results with an error.
|
| 218 |
$("q").addEventListener("input", () => {
|
static/index.html
CHANGED
|
@@ -92,7 +92,7 @@ scans it whole; no model call.</p>
|
|
| 92 |
<p class="note prov">These are public agent-rollout corpora on Hugging Face (SWE-agent and OpenHands
|
| 93 |
scaffolds solving SWE-bench-family GitHub issues). ProcGrep canonicalizes each trajectory into an action spine; nothing is re-hosted.</p>
|
| 94 |
<div class="qbar"><span class="mag">⌕</span>
|
| 95 |
-
<input id="q" placeholder="atom pattern
|
| 96 |
<div class="tryline">try: <span id="trychips"></span> <span class="chip" id="noisetog">hide think/other</span></div>
|
| 97 |
<div id="res"></div>
|
| 98 |
</section>
|
|
|
|
| 92 |
<p class="note prov">These are public agent-rollout corpora on Hugging Face (SWE-agent and OpenHands
|
| 93 |
scaffolds solving SWE-bench-family GitHub issues). ProcGrep canonicalizes each trajectory into an action spine; nothing is re-hosted.</p>
|
| 94 |
<div class="qbar"><span class="mag">⌕</span>
|
| 95 |
+
<input id="q" placeholder="atom pattern like (edit ){5,}, or an English question + Enter (BYO Anthropic key)" autocomplete="off"></div>
|
| 96 |
<div class="tryline">try: <span id="trychips"></span> <span class="chip" id="noisetog">hide think/other</span></div>
|
| 97 |
<div id="res"></div>
|
| 98 |
</section>
|