opencode-agent-skill 14.2.0-beta.1 → 14.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -8
- package/docs/PI-COMPAT.md +16 -1
- package/lib/capability-fabric.mjs +23 -0
- package/lib/code-intelligence/edit-anchor.mjs +102 -0
- package/lib/code-intelligence/index.mjs +95 -0
- package/lib/code-intelligence/lsp-provider.mjs +189 -0
- package/lib/completion-auditor.mjs +82 -0
- package/lib/document-ingestion.mjs +60 -0
- package/lib/fast-verification-gate.mjs +69 -0
- package/lib/mcp-health.mjs +144 -0
- package/lib/mcp-tool-policy.mjs +19 -0
- package/lib/memory-engine.mjs +28 -0
- package/lib/prompt-cache.mjs +26 -12
- package/lib/reversible-context.mjs +49 -0
- package/lib/task-engine.mjs +6 -10
- package/lib/task-policy.mjs +61 -5
- package/package.json +3 -3
- package/pi/extensions/ues-child-runtime.ts +155 -0
- package/pi/extensions/ues.ts +145 -18
- package/scripts/check-source-integrity.mjs +62 -0
|
@@ -10,6 +10,15 @@ import {
|
|
|
10
10
|
canonicalVerificationCommand,
|
|
11
11
|
looksLikeVerificationCommand,
|
|
12
12
|
} from "../../lib/verification-command.mjs";
|
|
13
|
+
import {
|
|
14
|
+
applyAnchoredFileEdits,
|
|
15
|
+
diagnoseCode,
|
|
16
|
+
probeCodeIntelligence,
|
|
17
|
+
readAnchoredCode,
|
|
18
|
+
searchCodeIntelligence,
|
|
19
|
+
} from "../../lib/code-intelligence/index.mjs";
|
|
20
|
+
import { ingestDocument } from "../../lib/document-ingestion.mjs";
|
|
21
|
+
import { compactContext, expandContext, searchContext } from "../../lib/reversible-context.mjs";
|
|
13
22
|
|
|
14
23
|
const toolExecutionState = new Map<string, {
|
|
15
24
|
startedAt: number;
|
|
@@ -190,6 +199,152 @@ export default function (pi: ExtensionAPI) {
|
|
|
190
199
|
};
|
|
191
200
|
});
|
|
192
201
|
|
|
202
|
+
const AnchoredEdit = Type.Object({
|
|
203
|
+
anchor: Type.String({ minLength: 1 }),
|
|
204
|
+
endAnchor: Type.Optional(Type.String({ minLength: 1 })),
|
|
205
|
+
replacement: Type.String(),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
pi.registerTool({
|
|
209
|
+
name: "ues_code",
|
|
210
|
+
label: "UES Code Intelligence",
|
|
211
|
+
description:
|
|
212
|
+
"Bounded code/document/context intelligence for weak models: semantic/AST search, hash-anchored reads, optional LSP diagnostics, optional MarkItDown ingestion, and reversible context recovery.",
|
|
213
|
+
parameters: Type.Object({
|
|
214
|
+
action: Type.Union([
|
|
215
|
+
Type.Literal("status"),
|
|
216
|
+
Type.Literal("search"),
|
|
217
|
+
Type.Literal("read"),
|
|
218
|
+
Type.Literal("diagnostics"),
|
|
219
|
+
Type.Literal("document"),
|
|
220
|
+
Type.Literal("context-expand"),
|
|
221
|
+
Type.Literal("context-search"),
|
|
222
|
+
]),
|
|
223
|
+
file: Type.Optional(Type.String()),
|
|
224
|
+
query: Type.Optional(Type.String()),
|
|
225
|
+
structuralPattern: Type.Optional(Type.String()),
|
|
226
|
+
language: Type.Optional(Type.String()),
|
|
227
|
+
startLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
228
|
+
endLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
229
|
+
ref: Type.Optional(Type.String()),
|
|
230
|
+
maxBytes: Type.Optional(Type.Number({ minimum: 1, maximum: 128000 })),
|
|
231
|
+
}),
|
|
232
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
233
|
+
try {
|
|
234
|
+
let result: any;
|
|
235
|
+
if (params.action === "status") {
|
|
236
|
+
result = probeCodeIntelligence(params.file || "");
|
|
237
|
+
} else if (params.action === "search") {
|
|
238
|
+
if (!params.query) throw new Error("ues_code search requires query");
|
|
239
|
+
result = await searchCodeIntelligence(ctx.cwd, params.query, {
|
|
240
|
+
structuralPattern: params.structuralPattern,
|
|
241
|
+
language: params.language,
|
|
242
|
+
file: params.file,
|
|
243
|
+
maxResults: 12,
|
|
244
|
+
});
|
|
245
|
+
} else if (params.action === "read") {
|
|
246
|
+
if (!params.file) throw new Error("ues_code read requires file");
|
|
247
|
+
const startLine = Math.max(1, Math.trunc(Number(params.startLine || 1)));
|
|
248
|
+
const endLine = Math.max(startLine, Math.min(startLine + 399, Math.trunc(Number(params.endLine || startLine + 199))));
|
|
249
|
+
result = await readAnchoredCode(ctx.cwd, params.file, { startLine, endLine });
|
|
250
|
+
return {
|
|
251
|
+
content: [{ type: "text", text: [
|
|
252
|
+
`file: ${result.file}; lines: ${result.startLine}-${result.endLine}/${result.lineCount}; sourceHash: ${result.sourceHash}`,
|
|
253
|
+
"",
|
|
254
|
+
result.text,
|
|
255
|
+
].join("\n") }],
|
|
256
|
+
details: { action: params.action, file: result.file, sourceHash: result.sourceHash, startLine: result.startLine, endLine: result.endLine },
|
|
257
|
+
};
|
|
258
|
+
} else if (params.action === "diagnostics") {
|
|
259
|
+
if (!params.file) throw new Error("ues_code diagnostics requires file");
|
|
260
|
+
result = await diagnoseCode(ctx.cwd, params.file, { timeoutMs: 3000, maxDiagnostics: 40 });
|
|
261
|
+
} else if (params.action === "document") {
|
|
262
|
+
if (!params.file) throw new Error("ues_code document requires file");
|
|
263
|
+
const document = await ingestDocument(ctx.cwd, params.file, { maxBytes: Math.min(Number(params.maxBytes || 4 * 1024 * 1024), 4 * 1024 * 1024) });
|
|
264
|
+
const block = await compactContext(ctx.cwd, document.markdown, {
|
|
265
|
+
kind: "document-ingestion",
|
|
266
|
+
source: document.file,
|
|
267
|
+
summary: `Normalized document from ${document.provider}`,
|
|
268
|
+
});
|
|
269
|
+
result = {
|
|
270
|
+
provider: document.provider,
|
|
271
|
+
file: document.file,
|
|
272
|
+
bytes: document.bytes,
|
|
273
|
+
optionalDependency: document.optionalDependency,
|
|
274
|
+
contextRef: block.ref,
|
|
275
|
+
originalChars: block.originalChars,
|
|
276
|
+
summary: block.levels.T1,
|
|
277
|
+
};
|
|
278
|
+
} else if (params.action === "context-expand") {
|
|
279
|
+
if (!params.ref) throw new Error("ues_code context-expand requires ref");
|
|
280
|
+
const expanded = await expandContext(ctx.cwd, params.ref, { maxBytes: params.maxBytes || 16000 });
|
|
281
|
+
return {
|
|
282
|
+
content: [{ type: "text", text: expanded.content }],
|
|
283
|
+
details: { action: params.action, ref: expanded.ref, start: expanded.start, returnedBytes: expanded.returnedBytes, truncated: expanded.truncated },
|
|
284
|
+
};
|
|
285
|
+
} else if (params.action === "context-search") {
|
|
286
|
+
if (!params.ref || !params.query) throw new Error("ues_code context-search requires ref and query");
|
|
287
|
+
result = await searchContext(ctx.cwd, params.ref, params.query, { maxBytes: params.maxBytes || 512000, maxMatches: 12 });
|
|
288
|
+
} else {
|
|
289
|
+
throw new Error("unsupported ues_code action");
|
|
290
|
+
}
|
|
291
|
+
const encoded = JSON.stringify(result, null, 2);
|
|
292
|
+
return {
|
|
293
|
+
content: [{ type: "text", text: encoded.length <= 32000 ? encoded : encoded.slice(0, 32000) + "\n...[bounded by ues_code]" }],
|
|
294
|
+
details: { action: params.action, bounded: encoded.length > 32000 },
|
|
295
|
+
};
|
|
296
|
+
} catch (error) {
|
|
297
|
+
return {
|
|
298
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
299
|
+
details: { action: params.action },
|
|
300
|
+
isError: true,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
pi.registerTool({
|
|
307
|
+
name: "ues_code_edit",
|
|
308
|
+
label: "UES Anchored Edit",
|
|
309
|
+
description:
|
|
310
|
+
"Apply fail-closed hash-anchored edits. A stale or mismatched anchor is rejected; re-read with ues_code instead of fuzzy retrying.",
|
|
311
|
+
parameters: Type.Object({
|
|
312
|
+
file: Type.String({ minLength: 1 }),
|
|
313
|
+
edits: Type.Array(AnchoredEdit, { minItems: 1, maxItems: 50 }),
|
|
314
|
+
dryRun: Type.Optional(Type.Boolean()),
|
|
315
|
+
diagnostics: Type.Optional(Type.Boolean()),
|
|
316
|
+
}),
|
|
317
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
318
|
+
try {
|
|
319
|
+
const edited = await applyAnchoredFileEdits(ctx.cwd, params.file, params.edits, { dryRun: params.dryRun === true });
|
|
320
|
+
const diagnostics = params.diagnostics === true && params.dryRun !== true
|
|
321
|
+
? await diagnoseCode(ctx.cwd, params.file, { timeoutMs: 3000, maxDiagnostics: 40 }).catch(() => null)
|
|
322
|
+
: null;
|
|
323
|
+
const result = {
|
|
324
|
+
file: edited.file,
|
|
325
|
+
applied: edited.applied,
|
|
326
|
+
dryRun: edited.dryRun,
|
|
327
|
+
sourceHash: edited.sourceHash,
|
|
328
|
+
outputHash: edited.outputHash,
|
|
329
|
+
diagnostics: diagnostics ? {
|
|
330
|
+
available: diagnostics.available,
|
|
331
|
+
provider: diagnostics.provider,
|
|
332
|
+
reason: diagnostics.reason,
|
|
333
|
+
count: diagnostics.diagnostics?.length || 0,
|
|
334
|
+
items: (diagnostics.diagnostics || []).slice(0, 40),
|
|
335
|
+
} : null,
|
|
336
|
+
};
|
|
337
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], details: result };
|
|
338
|
+
} catch (error) {
|
|
339
|
+
return {
|
|
340
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
341
|
+
details: { file: params.file },
|
|
342
|
+
isError: true,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
|
|
193
348
|
pi.registerTool({
|
|
194
349
|
name: "ues_evidence_get",
|
|
195
350
|
label: "UES Evidence Get",
|
package/pi/extensions/ues.ts
CHANGED
|
@@ -28,6 +28,10 @@ import { adaptiveContextBudget } from "../../lib/adaptive-context-budget.mjs";
|
|
|
28
28
|
import { clearSkillCompilerCache, compileSkillContext } from "../../lib/skill-compiler.mjs";
|
|
29
29
|
import { clearAffectedTestCache, resolveAffectedTests } from "../../lib/affected-tests.mjs";
|
|
30
30
|
import { findReusableVerification, listReusableVerification, recordVerification } from "../../lib/verification-broker.mjs";
|
|
31
|
+
import { evaluateFastVerificationGate } from "../../lib/fast-verification-gate.mjs";
|
|
32
|
+
import { auditCompletion } from "../../lib/completion-auditor.mjs";
|
|
33
|
+
import { mcpExecutionPolicy } from "../../lib/mcp-tool-policy.mjs";
|
|
34
|
+
import { McpHealthTracker } from "../../lib/mcp-health.mjs";
|
|
31
35
|
import { runtimeWorkspaceFingerprint, runtimeWorkspaceSnapshot } from "../../lib/workspace-fingerprint.mjs";
|
|
32
36
|
import { appendTrajectoryEvent, createTraceID } from "../../lib/trajectory.mjs";
|
|
33
37
|
import {
|
|
@@ -135,6 +139,10 @@ const ACTIVE_CLI_CHILDREN = new Map<number, {
|
|
|
135
139
|
proc: any;
|
|
136
140
|
abort: () => boolean;
|
|
137
141
|
}>();
|
|
142
|
+
const MCP_HEALTH = new McpHealthTracker({
|
|
143
|
+
failureThreshold: 2,
|
|
144
|
+
cooldownMs: configuredDuration("UES_MCP_HEALTH_COOLDOWN_MS", 15_000, 1_000, 5 * 60_000),
|
|
145
|
+
});
|
|
138
146
|
|
|
139
147
|
function abortActiveCliChildren() {
|
|
140
148
|
let aborted = 0;
|
|
@@ -165,7 +173,8 @@ function refreshHostBrowserToolNames(pi: ExtensionAPI) {
|
|
|
165
173
|
typeof (pi as any).getAllTools === "function"
|
|
166
174
|
? (pi as any).getAllTools()
|
|
167
175
|
: [];
|
|
168
|
-
|
|
176
|
+
const healthyTools = tools.filter((tool: any) => MCP_HEALTH.available(String(tool?.name || "")));
|
|
177
|
+
HOST_BROWSER_TOOL_NAMES = selectBrowserMcpToolNames(healthyTools.length ? healthyTools : tools, {
|
|
169
178
|
explicitNames: configuredBrowserToolNames(),
|
|
170
179
|
limit: BROWSER_MCP_TOOL_LIMIT,
|
|
171
180
|
});
|
|
@@ -247,6 +256,8 @@ function getAgentPrompt(agent: AgentName) {
|
|
|
247
256
|
`- If \`ues_cli\` is unavailable, invoke the bundled CLI as \`${fallbackCli} ...\`; do not assume a global \`ocskill\` binary exists.`,
|
|
248
257
|
"- Do not call OpenCode-only dispatch tools such as \`ues.dispatch_task\` or \`ues.dispatch_parallel\`.",
|
|
249
258
|
"- Respect the original role's edit/read-only boundary and return evidence to the parent Pi session.",
|
|
259
|
+
"- Prefer ues_code for bounded semantic/AST search, hash-anchored reads and optional LSP diagnostics. Writer roles may use ues_code_edit only after an anchored read; stale anchors must be re-read rather than fuzzily retried.",
|
|
260
|
+
"- For PDF/DOCX/PPTX/XLSX evidence, ues_code action=document may use optional MarkItDown when installed; do not install it unless that capability is needed.",
|
|
250
261
|
"",
|
|
251
262
|
].join("\n");
|
|
252
263
|
const verdictContract =
|
|
@@ -542,8 +553,12 @@ async function runAgentCli(
|
|
|
542
553
|
];
|
|
543
554
|
if (model) args.push("--model", model);
|
|
544
555
|
if (thinkingLevel) args.push("--thinking", thinkingLevel);
|
|
556
|
+
const codeIntelligenceTools = WRITE_AGENTS.has(agent)
|
|
557
|
+
? ["ues_code", "ues_code_edit"]
|
|
558
|
+
: ["ues_code"];
|
|
545
559
|
const allowedTools = [...new Set([
|
|
546
560
|
...config.tools,
|
|
561
|
+
...codeIntelligenceTools,
|
|
547
562
|
...extraTools,
|
|
548
563
|
...(runtimeOptions.compactToolOutput ? ["ues_evidence_get"] : []),
|
|
549
564
|
])];
|
|
@@ -1296,6 +1311,13 @@ async function runRoutedAgent(
|
|
|
1296
1311
|
? selectBrowserToolsForTask(HOST_BROWSER_TOOL_NAMES, task, role)
|
|
1297
1312
|
: [];
|
|
1298
1313
|
const taskPolicy = classifyEngineeringTask(task);
|
|
1314
|
+
const fastBoundedContext =
|
|
1315
|
+
attempt === 1 &&
|
|
1316
|
+
taskPolicy.executionProfile === "fast" &&
|
|
1317
|
+
taskPolicy.singleFileBounded === true &&
|
|
1318
|
+
taskPolicy.risk === "low" &&
|
|
1319
|
+
["executor", "verifier"].includes(role) &&
|
|
1320
|
+
!browserRequested;
|
|
1299
1321
|
const budgetDecision = adaptiveContextBudget(taskPolicy, role, attempt, {
|
|
1300
1322
|
disabled: !ADAPTIVE_CONTEXT_ENABLED,
|
|
1301
1323
|
});
|
|
@@ -1363,6 +1385,18 @@ async function runRoutedAgent(
|
|
|
1363
1385
|
let reusableVerification: any = null;
|
|
1364
1386
|
let contextCacheHit = false;
|
|
1365
1387
|
try {
|
|
1388
|
+
if (fastBoundedContext) {
|
|
1389
|
+
contextQuality = { schemaVersion: 1, profile: "fast-bounded", bounded: true };
|
|
1390
|
+
enrichedTask = [
|
|
1391
|
+
task,
|
|
1392
|
+
"",
|
|
1393
|
+
"## UES FAST bounded lane",
|
|
1394
|
+
"This is a low-risk single-file task. Read the named target file first and avoid broad repository scans unless direct evidence shows the task is wider than declared.",
|
|
1395
|
+
role === "executor"
|
|
1396
|
+
? "Implement every explicit acceptance branch, then run the narrowest behavioral check available. When the repository has no suitable JS/TS test, prefer a temporary .ues-cache/fast-acceptance.test.mjs probe and run `node --test .ues-cache/fast-acceptance.test.mjs`; cover every enumerated edge/error/idempotency/non-mutation requirement and remove only the temporary probe afterwards."
|
|
1397
|
+
: "Verify every explicit acceptance clause independently. Read the final diff/target file, then run a narrow behavioral check. Compilation or syntax alone is not proof. If any enumerated edge/error/idempotency/non-mutation case lacks fresh executable evidence, return FAIL.",
|
|
1398
|
+
].join("\n");
|
|
1399
|
+
} else {
|
|
1366
1400
|
const cacheKey = cachedContextKey(
|
|
1367
1401
|
cwd,
|
|
1368
1402
|
task,
|
|
@@ -1466,6 +1500,7 @@ async function runRoutedAgent(
|
|
|
1466
1500
|
].filter(Boolean).join("\n")).join("\n")
|
|
1467
1501
|
: "",
|
|
1468
1502
|
].filter(Boolean).join("\n");
|
|
1503
|
+
}
|
|
1469
1504
|
} catch (error) {
|
|
1470
1505
|
contextError = error instanceof Error ? error.message : String(error);
|
|
1471
1506
|
if (recentFailure) {
|
|
@@ -2350,6 +2385,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2350
2385
|
clearAffectedTestCache();
|
|
2351
2386
|
clearRepoGraphRuntimeCache();
|
|
2352
2387
|
clearSemanticIndexRuntimeCache();
|
|
2388
|
+
MCP_HEALTH.clear();
|
|
2353
2389
|
abortActiveCliChildren();
|
|
2354
2390
|
await RPC_POOL.stopAll().catch(() => {});
|
|
2355
2391
|
});
|
|
@@ -2399,16 +2435,40 @@ export default function (pi: ExtensionAPI) {
|
|
|
2399
2435
|
});
|
|
2400
2436
|
|
|
2401
2437
|
pi.on("tool_call", async (event, ctx) => {
|
|
2402
|
-
|
|
2438
|
+
const toolName = String(event.toolName || "");
|
|
2439
|
+
if (toolName !== "bash" && toolName !== "powershell") {
|
|
2440
|
+
const allTools = typeof (pi as any).getAllTools === "function" ? (pi as any).getAllTools() : [];
|
|
2441
|
+
const descriptor = allTools.find((tool: any) => String(tool?.name || "") === toolName);
|
|
2442
|
+
const policy = mcpExecutionPolicy(descriptor || { name: toolName });
|
|
2443
|
+
if (policy.confirmationRequired) {
|
|
2444
|
+
const allowed = await approveRisk(ctx, `MCP/tool call: ${toolName}`, `mcp-destructive:${toolName}`);
|
|
2445
|
+
if (!allowed) return { block: true, reason: `Blocked by UES MCP destructive-hint gate: ${toolName}` };
|
|
2446
|
+
}
|
|
2447
|
+
MCP_HEALTH.begin(String((event as any).toolCallId || ""), toolName, policy);
|
|
2448
|
+
return undefined;
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2403
2451
|
const command = String((event.input as any)?.command || "");
|
|
2404
2452
|
const risk = destructiveShellRisk(command);
|
|
2405
2453
|
if (!risk.risky) return undefined;
|
|
2406
|
-
|
|
2407
2454
|
const allowed = await approveRisk(ctx, command, risk.id || "destructive");
|
|
2408
2455
|
if (!allowed) return { block: true, reason: `Blocked by UES safety gate: ${risk.id}` };
|
|
2409
2456
|
return undefined;
|
|
2410
2457
|
});
|
|
2411
2458
|
|
|
2459
|
+
pi.on("tool_result", async (event) => {
|
|
2460
|
+
const toolName = String((event as any).toolName || "");
|
|
2461
|
+
if (!toolName || toolName === "bash" || toolName === "powershell") return undefined;
|
|
2462
|
+
MCP_HEALTH.finish(
|
|
2463
|
+
String((event as any).toolCallId || ""),
|
|
2464
|
+
{
|
|
2465
|
+
isError: (event as any).isError === true,
|
|
2466
|
+
text: toolResultText(event),
|
|
2467
|
+
},
|
|
2468
|
+
);
|
|
2469
|
+
return undefined;
|
|
2470
|
+
});
|
|
2471
|
+
|
|
2412
2472
|
pi.registerTool({
|
|
2413
2473
|
name: "ues_cli",
|
|
2414
2474
|
label: "UES CLI",
|
|
@@ -2919,9 +2979,19 @@ export default function (pi: ExtensionAPI) {
|
|
|
2919
2979
|
recentFailure = diagnosis.output;
|
|
2920
2980
|
}
|
|
2921
2981
|
|
|
2982
|
+
const fastBoundedLane =
|
|
2983
|
+
policy.executionProfile === "fast" &&
|
|
2984
|
+
policy.singleFileBounded === true &&
|
|
2985
|
+
policy.risk === "low" &&
|
|
2986
|
+
!visualEvidenceNeeded(params.task) &&
|
|
2987
|
+
!browserEvidenceNeeded(params.task, "executor");
|
|
2988
|
+
const fastAttemptStartedAt = Date.now();
|
|
2922
2989
|
const executorTask = [
|
|
2923
2990
|
params.task,
|
|
2924
2991
|
recentFailure ? "\nEvidence from diagnosis/previous failed verification:\n" + cap(recentFailure, 7000) : "",
|
|
2992
|
+
fastBoundedLane
|
|
2993
|
+
? "\nFAST bounded rule: stay on the named file, implement every explicit branch, and produce fresh behavioral evidence before handoff. Prefer one focused project-native test command. If no JS/TS test exists, use a temporary .ues-cache/fast-acceptance.test.mjs and run node --test .ues-cache/fast-acceptance.test.mjs so the controller can independently reuse the successful tool-boundary receipt. Cover every enumerated error, boundary, idempotency and non-mutation case; syntax/build alone is insufficient."
|
|
2994
|
+
: "",
|
|
2925
2995
|
"\nImplement the smallest coherent change. Do not push, publish, deploy, rewrite history, or broaden scope without evidence.",
|
|
2926
2996
|
].filter(Boolean).join("\n");
|
|
2927
2997
|
|
|
@@ -2938,23 +3008,43 @@ export default function (pi: ExtensionAPI) {
|
|
|
2938
3008
|
continue;
|
|
2939
3009
|
}
|
|
2940
3010
|
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
if (
|
|
3011
|
+
let verification: RunResult;
|
|
3012
|
+
let fastGate: any = null;
|
|
3013
|
+
if (fastBoundedLane) {
|
|
3014
|
+
const snapshot = runtimeWorkspaceSnapshot(cwd);
|
|
3015
|
+
const receipts = await listReusableVerification(cwd, {
|
|
3016
|
+
limit: 12,
|
|
3017
|
+
maxAgeMs: 10 * 60_000,
|
|
3018
|
+
previewBytes: 2200,
|
|
3019
|
+
...(snapshot.cacheable === true && snapshot.fingerprint ? { workspaceFingerprint: snapshot.fingerprint } : {}),
|
|
3020
|
+
}).catch(() => ({ results: [] }));
|
|
3021
|
+
fastGate = evaluateFastVerificationGate({ policy, implementation, receipts: receipts?.results || [], attemptStartedAtMs: fastAttemptStartedAt, visualRequired: false });
|
|
3022
|
+
}
|
|
3023
|
+
if (fastGate?.passed === true) {
|
|
3024
|
+
verification = {
|
|
3025
|
+
agent: "ues-deterministic-verifier", task: params.task, cwd, exitCode: 0,
|
|
3026
|
+
output: ["FAST bounded verification reused fresh behavioral evidence captured at the tool boundary.", ...fastGate.behavioralReceipts.map((item: any) => "- " + item.command), "", "UES_VERDICT: PASS"].join("\n"),
|
|
3027
|
+
stderr: "", verdict: "PASS", durationMs: 0, toolCalls: 0, toolNames: [],
|
|
3028
|
+
report: { schemaVersion: 1, valid: true, verdict: "PASS", sections: { "checks-run": fastGate.behavioralReceipts.map((item: any) => item.command).join("\n"), "acceptance-criteria-proven": "Fresh behavioral verification receipt(s) exist at the post-implementation workspace fingerprint.", "completion-evidence": "Deterministic PASS receipt captured after this implementation attempt." } },
|
|
3029
|
+
optimizations: { fastDeterministicVerification: true, behavioralReceiptCount: fastGate.behavioralReceipts.length },
|
|
3030
|
+
};
|
|
3031
|
+
steps.push(verification);
|
|
3032
|
+
onUpdate?.({ content: [{ type: "text", text: "UES FAST verifier: reused " + fastGate.behavioralReceipts.length + " fresh behavioral receipt(s); skipped an extra verifier model turn" }], details: { mode: "execute", policy, fastGate, traceID } });
|
|
3033
|
+
} else {
|
|
3034
|
+
verification = await run(
|
|
3035
|
+
"ues-verifier",
|
|
3036
|
+
[
|
|
3037
|
+
fastBoundedLane ? "FAST bounded verification: independently verify the final target file and every explicit acceptance branch. Run one narrow behavioral check; compilation/syntax alone is insufficient. Return FAIL if any enumerated edge/error/idempotency/non-mutation case lacks fresh executable evidence." : "Independently verify the current working tree against this task:",
|
|
3038
|
+
params.task, "", "Implementation handoff (not proof by itself):", implementation.output,
|
|
3039
|
+
fastGate?.reason ? "\nFAST receipt gate did not short-circuit because: " + fastGate.reason : "",
|
|
3040
|
+
].join("\n"), attempt, recentFailure || undefined,
|
|
3041
|
+
);
|
|
3042
|
+
if (isAbortedRun(verification)) return abortedResponse(verification, "verification");
|
|
3043
|
+
}
|
|
2954
3044
|
const verified = verification.exitCode === 0 && verification.verdict === "PASS";
|
|
2955
|
-
await recordRuntimeOutcome(implementation, params.task, verified, attempt - 1);
|
|
2956
3045
|
if (!verified) {
|
|
2957
3046
|
recentFailure = verification.output;
|
|
3047
|
+
await recordRuntimeOutcome(implementation, params.task, false, attempt - 1);
|
|
2958
3048
|
continue;
|
|
2959
3049
|
}
|
|
2960
3050
|
|
|
@@ -2973,6 +3063,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2973
3063
|
if (isAbortedRun(integrationResult)) return abortedResponse(integrationResult, "integration-verification");
|
|
2974
3064
|
if (integrationResult.exitCode !== 0 || integrationResult.verdict !== "PASS") {
|
|
2975
3065
|
recentFailure = integrationResult.output;
|
|
3066
|
+
await recordRuntimeOutcome(implementation, params.task, false, attempt - 1);
|
|
2976
3067
|
if (attempt < maxAttempts) continue;
|
|
2977
3068
|
return {
|
|
2978
3069
|
content: [{ type: "text", text: `Integration verification did not pass:\n\n${integrationResult.output}` }],
|
|
@@ -3000,6 +3091,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
3000
3091
|
if (isAbortedRun(visualResult)) return abortedResponse(visualResult, "visual-verification");
|
|
3001
3092
|
if (visualResult.exitCode !== 0 || visualResult.verdict !== "PASS") {
|
|
3002
3093
|
recentFailure = visualResult.output;
|
|
3094
|
+
await recordRuntimeOutcome(implementation, params.task, false, attempt - 1);
|
|
3003
3095
|
if (attempt < maxAttempts) continue;
|
|
3004
3096
|
return {
|
|
3005
3097
|
content: [{
|
|
@@ -3012,6 +3104,41 @@ export default function (pi: ExtensionAPI) {
|
|
|
3012
3104
|
}
|
|
3013
3105
|
}
|
|
3014
3106
|
|
|
3107
|
+
const completionSnapshot = runtimeWorkspaceSnapshot(cwd);
|
|
3108
|
+
const completionReceipts = await listReusableVerification(cwd, {
|
|
3109
|
+
limit: 24,
|
|
3110
|
+
maxAgeMs: 10 * 60_000,
|
|
3111
|
+
previewBytes: 1200,
|
|
3112
|
+
...(completionSnapshot.cacheable === true && completionSnapshot.fingerprint
|
|
3113
|
+
? { workspaceFingerprint: completionSnapshot.fingerprint }
|
|
3114
|
+
: {}),
|
|
3115
|
+
}).catch(() => ({ results: [] }));
|
|
3116
|
+
const freshReceipts = (completionReceipts?.results || []).filter((row: any) => {
|
|
3117
|
+
const finished = Date.parse(row?.finishedAt || row?.receipt?.finishedAt || "");
|
|
3118
|
+
return Number.isFinite(finished) && finished >= fastAttemptStartedAt;
|
|
3119
|
+
});
|
|
3120
|
+
const completionAudit = auditCompletion({
|
|
3121
|
+
verification,
|
|
3122
|
+
integration: integrationResult,
|
|
3123
|
+
visual: visualResult,
|
|
3124
|
+
requireIntegration: policy.requireIntegrationVerification === true,
|
|
3125
|
+
requireVisual: visualEvidenceNeeded(params.task),
|
|
3126
|
+
workspaceSnapshot: completionSnapshot,
|
|
3127
|
+
behavioralReceipts: freshReceipts,
|
|
3128
|
+
requireBehavioralReceipt: true,
|
|
3129
|
+
});
|
|
3130
|
+
if (!completionAudit.passed) {
|
|
3131
|
+
recentFailure = "Completion auditor rejected PASS: " + completionAudit.failures.join(", ");
|
|
3132
|
+
await recordRuntimeOutcome(implementation, params.task, false, attempt - 1);
|
|
3133
|
+
if (attempt < maxAttempts) continue;
|
|
3134
|
+
return {
|
|
3135
|
+
content: [{ type: "text", text: recentFailure }],
|
|
3136
|
+
details: { mode: "execute", policy, steps, attempts: attempt, completionAudit, traceID },
|
|
3137
|
+
isError: true,
|
|
3138
|
+
};
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
await recordRuntimeOutcome(implementation, params.task, true, attempt - 1);
|
|
3015
3142
|
const memory = await rememberVerifiedTask(cwd, params.task, verification, integrationResult);
|
|
3016
3143
|
const final = steps.at(-1);
|
|
3017
3144
|
return {
|
|
@@ -3024,7 +3151,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
3024
3151
|
final?.output || verification.output,
|
|
3025
3152
|
].join("\n"),
|
|
3026
3153
|
}],
|
|
3027
|
-
details: { mode: "execute", policy, steps, attempts: attempt, memory, traceID },
|
|
3154
|
+
details: { mode: "execute", policy, steps, attempts: attempt, memory, completionAudit, traceID },
|
|
3028
3155
|
};
|
|
3029
3156
|
}
|
|
3030
3157
|
|
|
@@ -16,6 +16,9 @@ const CONTRACTS = [
|
|
|
16
16
|
'name: "ues_dispatch"',
|
|
17
17
|
"runRoutedAgent",
|
|
18
18
|
"PiRpcWorkerPool",
|
|
19
|
+
"McpHealthTracker",
|
|
20
|
+
"MCP_HEALTH",
|
|
21
|
+
"auditCompletion",
|
|
19
22
|
"CHILD_RUNTIME_EXTENSION",
|
|
20
23
|
"isAbortedRun",
|
|
21
24
|
"abortedResponse",
|
|
@@ -30,6 +33,10 @@ const CONTRACTS = [
|
|
|
30
33
|
'pi.on("tool_call"',
|
|
31
34
|
'pi.on("tool_result"',
|
|
32
35
|
'name: "ues_evidence_get"',
|
|
36
|
+
'name: "ues_code"',
|
|
37
|
+
'name: "ues_code_edit"',
|
|
38
|
+
"applyAnchoredFileEdits",
|
|
39
|
+
"diagnoseCode",
|
|
33
40
|
"recordVerification",
|
|
34
41
|
"canonicalVerificationCommand",
|
|
35
42
|
"destructiveShellRisk",
|
|
@@ -141,6 +148,61 @@ const CONTRACTS = [
|
|
|
141
148
|
],
|
|
142
149
|
},
|
|
143
150
|
|
|
151
|
+
{
|
|
152
|
+
file: "lib/code-intelligence/edit-anchor.mjs",
|
|
153
|
+
minBytes: 2_500,
|
|
154
|
+
startsWith: "import ",
|
|
155
|
+
required: ["anchoredLines", "applyAnchoredEdits", "UES_STALE_ANCHOR"],
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
file: "lib/code-intelligence/index.mjs",
|
|
159
|
+
minBytes: 4_000,
|
|
160
|
+
startsWith: "import ",
|
|
161
|
+
required: ["readAnchoredCode", "applyAnchoredFileEdits", "searchCodeIntelligence", "diagnoseCode"],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
file: "lib/code-intelligence/lsp-provider.mjs",
|
|
165
|
+
minBytes: 5_000,
|
|
166
|
+
startsWith: "import ",
|
|
167
|
+
required: ["diagnoseCode", "lspProviderStatus", "publishDiagnostics"],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
file: "lib/completion-auditor.mjs",
|
|
171
|
+
minBytes: 2_500,
|
|
172
|
+
startsWith: "function text",
|
|
173
|
+
required: ["auditCompletion", "fresh-behavioral-receipt-missing", "missing-report-section"],
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
file: "lib/document-ingestion.mjs",
|
|
177
|
+
minBytes: 3_000,
|
|
178
|
+
startsWith: "import ",
|
|
179
|
+
required: ["ingestDocument", "documentIngestionSupport", "UES_MARKITDOWN_UNAVAILABLE"],
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
file: "lib/reversible-context.mjs",
|
|
183
|
+
minBytes: 2_500,
|
|
184
|
+
startsWith: "import ",
|
|
185
|
+
required: ["compactContext", "expandContext", "searchContext"],
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
file: "lib/mcp-tool-policy.mjs",
|
|
189
|
+
minBytes: 1_000,
|
|
190
|
+
startsWith: "function firstObject",
|
|
191
|
+
required: ["normalizeMcpAnnotations", "mcpExecutionPolicy", 'trust: "hint-only"'],
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
file: "lib/mcp-health.mjs",
|
|
195
|
+
minBytes: 4_000,
|
|
196
|
+
startsWith: "const TRANSIENT_ERROR",
|
|
197
|
+
required: ["McpHealthTracker", "mcpReconnectAdvice", "transient-idempotent-failure", "cooldownUntil"],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
file: "test/v14.3-intelligence.test.mjs",
|
|
201
|
+
minBytes: 5_000,
|
|
202
|
+
startsWith: 'import test from "node:test"',
|
|
203
|
+
required: ["hash anchored edits fail closed", "completion auditor rejects narrative PASS", "verified memory snapshots ignore retrieval/touch noise", "MCP health only recommends reconnect"],
|
|
204
|
+
},
|
|
205
|
+
|
|
144
206
|
{
|
|
145
207
|
file: "lib/affected-tests.mjs",
|
|
146
208
|
minBytes: 7_500,
|