tensor-cli 0.1.4-beta-lite → 0.1.5-beta-lite

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.
Files changed (2) hide show
  1. package/dist/index.js +372 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -340793,6 +340793,222 @@ async function webSearch(query, budget, limit = DEFAULT_LIMIT) {
340793
340793
  }
340794
340794
  }
340795
340795
 
340796
+ // src/tools/harness-verify.ts
340797
+ var VERIFY_MAX_REVISIONS = 1;
340798
+ var VERIFY_MIN_CHARS = 400;
340799
+ var AUTO_FULL_MIN_CHARS = 1500;
340800
+ var VERIFY_CONTENT_CHAR_CAP = 24000;
340801
+ var VERIFY_SOURCE_CHAR_CAP = 12000;
340802
+ var VERIFIER_MAX_TOKENS = 600;
340803
+ function formatFindings(findings) {
340804
+ return findings.map((f2, i2) => `${i2 + 1}. ${f2.issue}${f2.evidence ? ` (${f2.evidence})` : ""}`).join(`
340805
+ `);
340806
+ }
340807
+ var TOOL_TAG_RE = /<tool_call\b|<function=|<parameter=|<tool_use\b|<file_path>/i;
340808
+ var ELISION_RE = /^[ \t]*(?:\/\/|#|\/\*|<!--)[ \t]*(?:\.{3}|\u2026)[ \t]*(?:rest|existing|remaining|other|previous|unchanged|same)\b|^[ \t]*(?:\/\/|#|\/\*)[ \t]*(?:rest of|remaining|existing)[ \t]+(?:the[ \t]+)?(?:code|file|implementation|content)\b/im;
340809
+ var LOADERS = {
340810
+ ".ts": "ts",
340811
+ ".tsx": "tsx",
340812
+ ".js": "js",
340813
+ ".mjs": "js",
340814
+ ".cjs": "js",
340815
+ ".jsx": "jsx"
340816
+ };
340817
+ function extOf(file2) {
340818
+ const dot = file2.lastIndexOf(".");
340819
+ return dot > file2.lastIndexOf("/") ? file2.slice(dot).toLowerCase() : "";
340820
+ }
340821
+ function syntaxError(file2, content) {
340822
+ const loader = LOADERS[extOf(file2)];
340823
+ if (!loader)
340824
+ return null;
340825
+ const Transpiler = globalThis.Bun?.Transpiler;
340826
+ if (!Transpiler)
340827
+ return null;
340828
+ try {
340829
+ new Transpiler({ loader }).transformSync(content);
340830
+ return null;
340831
+ } catch (e3) {
340832
+ const errs = e3.errors;
340833
+ const msg = Array.isArray(errs) && errs.length > 0 ? errs.slice(0, 3).map((x) => x.message ?? String(x)).join("; ") : e3 instanceof Error ? e3.message : String(e3);
340834
+ return clipText(msg, 300);
340835
+ }
340836
+ }
340837
+ function deterministicChecks(file2, content, mode) {
340838
+ if (content.trim() === "")
340839
+ return [{ issue: "content is empty", hard: true }];
340840
+ const out = [];
340841
+ const ext = extOf(file2);
340842
+ if (TOOL_TAG_RE.test(content)) {
340843
+ out.push({ issue: "content contains leaked tool-call markup", hard: true });
340844
+ }
340845
+ if (/^```/.test(content.trimStart()) && ext !== ".md" && ext !== ".mdx") {
340846
+ out.push({ issue: "content starts with a markdown code fence", hard: true });
340847
+ }
340848
+ if (mode === "write") {
340849
+ const elision = DOC_EXT.has(ext) ? null : ELISION_RE.exec(content);
340850
+ if (elision) {
340851
+ out.push({
340852
+ issue: "content contains an elision placeholder (e.g. 'rest of file unchanged'); a write must contain the complete file",
340853
+ evidence: clipText(elision[0].trim(), 80)
340854
+ });
340855
+ }
340856
+ if (ext === ".json" && !/(^|\/)(tsconfig|jsconfig)[^/]*\.json$/.test(file2)) {
340857
+ try {
340858
+ JSON.parse(content);
340859
+ } catch (e3) {
340860
+ out.push({
340861
+ issue: "invalid JSON",
340862
+ evidence: clipText(e3 instanceof Error ? e3.message : String(e3), 200),
340863
+ hard: true
340864
+ });
340865
+ }
340866
+ }
340867
+ const se = syntaxError(file2, content);
340868
+ if (se)
340869
+ out.push({ issue: "syntax error", evidence: se, hard: true });
340870
+ }
340871
+ return out;
340872
+ }
340873
+ function parseVerifyMode(v) {
340874
+ const x = (v ?? "").trim().toLowerCase();
340875
+ if (x === "off" || x === "0" || x === "false")
340876
+ return "off";
340877
+ if (x === "checks")
340878
+ return "checks";
340879
+ if (x === "full" || x === "1" || x === "true")
340880
+ return "full";
340881
+ return "auto";
340882
+ }
340883
+ var DOC_EXT = new Set([".md", ".mdx", ".txt", ".rst"]);
340884
+ function chooseVerifyLevel(a2) {
340885
+ if (a2.mode === "checks" || a2.mode === "full")
340886
+ return a2.mode;
340887
+ const shrinks = a2.tool === "write" && a2.currentFile.length >= 400 && a2.content.length < a2.currentFile.length * 0.5;
340888
+ if (shrinks)
340889
+ return "full";
340890
+ if (DOC_EXT.has(extOf(a2.file)))
340891
+ return "checks";
340892
+ const overwrite = a2.tool === "write" && a2.currentFile.trim() !== "";
340893
+ if (overwrite && a2.content.length >= VERIFY_MIN_CHARS)
340894
+ return "full";
340895
+ if (a2.content.length >= AUTO_FULL_MIN_CHARS)
340896
+ return "full";
340897
+ return "checks";
340898
+ }
340899
+ var VERIFIER_SYSTEM = `You are a strict reviewer. You did NOT write the proposed content below; your only job is to find concrete, checkable problems in it. Do not praise it.
340900
+ ` + `Check ONLY these:
340901
+ ` + `1. It does what the TASK and INTENT ask. Missing or contradicted requirements count.
340902
+ ` + `2. It does not reference imports, functions, files, fields or APIs that appear in neither the SOURCES nor the standard library / well-known packages.
340903
+ ` + `3. For a whole-file REPLACE: it does not silently drop existing behaviour from CURRENT FILE that the task did not ask to remove.
340904
+ ` + `4. It is complete: no TODO stubs standing in for required logic, no "rest unchanged" elisions, no truncated ending.
340905
+ ` + `Do NOT fail for style, naming, formatting or optional improvements. If you cannot tell from the SOURCES, pass.
340906
+ ` + `Respond with ONLY one JSON object: {"pass": boolean, "failures": [{"issue": string, "evidence": string}]}. ` + `"failures" is empty when pass is true. Each evidence is a short quote or location from the content.`;
340907
+ async function modelVerify(a2, content) {
340908
+ const target = a2.mode === "append" ? "the content below will be APPENDED to the end of the file" : a2.currentFile ? "the content below will REPLACE the whole file" : "this is a NEW file";
340909
+ const sources = a2.sources.map((s2, i2) => `[Source ${i2 + 1}]
340910
+ ${clipText(s2, 5000)}`).join(`
340911
+
340912
+ `);
340913
+ const user = `TASK (the user's request):
340914
+ ${clipText(a2.task, 1500)}
340915
+
340916
+ ` + `INTENT of this step:
340917
+ ${clipText(a2.intent, 500)}
340918
+
340919
+ ` + `TARGET FILE: ${a2.file} (${target})
340920
+
340921
+ ` + (a2.currentFile ? `CURRENT FILE ON DISK:
340922
+ ${clipText(a2.currentFile, VERIFY_SOURCE_CHAR_CAP / 2)}
340923
+
340924
+ ` : "") + (sources ? `SOURCES (files the agent read):
340925
+ ${sources}
340926
+
340927
+ ` : "") + `PROPOSED CONTENT:
340928
+ ${clipText(content, VERIFY_CONTENT_CHAR_CAP)}`;
340929
+ let raw = "";
340930
+ try {
340931
+ raw = await a2.chat([
340932
+ { role: "system", content: VERIFIER_SYSTEM },
340933
+ { role: "user", content: user }
340934
+ ], VERIFIER_MAX_TOKENS);
340935
+ } catch {
340936
+ return { available: false, failures: [] };
340937
+ }
340938
+ const json3 = extractFirstJsonObject(raw);
340939
+ if (!json3)
340940
+ return { available: false, failures: [] };
340941
+ let parsed;
340942
+ try {
340943
+ parsed = JSON.parse(json3);
340944
+ } catch {
340945
+ return { available: false, failures: [] };
340946
+ }
340947
+ if (!isRecord2(parsed) || typeof parsed.pass !== "boolean") {
340948
+ return { available: false, failures: [] };
340949
+ }
340950
+ if (parsed.pass)
340951
+ return { available: true, failures: [] };
340952
+ const failures = (Array.isArray(parsed.failures) ? parsed.failures : []).filter(isRecord2).map((f2) => ({
340953
+ issue: String(f2.issue ?? "").trim().slice(0, 300),
340954
+ evidence: f2.evidence ? String(f2.evidence).trim().slice(0, 300) : undefined
340955
+ })).filter((f2) => f2.issue !== "").slice(0, 5);
340956
+ return { available: true, failures };
340957
+ }
340958
+ async function verifyBeforeWrite(a2) {
340959
+ let content = a2.content;
340960
+ let revisions = 0;
340961
+ let verifierCalls = 0;
340962
+ let verifierUnavailable = false;
340963
+ let findings = [];
340964
+ let cleanDraft = null;
340965
+ let cleanDraftFindings = [];
340966
+ const result = (c2, status, f2) => ({
340967
+ content: c2,
340968
+ status,
340969
+ findings: f2,
340970
+ revisions,
340971
+ verifierCalls,
340972
+ verifierUnavailable
340973
+ });
340974
+ for (;; ) {
340975
+ const det = deterministicChecks(a2.file, content, a2.mode);
340976
+ findings = det;
340977
+ if (a2.level === "full" && det.length === 0 && !a2.isCancelled?.()) {
340978
+ verifierCalls++;
340979
+ const v = await modelVerify(a2, content);
340980
+ if (v.available)
340981
+ findings = v.failures;
340982
+ else
340983
+ verifierUnavailable = true;
340984
+ }
340985
+ if (!findings.some((f2) => f2.hard)) {
340986
+ cleanDraft = content;
340987
+ cleanDraftFindings = findings;
340988
+ }
340989
+ if (findings.length === 0)
340990
+ return result(content, "verified", []);
340991
+ if (revisions >= VERIFY_MAX_REVISIONS || a2.isCancelled?.())
340992
+ break;
340993
+ revisions++;
340994
+ const first = findings[0];
340995
+ a2.log?.(`Revising ${a2.file}: ${first?.issue ?? "failed check"}${first?.evidence ? ` [${first.evidence}]` : ""}`);
340996
+ let revised = "";
340997
+ try {
340998
+ revised = await a2.revise(content, findings);
340999
+ } catch {}
341000
+ if (revised.trim() === "" || revised === content)
341001
+ break;
341002
+ content = revised;
341003
+ }
341004
+ if (findings.some((f2) => f2.hard)) {
341005
+ if (cleanDraft !== null)
341006
+ return result(cleanDraft, "unverified", cleanDraftFindings);
341007
+ return result(content, "blocked", findings);
341008
+ }
341009
+ return result(content, "unverified", findings);
341010
+ }
341011
+
340796
341012
  // src/tools/harness-orchestrator.ts
340797
341013
  function estimateMessagesTokens(messages) {
340798
341014
  let textTokens = 0;
@@ -340840,6 +341056,124 @@ class HarnessOrchestrator {
340840
341056
  this.totalUsedContext = countTokens2(this.buildDecisionPrompt(false));
340841
341057
  }
340842
341058
  filePluginHandler = null;
341059
+ static VERIFY_MODE = parseVerifyMode("full");
341060
+ verifyStats = {
341061
+ checked: 0,
341062
+ full: 0,
341063
+ revised: 0,
341064
+ verifierCalls: 0,
341065
+ unverified: 0,
341066
+ blocked: 0
341067
+ };
341068
+ getVerifyStats() {
341069
+ return { ...this.verifyStats };
341070
+ }
341071
+ async* preWriteGate(ctx, a2) {
341072
+ const mode = HarnessOrchestrator.VERIFY_MODE;
341073
+ if (mode === "off") {
341074
+ return {
341075
+ content: a2.content,
341076
+ status: "verified",
341077
+ findings: [],
341078
+ revisions: 0,
341079
+ verifierCalls: 0,
341080
+ verifierUnavailable: false
341081
+ };
341082
+ }
341083
+ const currentFile = existsSync(a2.filePath) ? await readFileContent(a2.filePath).catch(() => "") : "";
341084
+ const level = chooseVerifyLevel({
341085
+ mode,
341086
+ file: a2.displayPath,
341087
+ tool: a2.tool,
341088
+ content: a2.content,
341089
+ currentFile
341090
+ });
341091
+ const lines = [];
341092
+ const out = yield* this.pump(verifyBeforeWrite({
341093
+ file: a2.displayPath,
341094
+ mode: a2.tool,
341095
+ content: a2.content,
341096
+ task: ctx.userTask,
341097
+ intent: a2.intent,
341098
+ currentFile,
341099
+ sources: level === "full" ? this.verifySources(ctx, a2.displayPath) : [],
341100
+ level,
341101
+ isCancelled: this.isCancelled,
341102
+ log: (l) => lines.push(l),
341103
+ chat: (messages, maxTokens) => this.routedChat(a2.verifierModelId, messages, 0.1, maxTokens).then((r) => r.content),
341104
+ revise: (draft, findings) => this.reviseContent(ctx, a2, draft, findings)
341105
+ }));
341106
+ const s2 = this.verifyStats;
341107
+ s2.checked++;
341108
+ if (level === "full")
341109
+ s2.full++;
341110
+ s2.revised += out.revisions;
341111
+ s2.verifierCalls += out.verifierCalls;
341112
+ if (out.status === "unverified")
341113
+ s2.unverified++;
341114
+ if (out.status === "blocked")
341115
+ s2.blocked++;
341116
+ for (const l of lines)
341117
+ yield { delta: `- ${l}
341118
+ ` };
341119
+ if (out.status === "unverified") {
341120
+ yield {
341121
+ delta: `- ${a2.displayPath} did not pass every check (${out.findings[0]?.issue ?? "see findings"}); writing it anyway and flagging it
341122
+
341123
+ `
341124
+ };
341125
+ }
341126
+ if (DEBUG_TRACE) {
341127
+ yield {
341128
+ delta: `[debug] pre-write gate: ${out.status}, ${out.verifierCalls} verifier call(s), ${out.revisions} revision(s)
341129
+ `
341130
+ };
341131
+ }
341132
+ return out;
341133
+ }
341134
+ async reviseContent(ctx, a2, draft, findings) {
341135
+ const res = await this.routedChat(ctx.modelId, [
341136
+ {
341137
+ role: "system",
341138
+ content: `RAW CODE OUTPUT MODE. Respond with ONLY the raw ${a2.tool === "append" ? "text to append" : "complete file"}. ` + `No JSON, no markdown fences, no commentary. The first character of your response must be the first character of the content.`
341139
+ },
341140
+ ...this.memoryMessages(),
341141
+ {
341142
+ role: "user",
341143
+ content: `Task: ${clipText(ctx.userTask, 3000)}
341144
+ ` + `Target file: ${a2.targetFile}
341145
+
341146
+ ` + `Your previous draft was rejected for these problems:
341147
+ ${formatFindings(findings)}
341148
+
341149
+ ` + `Previous draft:
341150
+ ${draft}
341151
+
341152
+ ` + `Return the corrected ${a2.tool === "append" ? "text to append" : "complete file"}. ` + `Fix only the listed problems and keep everything else unchanged.`
341153
+ }
341154
+ ], 0.2, CONTENT_MAX_TOKENS);
341155
+ if (res.content.startsWith("AGENT LOOP FAILED"))
341156
+ return "";
341157
+ let text = res.content.replace(/^```[a-z]*\n?|\n?```$/g, "").trim();
341158
+ const { unwrapped, wasWrapper } = tryUnwrapDecisionJson(text);
341159
+ if (wasWrapper)
341160
+ text = (unwrapped ?? "").trim();
341161
+ return text;
341162
+ }
341163
+ verifySources(ctx, displayPath) {
341164
+ const out = [];
341165
+ for (let i2 = ctx.contextMessages.length - 1;i2 >= 0 && out.length < 3; i2--) {
341166
+ const c2 = ctx.contextMessages[i2]?.content;
341167
+ if (typeof c2 !== "string" || !c2.startsWith("[Tool Output \u2014 read on "))
341168
+ continue;
341169
+ if (c2.includes(`read on ${displayPath}]`))
341170
+ continue;
341171
+ if (c2.includes("elided to save context"))
341172
+ continue;
341173
+ out.push(c2.slice(0, 5000));
341174
+ }
341175
+ return out;
341176
+ }
340843
341177
  registerFileHandler(handler) {
340844
341178
  this.filePluginHandler = handler;
340845
341179
  }
@@ -342675,6 +343009,43 @@ ${truncateForContext(priorFileSnapshot)}
342675
343009
  }
342676
343010
  }
342677
343011
  ctx.updateThinkingWord?.("toolLeveraging");
343012
+ if (HarnessOrchestrator.VERIFY_MODE !== "off" && (decision.tool === "write" || decision.tool === "append") && typeof decision.content === "string" && decision.content.trim() !== "") {
343013
+ const draft = decision.content;
343014
+ const gate = yield* this.preWriteGate(ctx, {
343015
+ tool: decision.tool,
343016
+ targetFile: decision.targetFile,
343017
+ displayPath,
343018
+ filePath,
343019
+ content: draft,
343020
+ intent: decision.reasoning ?? "",
343021
+ verifierModelId: decisionModelId
343022
+ });
343023
+ if (gate.status === "blocked") {
343024
+ this.settleToolCall(call, "refused", `pre-write check failed: ${gate.findings[0]?.issue ?? "invalid content"}`);
343025
+ yield { delta: `- Not written: ${displayPath} failed pre-write checks
343026
+
343027
+ ` };
343028
+ ctx.contextMessages.push({
343029
+ role: "user",
343030
+ content: `[System] The content for "${decision.targetFile}" failed checks and was NOT written:
343031
+ ${formatFindings(gate.findings)}
343032
+ Fix these and try again, or return {"tool": null}.`
343033
+ });
343034
+ continue;
343035
+ }
343036
+ if (gate.content !== draft) {
343037
+ decision = { ...decision, content: gate.content };
343038
+ verifiedContentOverride = null;
343039
+ }
343040
+ if (gate.status === "unverified") {
343041
+ ctx.contextMessages.push({
343042
+ role: "user",
343043
+ content: `[System] "${decision.targetFile}" is being written but did not pass every check:
343044
+ ${formatFindings(gate.findings)}
343045
+ Tell the user about these in your final answer.`
343046
+ });
343047
+ }
343048
+ }
342678
343049
  const breakOnSemicolons = (text, indent = " ") => {
342679
343050
  return text.replace(/; ?/g, `;
342680
343051
  ${indent}`);
@@ -344476,7 +344847,7 @@ var Header = () => {
344476
344847
  }, undefined, false, undefined, this),
344477
344848
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
344478
344849
  fg: t2.inkFaint,
344479
- children: "v0.1.4@beta-lite"
344850
+ children: "v0.1.5@beta-lite"
344480
344851
  }, undefined, false, undefined, this)
344481
344852
  ]
344482
344853
  }, undefined, true, undefined, this),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tensor-cli",
3
- "version": "0.1.4-beta-lite",
3
+ "version": "0.1.5-beta-lite",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "tensor": "./dist/index.js"