opencode-agent-skill 15.1.0 → 15.1.2
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 +5 -5
- package/docs/V15-MANAGED-RUNTIME.md +18 -0
- package/global-config/agents/verifier.md +6 -2
- package/lib/affected-tests.mjs +28 -7
- package/lib/capability-fabric.mjs +107 -48
- package/lib/code-intelligence/index.mjs +50 -24
- package/lib/code-intelligence/lsp-pool.mjs +831 -0
- package/lib/code-intelligence/lsp-provider.mjs +197 -20
- package/lib/compaction-resume-guard.mjs +76 -4
- package/lib/completion-auditor.mjs +20 -0
- package/lib/context-manifest.mjs +88 -36
- package/lib/decision-policy.mjs +40 -2
- package/lib/evidence-store.mjs +121 -31
- package/lib/executable-probe.mjs +69 -0
- package/lib/execution-contract.mjs +2 -2
- package/lib/hierarchical-context.mjs +31 -3
- package/lib/learning-engine.mjs +164 -65
- package/lib/memory-engine.mjs +177 -95
- package/lib/model-config.mjs +86 -7
- package/lib/performance-fabric.mjs +92 -0
- package/lib/permission-policy.mjs +232 -0
- package/lib/pi-rpc-pool.mjs +220 -24
- package/lib/provider-recovery.mjs +51 -0
- package/lib/repo-graph.mjs +40 -7
- package/lib/repo-inspect.mjs +3 -2
- package/lib/runtime-events.mjs +31 -10
- package/lib/semantic-index.mjs +69 -21
- package/lib/skill-compiler.mjs +84 -18
- package/lib/task-engine.mjs +28 -9
- package/lib/task-policy.mjs +80 -7
- package/lib/trajectory.mjs +25 -1
- package/lib/untrusted-output.mjs +106 -0
- package/lib/workspace-fingerprint.mjs +17 -9
- package/lib/workspace-hygiene.mjs +2 -2
- package/lib/worktree-sandbox.mjs +14 -8
- package/package.json +8 -6
- package/pi/extensions/ues-child-runtime.ts +116 -5
- package/pi/extensions/ues.ts +780 -81
- package/scripts/benchmark-lsp-pool.mjs +128 -0
- package/scripts/check-release-consistency.mjs +16 -4
- package/scripts/check-source-integrity.mjs +118 -6
- package/scripts/run-test-suite.mjs +143 -0
- package/scripts/smoke-package-closure.mjs +4 -0
package/pi/extensions/ues.ts
CHANGED
|
@@ -33,6 +33,7 @@ import { findReusableVerification, listReusableVerification, recordVerification
|
|
|
33
33
|
import { evaluateFastVerificationGate } from "../../lib/fast-verification-gate.mjs";
|
|
34
34
|
import { turboFastPathDecision, turboFastTimeoutBudget } from "../../lib/turbo-fast-path.mjs";
|
|
35
35
|
import { failureDelta, leafTaskPolicy } from "../../lib/leaf-runtime-optimizer.mjs";
|
|
36
|
+
import { classifyProviderFailure, providerRecoveryBackoffMs } from "../../lib/provider-recovery.mjs";
|
|
36
37
|
import { planningRuntimeBudget, shouldSoftSteerArchitect, shouldSoftSteerPlanningRole } from "../../lib/planning-speed-policy.mjs";
|
|
37
38
|
import { sourceFacingPaths, sourceGitPathspecs } from "../../lib/runtime-artifacts.mjs";
|
|
38
39
|
import { createSubagentArtifact, failSubagentArtifact, finalizeSubagentArtifact, listSubagentArtifacts, readSubagentArtifact } from "../../lib/subagent-artifacts.mjs";
|
|
@@ -44,6 +45,8 @@ import { createAdaptiveDeadline } from "../../lib/activity-deadline.mjs";
|
|
|
44
45
|
import { extractValidatedPlan } from "../../lib/plan-salvage.mjs";
|
|
45
46
|
import { auditCompletion } from "../../lib/completion-auditor.mjs";
|
|
46
47
|
import { mcpExecutionPolicy } from "../../lib/mcp-tool-policy.mjs";
|
|
48
|
+
import { PermissionPolicyStore, permissionRecoveryHint, toolPermissionRequest } from "../../lib/permission-policy.mjs";
|
|
49
|
+
import { analyzeUntrustedOutput, renderUntrustedOutputWarning } from "../../lib/untrusted-output.mjs";
|
|
47
50
|
import { McpHealthTracker } from "../../lib/mcp-health.mjs";
|
|
48
51
|
import { captureWorkspaceStateV2, runtimeWorkspaceFingerprint, runtimeWorkspaceSnapshot } from "../../lib/workspace-fingerprint.mjs";
|
|
49
52
|
import { captureWorkspaceHygieneBaseline, postRunFileHygiene, preFinalWorkspaceAudit } from "../../lib/workspace-hygiene.mjs";
|
|
@@ -56,6 +59,17 @@ import {
|
|
|
56
59
|
} from "../../lib/browser-mcp-routing.mjs";
|
|
57
60
|
import { clearRepoGraphRuntimeCache } from "../../lib/repo-graph.mjs";
|
|
58
61
|
import { clearSemanticIndexRuntimeCache } from "../../lib/semantic-index.mjs";
|
|
62
|
+
import {
|
|
63
|
+
diagnoseCode,
|
|
64
|
+
lspOperation,
|
|
65
|
+
lspPoolStatus,
|
|
66
|
+
probeCodeIntelligence,
|
|
67
|
+
readAnchoredCode,
|
|
68
|
+
searchCodeIntelligence,
|
|
69
|
+
shutdownLspPool,
|
|
70
|
+
} from "../../lib/code-intelligence/index.mjs";
|
|
71
|
+
import { ingestDocument } from "../../lib/document-ingestion.mjs";
|
|
72
|
+
import { compactContext, expandContext, searchContext } from "../../lib/reversible-context.mjs";
|
|
59
73
|
import {
|
|
60
74
|
createTaskSandbox,
|
|
61
75
|
integrateTaskSandbox,
|
|
@@ -142,6 +156,12 @@ const MODEL_VISIBLE_OUTPUT_LIMIT = configuredDuration(
|
|
|
142
156
|
16 * 1024,
|
|
143
157
|
256 * 1024,
|
|
144
158
|
);
|
|
159
|
+
const PARENT_CODE_VISIBLE_OUTPUT_LIMIT = configuredDuration(
|
|
160
|
+
"UES_PARENT_CODE_VISIBLE_OUTPUT_LIMIT",
|
|
161
|
+
16 * 1024,
|
|
162
|
+
8 * 1024,
|
|
163
|
+
64 * 1024,
|
|
164
|
+
);
|
|
145
165
|
|
|
146
166
|
function configuredCount(name: string, fallback: number, min: number, max: number) {
|
|
147
167
|
const parsed = Number(process.env[name] || "");
|
|
@@ -161,6 +181,22 @@ const CONTEXT_CACHE_MAX = configuredCount(
|
|
|
161
181
|
4,
|
|
162
182
|
128,
|
|
163
183
|
);
|
|
184
|
+
const PROVIDER_RECOVERY_RETRIES = (() => {
|
|
185
|
+
const parsed = Number(process.env.UES_PROVIDER_RECOVERY_RETRIES ?? "1");
|
|
186
|
+
if (!Number.isFinite(parsed)) return 1;
|
|
187
|
+
return Math.max(0, Math.min(2, Math.trunc(parsed)));
|
|
188
|
+
})();
|
|
189
|
+
const PROVIDER_SESSION_RESUME_RETRIES = (() => {
|
|
190
|
+
const parsed = Number(process.env.UES_PROVIDER_SESSION_RESUME_RETRIES ?? "1");
|
|
191
|
+
if (!Number.isFinite(parsed)) return 1;
|
|
192
|
+
return Math.max(0, Math.min(2, Math.trunc(parsed)));
|
|
193
|
+
})();
|
|
194
|
+
const PROVIDER_RECOVERY_BASE_DELAY_MS = configuredDuration(
|
|
195
|
+
"UES_PROVIDER_RECOVERY_BASE_DELAY_MS",
|
|
196
|
+
250,
|
|
197
|
+
50,
|
|
198
|
+
5_000,
|
|
199
|
+
);
|
|
164
200
|
|
|
165
201
|
function configuredBoolean(name: string, fallback = true) {
|
|
166
202
|
const raw = String(process.env[name] ?? "").trim().toLowerCase();
|
|
@@ -186,6 +222,9 @@ const MCP_HEALTH = new McpHealthTracker({
|
|
|
186
222
|
failureThreshold: 2,
|
|
187
223
|
cooldownMs: configuredDuration("UES_MCP_HEALTH_COOLDOWN_MS", 15_000, 1_000, 5 * 60_000),
|
|
188
224
|
});
|
|
225
|
+
const PERMISSION_POLICY = new PermissionPolicyStore(
|
|
226
|
+
path.join(getUesConfigDir(), ".ues", "permissions.json"),
|
|
227
|
+
);
|
|
189
228
|
|
|
190
229
|
function abortActiveCliChildren() {
|
|
191
230
|
let aborted = 0;
|
|
@@ -275,6 +314,9 @@ type RunResult = {
|
|
|
275
314
|
browserTools?: string[];
|
|
276
315
|
childRuntime?: "rpc" | "cli";
|
|
277
316
|
workerReused?: boolean;
|
|
317
|
+
providerFailure?: string;
|
|
318
|
+
providerRecoveryAttempts?: number;
|
|
319
|
+
providerSessionResumeAttempts?: number;
|
|
278
320
|
subagentArtifact?: any;
|
|
279
321
|
optimizations?: any;
|
|
280
322
|
};
|
|
@@ -663,6 +705,7 @@ async function runAgentCli(
|
|
|
663
705
|
idleTimeoutMs?: number;
|
|
664
706
|
postToolErrorIdleTimeoutMs?: number;
|
|
665
707
|
allowLocalEnvWrite?: boolean;
|
|
708
|
+
reuseRpcSession?: boolean;
|
|
666
709
|
} = {},
|
|
667
710
|
): Promise<RunResult> {
|
|
668
711
|
const config = AGENTS[agent];
|
|
@@ -723,6 +766,7 @@ async function runAgentCli(
|
|
|
723
766
|
UES_CHILD_TOOL_OUTPUT_LIMIT: String(runtimeOptions.toolOutputLimit || 24 * 1024),
|
|
724
767
|
UES_CHILD_VERIFICATION_TIMEOUT_SEC: String(runtimeOptions.verificationTimeoutSec || 300),
|
|
725
768
|
UES_CHILD_ALLOW_LOCAL_ENV_WRITE: runtimeOptions.allowLocalEnvWrite ? "1" : "0",
|
|
769
|
+
UES_CHILD_EXTERNAL_TOOL_NAMES: extraTools.join(","),
|
|
726
770
|
},
|
|
727
771
|
shell: false,
|
|
728
772
|
detached: process.platform !== "win32",
|
|
@@ -1011,11 +1055,17 @@ async function runAgentCli(
|
|
|
1011
1055
|
}
|
|
1012
1056
|
|
|
1013
1057
|
|
|
1058
|
+
const RPC_PROMPT_PATH_CACHE = new Map<AgentName, string>();
|
|
1059
|
+
|
|
1014
1060
|
function rpcPromptPath(agent: AgentName) {
|
|
1061
|
+
const cached = RPC_PROMPT_PATH_CACHE.get(agent);
|
|
1062
|
+
if (cached && fs.existsSync(cached)) return cached;
|
|
1063
|
+
|
|
1015
1064
|
const dir = path.join(os.tmpdir(), "ues-pi-rpc-prompts");
|
|
1016
1065
|
fs.mkdirSync(dir, { recursive: true });
|
|
1017
1066
|
const file = path.join(dir, agent + ".md");
|
|
1018
1067
|
fs.writeFileSync(file, getAgentPrompt(agent), { encoding: "utf8", mode: 0o600 });
|
|
1068
|
+
RPC_PROMPT_PATH_CACHE.set(agent, file);
|
|
1019
1069
|
return file;
|
|
1020
1070
|
}
|
|
1021
1071
|
|
|
@@ -1048,6 +1098,7 @@ async function runAgentRpc(
|
|
|
1048
1098
|
idleTimeoutMs?: number;
|
|
1049
1099
|
postToolErrorIdleTimeoutMs?: number;
|
|
1050
1100
|
allowLocalEnvWrite?: boolean;
|
|
1101
|
+
reuseRpcSession?: boolean;
|
|
1051
1102
|
} = {},
|
|
1052
1103
|
): Promise<RunResult> {
|
|
1053
1104
|
const config = AGENTS[agent];
|
|
@@ -1128,6 +1179,7 @@ async function runAgentRpc(
|
|
|
1128
1179
|
UES_CHILD_TOOL_OUTPUT_LIMIT: String(runtimeOptions.toolOutputLimit || 24 * 1024),
|
|
1129
1180
|
UES_CHILD_VERIFICATION_TIMEOUT_SEC: String(runtimeOptions.verificationTimeoutSec || 300),
|
|
1130
1181
|
UES_CHILD_ALLOW_LOCAL_ENV_WRITE: runtimeOptions.allowLocalEnvWrite ? "1" : "0",
|
|
1182
|
+
UES_CHILD_EXTERNAL_TOOL_NAMES: extraTools.join(","),
|
|
1131
1183
|
},
|
|
1132
1184
|
},
|
|
1133
1185
|
taskInput,
|
|
@@ -1139,6 +1191,7 @@ async function runAgentRpc(
|
|
|
1139
1191
|
activityWindowMs,
|
|
1140
1192
|
idleTimeoutMs,
|
|
1141
1193
|
postToolErrorIdleTimeoutMs,
|
|
1194
|
+
reuseSession: runtimeOptions.reuseRpcSession === true,
|
|
1142
1195
|
onEvent: (event: any) => {
|
|
1143
1196
|
lastActivityAt = Date.now();
|
|
1144
1197
|
if (event.type === "tool_execution_start") {
|
|
@@ -1186,13 +1239,13 @@ async function runAgentRpc(
|
|
|
1186
1239
|
);
|
|
1187
1240
|
|
|
1188
1241
|
const message = rpc.message;
|
|
1189
|
-
const
|
|
1190
|
-
|
|
1242
|
+
const assistantText = extractAssistantText(message);
|
|
1243
|
+
const baseResult: RunResult = {
|
|
1191
1244
|
agent,
|
|
1192
1245
|
task,
|
|
1193
1246
|
cwd,
|
|
1194
|
-
exitCode: 0,
|
|
1195
|
-
output: cap(output, 100 * 1024),
|
|
1247
|
+
exitCode: message?.stopReason === "error" ? 1 : 0,
|
|
1248
|
+
output: cap(assistantText || rpc.stderr || "(no assistant output)", 100 * 1024),
|
|
1196
1249
|
stderr: cap(String(rpc.stderr || ""), 64 * 1024),
|
|
1197
1250
|
model: message?.model || model,
|
|
1198
1251
|
stopReason: message?.stopReason,
|
|
@@ -1204,6 +1257,16 @@ async function runAgentRpc(
|
|
|
1204
1257
|
childRuntime: "rpc",
|
|
1205
1258
|
workerReused: rpc.workerReused === true,
|
|
1206
1259
|
};
|
|
1260
|
+
const providerDecision = classifyProviderFailure(baseResult);
|
|
1261
|
+
if (providerDecision.transient) {
|
|
1262
|
+
return {
|
|
1263
|
+
...baseResult,
|
|
1264
|
+
exitCode: 1,
|
|
1265
|
+
providerFailure: providerDecision.reason || "empty-provider-response",
|
|
1266
|
+
errorMessage: baseResult.errorMessage || providerDecision.message || "Provider returned no usable assistant content",
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
return baseResult;
|
|
1207
1270
|
} catch (error) {
|
|
1208
1271
|
const message = error instanceof Error ? error.message : String(error);
|
|
1209
1272
|
if (detectedHang) {
|
|
@@ -1288,54 +1351,137 @@ async function runAgent(
|
|
|
1288
1351
|
idleTimeoutMs?: number;
|
|
1289
1352
|
postToolErrorIdleTimeoutMs?: number;
|
|
1290
1353
|
allowLocalEnvWrite?: boolean;
|
|
1354
|
+
reuseRpcSession?: boolean;
|
|
1291
1355
|
} = {},
|
|
1292
1356
|
): Promise<RunResult> {
|
|
1293
|
-
|
|
1357
|
+
const runOnce = async (): Promise<RunResult> => {
|
|
1358
|
+
if (CHILD_RUNTIME !== "cli") {
|
|
1359
|
+
try {
|
|
1360
|
+
return await runAgentRpc(
|
|
1361
|
+
agent, task, cwd, model, thinkingLevel, signal, onProgress, extraTools, runtimeOptions,
|
|
1362
|
+
);
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
if (CHILD_RUNTIME === "rpc") throw error;
|
|
1365
|
+
// Auto mode may fall back only when RPC failed before delegated work started.
|
|
1366
|
+
if ((error as any)?.uesRpcPhase && (error as any).uesRpcPhase !== "startup") throw error;
|
|
1367
|
+
try {
|
|
1368
|
+
onProgress?.({
|
|
1369
|
+
agent, elapsedMs: 0, idleMs: 0, toolCalls: 0, model, phase: "running",
|
|
1370
|
+
note: "RPC startup unavailable; falling back to isolated CLI child",
|
|
1371
|
+
});
|
|
1372
|
+
} catch {}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
return runAgentCli(
|
|
1376
|
+
agent, task, cwd, model, thinkingLevel, signal, onProgress, extraTools, runtimeOptions,
|
|
1377
|
+
);
|
|
1378
|
+
};
|
|
1379
|
+
|
|
1380
|
+
let result = await runOnce();
|
|
1381
|
+
let recoveryAttempts = 0;
|
|
1382
|
+
let sessionResumeAttempts = 0;
|
|
1383
|
+
let providerDecision = classifyProviderFailure(result);
|
|
1384
|
+
|
|
1385
|
+
while (
|
|
1386
|
+
providerDecision.transient && providerDecision.safeSessionResume &&
|
|
1387
|
+
result.childRuntime === "rpc" &&
|
|
1388
|
+
sessionResumeAttempts < PROVIDER_SESSION_RESUME_RETRIES && !signal?.aborted
|
|
1389
|
+
) {
|
|
1390
|
+
sessionResumeAttempts += 1;
|
|
1294
1391
|
try {
|
|
1295
|
-
|
|
1392
|
+
onProgress?.({
|
|
1393
|
+
agent, elapsedMs: 0, idleMs: 0, toolCalls: Number(result.toolCalls || 0),
|
|
1394
|
+
model: result.model || model, phase: "running",
|
|
1395
|
+
note: "provider returned no usable content after tool execution; resuming the same RPC session " +
|
|
1396
|
+
sessionResumeAttempts + "/" + PROVIDER_SESSION_RESUME_RETRIES,
|
|
1397
|
+
});
|
|
1398
|
+
} catch {}
|
|
1399
|
+
const delayMs = providerRecoveryBackoffMs(sessionResumeAttempts, {
|
|
1400
|
+
baseMs: PROVIDER_RECOVERY_BASE_DELAY_MS, maxMs: 2_000,
|
|
1401
|
+
});
|
|
1402
|
+
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1403
|
+
|
|
1404
|
+
const priorToolCalls = Number(result.toolCalls || 0);
|
|
1405
|
+
const priorToolNames = Array.isArray(result.toolNames) ? result.toolNames : [];
|
|
1406
|
+
try {
|
|
1407
|
+
const resumed = await runAgentRpc(
|
|
1296
1408
|
agent,
|
|
1297
|
-
|
|
1409
|
+
[
|
|
1410
|
+
"Continue the current delegated task from this existing RPC session after a transient provider failure.",
|
|
1411
|
+
"Do not restart the task and do not repeat tool calls that already completed.",
|
|
1412
|
+
"Use the current conversation, workspace state, and tool evidence as authoritative.",
|
|
1413
|
+
"Continue from the next unfinished step, then return the normal role report/verdict.",
|
|
1414
|
+
].join(" "),
|
|
1298
1415
|
cwd,
|
|
1299
|
-
model,
|
|
1416
|
+
result.model || model,
|
|
1300
1417
|
thinkingLevel,
|
|
1301
1418
|
signal,
|
|
1302
1419
|
onProgress,
|
|
1303
1420
|
extraTools,
|
|
1304
|
-
runtimeOptions,
|
|
1421
|
+
{ ...runtimeOptions, reuseRpcSession: true },
|
|
1305
1422
|
);
|
|
1423
|
+
result = {
|
|
1424
|
+
...resumed,
|
|
1425
|
+
task,
|
|
1426
|
+
toolCalls: priorToolCalls + Number(resumed.toolCalls || 0),
|
|
1427
|
+
toolNames: [...new Set([...priorToolNames, ...(resumed.toolNames || [])])],
|
|
1428
|
+
};
|
|
1429
|
+
providerDecision = classifyProviderFailure(result);
|
|
1306
1430
|
} catch (error) {
|
|
1307
|
-
if (CHILD_RUNTIME === "rpc") throw error;
|
|
1308
|
-
// Auto mode may fall back only when RPC failed before the delegated task
|
|
1309
|
-
// started. In-task failures must not cause a blind second execution.
|
|
1310
|
-
if ((error as any)?.uesRpcPhase && (error as any).uesRpcPhase !== "startup") {
|
|
1311
|
-
throw error;
|
|
1312
|
-
}
|
|
1313
1431
|
try {
|
|
1314
1432
|
onProgress?.({
|
|
1315
|
-
agent,
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
toolCalls: 0,
|
|
1319
|
-
model,
|
|
1320
|
-
phase: "running",
|
|
1321
|
-
note: "RPC startup unavailable; falling back to isolated CLI child",
|
|
1433
|
+
agent, elapsedMs: 0, idleMs: 0, toolCalls: priorToolCalls,
|
|
1434
|
+
model: result.model || model, phase: "running",
|
|
1435
|
+
note: "same-session provider recovery unavailable; preserving prior evidence without replay",
|
|
1322
1436
|
});
|
|
1323
1437
|
} catch {}
|
|
1438
|
+
break;
|
|
1324
1439
|
}
|
|
1325
1440
|
}
|
|
1326
|
-
return runAgentCli(
|
|
1327
|
-
agent,
|
|
1328
|
-
task,
|
|
1329
|
-
cwd,
|
|
1330
|
-
model,
|
|
1331
|
-
thinkingLevel,
|
|
1332
|
-
signal,
|
|
1333
|
-
onProgress,
|
|
1334
|
-
extraTools,
|
|
1335
|
-
runtimeOptions,
|
|
1336
|
-
);
|
|
1337
|
-
}
|
|
1338
1441
|
|
|
1442
|
+
while (
|
|
1443
|
+
providerDecision.transient && providerDecision.safeReplay &&
|
|
1444
|
+
recoveryAttempts < PROVIDER_RECOVERY_RETRIES && !signal?.aborted
|
|
1445
|
+
) {
|
|
1446
|
+
recoveryAttempts += 1;
|
|
1447
|
+
try {
|
|
1448
|
+
onProgress?.({
|
|
1449
|
+
agent, elapsedMs: 0, idleMs: 0, toolCalls: Number(result.toolCalls || 0),
|
|
1450
|
+
model: result.model || model, phase: "running",
|
|
1451
|
+
note: "provider returned no usable content; safe fresh-session retry " +
|
|
1452
|
+
recoveryAttempts + "/" + PROVIDER_RECOVERY_RETRIES,
|
|
1453
|
+
});
|
|
1454
|
+
} catch {}
|
|
1455
|
+
const delayMs = providerRecoveryBackoffMs(recoveryAttempts, {
|
|
1456
|
+
baseMs: PROVIDER_RECOVERY_BASE_DELAY_MS, maxMs: 2_000,
|
|
1457
|
+
});
|
|
1458
|
+
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1459
|
+
result = await runOnce();
|
|
1460
|
+
providerDecision = classifyProviderFailure(result);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
if (providerDecision.transient) {
|
|
1464
|
+
const recoveryNote = providerDecision.safeReplay
|
|
1465
|
+
? "UES provider recovery exhausted after " + recoveryAttempts +
|
|
1466
|
+
" bounded fresh-session retry attempt(s); task remains failed instead of being reported as success."
|
|
1467
|
+
: providerDecision.safeSessionResume
|
|
1468
|
+
? "UES same-session provider recovery exhausted or was unavailable after " + sessionResumeAttempts +
|
|
1469
|
+
" attempt(s). Completed tool side effects were preserved and were not blindly replayed."
|
|
1470
|
+
: "UES provider recovery stopped safely without replaying completed side effects.";
|
|
1471
|
+
result = {
|
|
1472
|
+
...result,
|
|
1473
|
+
exitCode: result.exitCode === 0 ? 1 : result.exitCode,
|
|
1474
|
+
output: [result.output, "", "[UES provider recovery] " + recoveryNote].filter(Boolean).join("\n"),
|
|
1475
|
+
providerFailure: providerDecision.reason || result.providerFailure || "empty-provider-response",
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
return {
|
|
1480
|
+
...result,
|
|
1481
|
+
providerRecoveryAttempts: recoveryAttempts,
|
|
1482
|
+
providerSessionResumeAttempts: sessionResumeAttempts,
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1339
1485
|
|
|
1340
1486
|
function roleForAgent(agent: AgentName) {
|
|
1341
1487
|
return agent.replace(/^ues-/, "");
|
|
@@ -1386,6 +1532,11 @@ function parseStructuredReport(output: string) {
|
|
|
1386
1532
|
};
|
|
1387
1533
|
}
|
|
1388
1534
|
|
|
1535
|
+
function acceptanceEvidenceStatusPresent(run: any) {
|
|
1536
|
+
const value = String(run?.report?.sections?.["acceptance-criteria-proven"] || "");
|
|
1537
|
+
return /(?:^|\n)\s*(?:[-*]\s*)?(?:VERIFIED|INFERRED|UNKNOWN)\s*:/im.test(value);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1389
1540
|
function taskRecord(task: string) {
|
|
1390
1541
|
return {
|
|
1391
1542
|
id: "pi-dispatch",
|
|
@@ -1565,6 +1716,8 @@ async function runRoutedAgent(
|
|
|
1565
1716
|
modelTier: selection.tier,
|
|
1566
1717
|
profile: taskPolicy.executionProfile,
|
|
1567
1718
|
risk: taskPolicy.risk,
|
|
1719
|
+
decisionConfidence: taskPolicy.decision?.confidence ?? null,
|
|
1720
|
+
decisionReason: taskPolicy.decision?.reason ?? null,
|
|
1568
1721
|
browserRequested,
|
|
1569
1722
|
}).catch(() => {});
|
|
1570
1723
|
}
|
|
@@ -1664,39 +1817,39 @@ async function runRoutedAgent(
|
|
|
1664
1817
|
}
|
|
1665
1818
|
}
|
|
1666
1819
|
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1820
|
+
const [microSkillResult, affectedTestResult, reusableVerificationResult] = await Promise.all([
|
|
1821
|
+
MICRO_SKILLS_ENABLED
|
|
1822
|
+
? compileSkillContext(taskPolicy, role, {
|
|
1823
|
+
maxSkills: taskPolicy.maxSkills,
|
|
1824
|
+
totalChars: taskPolicy.executionProfile === "fast" ? 1800 : 3200,
|
|
1825
|
+
taskText: task,
|
|
1826
|
+
}).catch(() => null)
|
|
1827
|
+
: Promise.resolve(null),
|
|
1675
1828
|
AFFECTED_TEST_HINTS_ENABLED &&
|
|
1676
1829
|
["executor", "debugger", "verifier", "integration-verifier"].includes(role)
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
if (
|
|
1830
|
+
? resolveAffectedTests(cwd, {
|
|
1831
|
+
limit: 10,
|
|
1832
|
+
changedFiles: workspaceState.changedFiles || [],
|
|
1833
|
+
...(workspaceState.cacheable === true && workspaceFingerprint !== "unknown"
|
|
1834
|
+
? { workspaceFingerprint }
|
|
1835
|
+
: {}),
|
|
1836
|
+
}).catch(() => null)
|
|
1837
|
+
: Promise.resolve(null),
|
|
1688
1838
|
["verifier", "integration-verifier"].includes(role) &&
|
|
1689
1839
|
!["high", "critical"].includes(String(taskPolicy.risk || "").toLowerCase())
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1840
|
+
? listReusableVerification(cwd, {
|
|
1841
|
+
limit: 8,
|
|
1842
|
+
maxAgeMs: 30 * 60_000,
|
|
1843
|
+
previewBytes: 2200,
|
|
1844
|
+
...(workspaceState.cacheable === true && workspaceFingerprint !== "unknown"
|
|
1845
|
+
? { workspaceFingerprint }
|
|
1846
|
+
: {}),
|
|
1847
|
+
}).catch(() => null)
|
|
1848
|
+
: Promise.resolve(null),
|
|
1849
|
+
]);
|
|
1850
|
+
microSkills = microSkillResult;
|
|
1851
|
+
affectedTests = affectedTestResult;
|
|
1852
|
+
reusableVerification = reusableVerificationResult;
|
|
1700
1853
|
|
|
1701
1854
|
contextQuality = pack.contextQuality;
|
|
1702
1855
|
contextPerformance = pack.performance || null;
|
|
@@ -2926,8 +3079,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
2926
3079
|
const AUTO_ADMISSION_ENABLED = !["0", "false", "off"].includes(
|
|
2927
3080
|
String(process.env.UES_AUTO_ADMIT || "1").trim().toLowerCase(),
|
|
2928
3081
|
);
|
|
2929
|
-
const UES_PARENT_TOOL_NAMES = new Set(["ues_cli", "ues_execute", "ues_service", "ues_dispatch"]);
|
|
3082
|
+
const UES_PARENT_TOOL_NAMES = new Set(["ues_cli", "ues_execute", "ues_service", "ues_session", "ues_dispatch"]);
|
|
3083
|
+
const ALWAYS_ON_PARENT_TOOLS = new Set(["ues_code"]);
|
|
2930
3084
|
let normalActiveTools: string[] | null = null;
|
|
3085
|
+
let parentRunToolCalls = 0;
|
|
3086
|
+
let parentRunLastAssistant: any = null;
|
|
3087
|
+
let parentProviderRecoveryConsecutive = 0;
|
|
3088
|
+
let parentProviderRecoveryTotal = 0;
|
|
3089
|
+
let parentProviderRecoveryPending = false;
|
|
3090
|
+
const PARENT_PROVIDER_RECOVERY_MAX_CONSECUTIVE = 1;
|
|
3091
|
+
const PARENT_PROVIDER_RECOVERY_MAX_TOTAL = 3;
|
|
2931
3092
|
|
|
2932
3093
|
const currentNonUesTools = () =>
|
|
2933
3094
|
pi.getActiveTools().filter((name) => !UES_PARENT_TOOL_NAMES.has(String(name)));
|
|
@@ -2986,7 +3147,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2986
3147
|
content,
|
|
2987
3148
|
display: false,
|
|
2988
3149
|
details: {
|
|
2989
|
-
schemaVersion: 1,
|
|
3150
|
+
schemaVersion: packet.schemaVersion || 1,
|
|
2990
3151
|
reason: event.reason,
|
|
2991
3152
|
willRetry: event.willRetry,
|
|
2992
3153
|
workspaceCount: packet.workspaceCount,
|
|
@@ -3008,6 +3169,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
3008
3169
|
MCP_HEALTH.clear();
|
|
3009
3170
|
abortActiveCliChildren();
|
|
3010
3171
|
await stopAllServices().catch(() => []);
|
|
3172
|
+
await shutdownLspPool().catch(() => ({ stopped: 0, remaining: 0 }));
|
|
3011
3173
|
await RPC_POOL.stopAll().catch(() => {});
|
|
3012
3174
|
for (const dir of [...ACTIVE_TASK_SANDBOXES.keys()]) {
|
|
3013
3175
|
const ownerRoot = await taskSandboxOwnerRoot(dir).catch(() => null);
|
|
@@ -3113,13 +3275,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
3113
3275
|
return { action: "continue" };
|
|
3114
3276
|
}
|
|
3115
3277
|
|
|
3116
|
-
const
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3278
|
+
const streamingBehavior = String(event.streamingBehavior || "");
|
|
3279
|
+
const forwarded = streamingBehavior === "followUp"
|
|
3280
|
+
? await RPC_POOL.followUpActive(text).catch(() => ({
|
|
3281
|
+
accepted: false,
|
|
3282
|
+
reason: "follow-up-failed",
|
|
3283
|
+
active: 0,
|
|
3284
|
+
}))
|
|
3285
|
+
: await RPC_POOL.steerActive(text).catch(() => ({
|
|
3286
|
+
accepted: false,
|
|
3287
|
+
reason: "steer-failed",
|
|
3288
|
+
active: 0,
|
|
3289
|
+
}));
|
|
3290
|
+
if (forwarded.accepted) {
|
|
3291
|
+
try {
|
|
3292
|
+
ctx.ui.notify(
|
|
3293
|
+
streamingBehavior === "followUp"
|
|
3294
|
+
? "UES: follow-up queued for the active child"
|
|
3295
|
+
: "UES: steering message forwarded to the active child",
|
|
3296
|
+
"info",
|
|
3297
|
+
);
|
|
3298
|
+
} catch {}
|
|
3123
3299
|
return { action: "handled" };
|
|
3124
3300
|
}
|
|
3125
3301
|
|
|
@@ -3129,19 +3305,109 @@ export default function (pi: ExtensionAPI) {
|
|
|
3129
3305
|
});
|
|
3130
3306
|
|
|
3131
3307
|
pi.on("before_agent_start", async () => {
|
|
3308
|
+
// Pi may start another provider request inside the same parent run when
|
|
3309
|
+
// agent_before_settle asks to continue. Preserve recovery accounting for
|
|
3310
|
+
// that continuation, but reset it for a genuinely new parent run.
|
|
3311
|
+
if (parentProviderRecoveryPending) {
|
|
3312
|
+
parentProviderRecoveryPending = false;
|
|
3313
|
+
parentRunLastAssistant = null;
|
|
3314
|
+
} else {
|
|
3315
|
+
parentRunToolCalls = 0;
|
|
3316
|
+
parentRunLastAssistant = null;
|
|
3317
|
+
parentProviderRecoveryConsecutive = 0;
|
|
3318
|
+
parentProviderRecoveryTotal = 0;
|
|
3319
|
+
}
|
|
3132
3320
|
if (uesModeActive()) activateParentUesTools();
|
|
3133
3321
|
else deactivateParentUesTools();
|
|
3134
3322
|
});
|
|
3135
3323
|
|
|
3324
|
+
pi.on("message_end", async (event) => {
|
|
3325
|
+
if ((event as any)?.message?.role !== "assistant") return;
|
|
3326
|
+
parentRunLastAssistant = (event as any).message;
|
|
3327
|
+
|
|
3328
|
+
// A substantive assistant response proves the previous empty-response
|
|
3329
|
+
// incident recovered. Reset only the consecutive incident budget; keep the
|
|
3330
|
+
// total run budget bounded so a flaky provider cannot loop forever.
|
|
3331
|
+
const text = extractAssistantText(parentRunLastAssistant).trim();
|
|
3332
|
+
if (text && parentRunLastAssistant?.stopReason !== "error") {
|
|
3333
|
+
parentProviderRecoveryConsecutive = 0;
|
|
3334
|
+
parentProviderRecoveryPending = false;
|
|
3335
|
+
}
|
|
3336
|
+
});
|
|
3337
|
+
|
|
3338
|
+
pi.on("agent_before_settle", async (event) => {
|
|
3339
|
+
if (
|
|
3340
|
+
uesModeActive() ||
|
|
3341
|
+
parentProviderRecoveryConsecutive >= PARENT_PROVIDER_RECOVERY_MAX_CONSECUTIVE ||
|
|
3342
|
+
parentProviderRecoveryTotal >= PARENT_PROVIDER_RECOVERY_MAX_TOTAL
|
|
3343
|
+
) {
|
|
3344
|
+
return undefined;
|
|
3345
|
+
}
|
|
3346
|
+
|
|
3347
|
+
const assistantText = extractAssistantText(parentRunLastAssistant);
|
|
3348
|
+
const decision = classifyProviderFailure({
|
|
3349
|
+
output: assistantText || "(no assistant output)",
|
|
3350
|
+
errorMessage: parentRunLastAssistant?.errorMessage,
|
|
3351
|
+
stopReason: parentRunLastAssistant?.stopReason,
|
|
3352
|
+
toolCalls: parentRunToolCalls,
|
|
3353
|
+
noAssistantMessage: !parentRunLastAssistant,
|
|
3354
|
+
});
|
|
3355
|
+
if (!decision.transient) return undefined;
|
|
3356
|
+
|
|
3357
|
+
parentProviderRecoveryConsecutive += 1;
|
|
3358
|
+
parentProviderRecoveryTotal += 1;
|
|
3359
|
+
parentProviderRecoveryPending = true;
|
|
3360
|
+
const afterTools = parentRunToolCalls > 0;
|
|
3361
|
+
const recoveryMessage = afterTools
|
|
3362
|
+
? [
|
|
3363
|
+
"UES parent provider recovery: the previous provider response was empty after completed tool calls.",
|
|
3364
|
+
"Continue from the current conversation and existing tool results.",
|
|
3365
|
+
"Do not restart the task and do not repeat tool calls that already completed unless fresh verification is strictly required.",
|
|
3366
|
+
"Resume from the next unfinished step and finish the requested work/report.",
|
|
3367
|
+
].join(" ")
|
|
3368
|
+
: [
|
|
3369
|
+
"UES parent provider recovery: the previous provider response was empty before any tool side effect.",
|
|
3370
|
+
"Retry the current request once using the existing conversation context and return a complete response.",
|
|
3371
|
+
].join(" ");
|
|
3372
|
+
|
|
3373
|
+
return {
|
|
3374
|
+
entries: [
|
|
3375
|
+
...(event.entries || []),
|
|
3376
|
+
{
|
|
3377
|
+
type: "custom_message",
|
|
3378
|
+
customType: "ues-parent-provider-recovery",
|
|
3379
|
+
content: recoveryMessage,
|
|
3380
|
+
display: false,
|
|
3381
|
+
details: {
|
|
3382
|
+
schemaVersion: 2,
|
|
3383
|
+
incidentAttempt: parentProviderRecoveryConsecutive,
|
|
3384
|
+
maxIncidentAttempts: PARENT_PROVIDER_RECOVERY_MAX_CONSECUTIVE,
|
|
3385
|
+
totalAttempts: parentProviderRecoveryTotal,
|
|
3386
|
+
maxTotalAttempts: PARENT_PROVIDER_RECOVERY_MAX_TOTAL,
|
|
3387
|
+
reason: decision.reason,
|
|
3388
|
+
toolCalls: parentRunToolCalls,
|
|
3389
|
+
safeReplay: decision.safeReplay,
|
|
3390
|
+
safeSessionResume: decision.safeSessionResume,
|
|
3391
|
+
},
|
|
3392
|
+
},
|
|
3393
|
+
],
|
|
3394
|
+
continue: true,
|
|
3395
|
+
};
|
|
3396
|
+
});
|
|
3397
|
+
|
|
3136
3398
|
pi.on("agent_end", async () => {
|
|
3137
3399
|
promptUesActive = false;
|
|
3400
|
+
parentProviderRecoveryPending = false;
|
|
3401
|
+
parentProviderRecoveryConsecutive = 0;
|
|
3402
|
+
parentProviderRecoveryTotal = 0;
|
|
3138
3403
|
deactivateParentUesTools();
|
|
3139
3404
|
});
|
|
3140
3405
|
|
|
3141
3406
|
pi.on("tool_call", async (event, ctx) => {
|
|
3142
3407
|
const toolName = String(event.toolName || "");
|
|
3408
|
+
if (!uesModeActive()) parentRunToolCalls += 1;
|
|
3143
3409
|
if (!uesModeActive()) {
|
|
3144
|
-
if (toolName.startsWith("ues_")) {
|
|
3410
|
+
if (toolName.startsWith("ues_") && !ALWAYS_ON_PARENT_TOOLS.has(toolName)) {
|
|
3145
3411
|
return {
|
|
3146
3412
|
block: true,
|
|
3147
3413
|
reason: "UES parent tools are hidden outside admitted UES runs. Submit a normal engineering task or start an explicit /ues-* command.",
|
|
@@ -3149,11 +3415,48 @@ export default function (pi: ExtensionAPI) {
|
|
|
3149
3415
|
}
|
|
3150
3416
|
return undefined;
|
|
3151
3417
|
}
|
|
3418
|
+
const permissionRequest = toolPermissionRequest(toolName, (event as any).input || {});
|
|
3419
|
+
const configuredPermission: any = await PERMISSION_POLICY.evaluate(permissionRequest, {
|
|
3420
|
+
agent: "ues-parent",
|
|
3421
|
+
}).catch((error) => ({
|
|
3422
|
+
configured: true,
|
|
3423
|
+
decision: null,
|
|
3424
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3425
|
+
}));
|
|
3426
|
+
if (configuredPermission.error) {
|
|
3427
|
+
return {
|
|
3428
|
+
block: true,
|
|
3429
|
+
reason: "UES permission policy is invalid: " + configuredPermission.error,
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
const permissionEffect = configuredPermission?.decision?.effect;
|
|
3433
|
+
let permissionApproved = false;
|
|
3434
|
+
if (permissionEffect === "deny") {
|
|
3435
|
+
return {
|
|
3436
|
+
block: true,
|
|
3437
|
+
reason: permissionRecoveryHint(permissionRequest, configuredPermission.decision, { effect: "deny" }),
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
if (permissionEffect === "ask") {
|
|
3441
|
+
const allowed = await approveRisk(
|
|
3442
|
+
ctx,
|
|
3443
|
+
permissionRequest.resources.join("\n"),
|
|
3444
|
+
"permission:" + permissionRequest.action,
|
|
3445
|
+
);
|
|
3446
|
+
if (!allowed) {
|
|
3447
|
+
return {
|
|
3448
|
+
block: true,
|
|
3449
|
+
reason: permissionRecoveryHint(permissionRequest, configuredPermission.decision, { effect: "ask" }),
|
|
3450
|
+
};
|
|
3451
|
+
}
|
|
3452
|
+
permissionApproved = true;
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3152
3455
|
if (toolName !== "bash" && toolName !== "powershell") {
|
|
3153
3456
|
const allTools = typeof (pi as any).getAllTools === "function" ? (pi as any).getAllTools() : [];
|
|
3154
3457
|
const descriptor = allTools.find((tool: any) => String(tool?.name || "") === toolName);
|
|
3155
3458
|
const policy = mcpExecutionPolicy(descriptor || { name: toolName });
|
|
3156
|
-
if (policy.confirmationRequired) {
|
|
3459
|
+
if (policy.confirmationRequired && !permissionApproved) {
|
|
3157
3460
|
const allowed = await approveRisk(ctx, `MCP/tool call: ${toolName}`, `mcp-destructive:${toolName}`);
|
|
3158
3461
|
if (!allowed) return { block: true, reason: `Blocked by UES MCP destructive-hint gate: ${toolName}` };
|
|
3159
3462
|
}
|
|
@@ -3172,8 +3475,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
3172
3475
|
}
|
|
3173
3476
|
const risk = destructiveShellRisk(command);
|
|
3174
3477
|
if (!risk.risky) return undefined;
|
|
3175
|
-
|
|
3176
|
-
|
|
3478
|
+
if (!permissionApproved) {
|
|
3479
|
+
const allowed = await approveRisk(ctx, command, risk.id || "destructive");
|
|
3480
|
+
if (!allowed) return { block: true, reason: `Blocked by UES safety gate: ${risk.id}` };
|
|
3481
|
+
}
|
|
3177
3482
|
return undefined;
|
|
3178
3483
|
});
|
|
3179
3484
|
|
|
@@ -3181,14 +3486,301 @@ export default function (pi: ExtensionAPI) {
|
|
|
3181
3486
|
if (!uesModeActive()) return undefined;
|
|
3182
3487
|
const toolName = String((event as any).toolName || "");
|
|
3183
3488
|
if (!toolName || toolName === "bash" || toolName === "powershell") return undefined;
|
|
3489
|
+
const resultText = toolResultText(event);
|
|
3490
|
+
const allTools = typeof (pi as any).getAllTools === "function" ? (pi as any).getAllTools() : [];
|
|
3491
|
+
const descriptor = allTools.find((tool: any) => String(tool?.name || "") === toolName);
|
|
3492
|
+
const policy = mcpExecutionPolicy(descriptor || { name: toolName });
|
|
3184
3493
|
MCP_HEALTH.finish(
|
|
3185
3494
|
String((event as any).toolCallId || ""),
|
|
3186
3495
|
{
|
|
3187
3496
|
isError: (event as any).isError === true,
|
|
3188
|
-
text:
|
|
3497
|
+
text: resultText,
|
|
3189
3498
|
},
|
|
3190
3499
|
);
|
|
3191
|
-
|
|
3500
|
+
|
|
3501
|
+
const externalBoundary =
|
|
3502
|
+
policy.externalEvidenceBoundary === true ||
|
|
3503
|
+
HOST_BROWSER_TOOL_NAMES.includes(toolName);
|
|
3504
|
+
if (!externalBoundary || !resultText) return undefined;
|
|
3505
|
+
|
|
3506
|
+
const analysis = analyzeUntrustedOutput(resultText, { source: toolName });
|
|
3507
|
+
if (!analysis.flagged) return undefined;
|
|
3508
|
+
const originalContent = Array.isArray((event as any).content)
|
|
3509
|
+
? (event as any).content
|
|
3510
|
+
: [{ type: "text", text: resultText }];
|
|
3511
|
+
return {
|
|
3512
|
+
content: [
|
|
3513
|
+
{ type: "text", text: renderUntrustedOutputWarning(analysis, { source: toolName }) },
|
|
3514
|
+
...originalContent,
|
|
3515
|
+
],
|
|
3516
|
+
details: {
|
|
3517
|
+
...((event as any).details && typeof (event as any).details === "object" ? (event as any).details : {}),
|
|
3518
|
+
uesUntrustedOutputBoundary: analysis,
|
|
3519
|
+
},
|
|
3520
|
+
isError: (event as any).isError === true,
|
|
3521
|
+
usage: (event as any).usage,
|
|
3522
|
+
};
|
|
3523
|
+
});
|
|
3524
|
+
|
|
3525
|
+
// Always-on, read-only intelligence for normal Pi conversations.
|
|
3526
|
+
// Keep this outside UES_PARENT_TOOL_NAMES so session_start does not hide it.
|
|
3527
|
+
pi.registerTool({
|
|
3528
|
+
name: "ues_code",
|
|
3529
|
+
label: "UES Code Intelligence Lite",
|
|
3530
|
+
description:
|
|
3531
|
+
"Always-on read-only UES code intelligence for normal Pi chats. Provides bounded semantic/AST search, anchored reads, persistent LSP navigation/diagnostics, document ingestion, and reversible context access without starting the UES controller or a specialist child.",
|
|
3532
|
+
parameters: Type.Object({
|
|
3533
|
+
action: Type.Union([
|
|
3534
|
+
Type.Literal("status"),
|
|
3535
|
+
Type.Literal("search"),
|
|
3536
|
+
Type.Literal("read"),
|
|
3537
|
+
Type.Literal("diagnostics"),
|
|
3538
|
+
Type.Literal("definition"),
|
|
3539
|
+
Type.Literal("references"),
|
|
3540
|
+
Type.Literal("symbols"),
|
|
3541
|
+
Type.Literal("hover"),
|
|
3542
|
+
Type.Literal("rename-preview"),
|
|
3543
|
+
Type.Literal("incoming-calls"),
|
|
3544
|
+
Type.Literal("outgoing-calls"),
|
|
3545
|
+
Type.Literal("document"),
|
|
3546
|
+
Type.Literal("context-expand"),
|
|
3547
|
+
Type.Literal("context-search"),
|
|
3548
|
+
]),
|
|
3549
|
+
file: Type.Optional(Type.String()),
|
|
3550
|
+
query: Type.Optional(Type.String()),
|
|
3551
|
+
structuralPattern: Type.Optional(Type.String()),
|
|
3552
|
+
language: Type.Optional(Type.String()),
|
|
3553
|
+
startLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
3554
|
+
endLine: Type.Optional(Type.Number({ minimum: 1 })),
|
|
3555
|
+
line: Type.Optional(Type.Number({
|
|
3556
|
+
minimum: 1,
|
|
3557
|
+
description: "1-based source line. UES converts it to the LSP protocol's 0-based line internally.",
|
|
3558
|
+
})),
|
|
3559
|
+
character: Type.Optional(Type.Number({
|
|
3560
|
+
minimum: 1,
|
|
3561
|
+
description: "1-based source character/column. UES converts it to the LSP protocol's 0-based character internally.",
|
|
3562
|
+
})),
|
|
3563
|
+
newName: Type.Optional(Type.String({ minLength: 1, maxLength: 512 })),
|
|
3564
|
+
includeDeclaration: Type.Optional(Type.Boolean()),
|
|
3565
|
+
includeSessions: Type.Optional(Type.Boolean()),
|
|
3566
|
+
ref: Type.Optional(Type.String()),
|
|
3567
|
+
maxBytes: Type.Optional(Type.Number({ minimum: 1, maximum: 128000 })),
|
|
3568
|
+
}),
|
|
3569
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
3570
|
+
try {
|
|
3571
|
+
let result: any;
|
|
3572
|
+
if (params.action === "status") {
|
|
3573
|
+
result = probeCodeIntelligence(params.file || "");
|
|
3574
|
+
result = {
|
|
3575
|
+
...result,
|
|
3576
|
+
mode: "parent-lite",
|
|
3577
|
+
controllerStarted: false,
|
|
3578
|
+
childSpawned: false,
|
|
3579
|
+
lsp: {
|
|
3580
|
+
...result.lsp,
|
|
3581
|
+
persistentPool: {
|
|
3582
|
+
...lspPoolStatus({ includeSessions: params.includeSessions === true, persistent: true }),
|
|
3583
|
+
policy: { enabled: true, source: "parent-lite" },
|
|
3584
|
+
},
|
|
3585
|
+
},
|
|
3586
|
+
};
|
|
3587
|
+
} else if (params.action === "search") {
|
|
3588
|
+
if (!params.query) throw new Error("ues_code search requires query");
|
|
3589
|
+
result = await searchCodeIntelligence(ctx.cwd, params.query, {
|
|
3590
|
+
structuralPattern: params.structuralPattern,
|
|
3591
|
+
language: params.language,
|
|
3592
|
+
file: params.file,
|
|
3593
|
+
maxResults: 12,
|
|
3594
|
+
});
|
|
3595
|
+
result.mode = "parent-lite";
|
|
3596
|
+
} else if (params.action === "read") {
|
|
3597
|
+
if (!params.file) throw new Error("ues_code read requires file");
|
|
3598
|
+
const startLine = Math.max(1, Math.trunc(Number(params.startLine || 1)));
|
|
3599
|
+
const endLine = Math.max(startLine, Math.min(startLine + 399, Math.trunc(Number(params.endLine || startLine + 199))));
|
|
3600
|
+
const read = await readAnchoredCode(ctx.cwd, params.file, { startLine, endLine });
|
|
3601
|
+
const rawRead = [
|
|
3602
|
+
`file: ${read.file}; lines: ${read.startLine}-${read.endLine}/${read.lineCount}; sourceHash: ${read.sourceHash}`,
|
|
3603
|
+
"",
|
|
3604
|
+
read.text,
|
|
3605
|
+
].join("\n");
|
|
3606
|
+
const originalChars = rawRead.length;
|
|
3607
|
+
const bounded = originalChars > PARENT_CODE_VISIBLE_OUTPUT_LIMIT;
|
|
3608
|
+
const exactRead = [
|
|
3609
|
+
`file: ${read.file}; lines: ${read.startLine}-${read.endLine}/${read.lineCount}; sourceHash: ${read.sourceHash}; originalChars: ${originalChars}; bounded: ${bounded}`,
|
|
3610
|
+
"",
|
|
3611
|
+
read.text,
|
|
3612
|
+
].join("\n");
|
|
3613
|
+
let contextRef: string | null = null;
|
|
3614
|
+
let visibleRead = exactRead;
|
|
3615
|
+
if (bounded) {
|
|
3616
|
+
const preserved = await compactContext(ctx.cwd, exactRead, {
|
|
3617
|
+
kind: "ues-code-read",
|
|
3618
|
+
source: `ues_code:read:${read.file}`,
|
|
3619
|
+
summary: `Exact anchored parent-lite read for ${read.file}`,
|
|
3620
|
+
}).catch(() => null);
|
|
3621
|
+
contextRef = preserved?.ref || null;
|
|
3622
|
+
const previewChars = Math.max(2_000, PARENT_CODE_VISIBLE_OUTPUT_LIMIT - 1_200);
|
|
3623
|
+
visibleRead = exactRead.slice(0, previewChars) +
|
|
3624
|
+
`\n...[anchored read bounded; exact content preserved${contextRef ? `; contextRef=${contextRef}` : ""}]`;
|
|
3625
|
+
}
|
|
3626
|
+
return {
|
|
3627
|
+
content: [{ type: "text", text: visibleRead }],
|
|
3628
|
+
details: {
|
|
3629
|
+
action: params.action,
|
|
3630
|
+
mode: "parent-lite",
|
|
3631
|
+
controllerStarted: false,
|
|
3632
|
+
childSpawned: false,
|
|
3633
|
+
file: read.file,
|
|
3634
|
+
sourceHash: read.sourceHash,
|
|
3635
|
+
startLine: read.startLine,
|
|
3636
|
+
endLine: read.endLine,
|
|
3637
|
+
bounded,
|
|
3638
|
+
originalChars,
|
|
3639
|
+
contextRef,
|
|
3640
|
+
},
|
|
3641
|
+
};
|
|
3642
|
+
} else if (params.action === "diagnostics") {
|
|
3643
|
+
if (!params.file) throw new Error("ues_code diagnostics requires file");
|
|
3644
|
+
result = await diagnoseCode(ctx.cwd, params.file, {
|
|
3645
|
+
timeoutMs: 5000,
|
|
3646
|
+
maxResults: 80,
|
|
3647
|
+
persistent: true,
|
|
3648
|
+
});
|
|
3649
|
+
} else if (["definition", "references", "symbols", "hover", "rename-preview", "incoming-calls", "outgoing-calls"].includes(params.action)) {
|
|
3650
|
+
if (!params.file) throw new Error(`ues_code ${params.action} requires file`);
|
|
3651
|
+
if (params.action === "rename-preview" && !params.newName) throw new Error("ues_code rename-preview requires newName");
|
|
3652
|
+
result = await lspOperation(ctx.cwd, params.file, params.action, {
|
|
3653
|
+
line: params.line || 1,
|
|
3654
|
+
character: params.character || 1,
|
|
3655
|
+
newName: params.newName,
|
|
3656
|
+
includeDeclaration: params.includeDeclaration,
|
|
3657
|
+
timeoutMs: 7000,
|
|
3658
|
+
maxResults: 120,
|
|
3659
|
+
persistent: true,
|
|
3660
|
+
});
|
|
3661
|
+
} else if (params.action === "document") {
|
|
3662
|
+
if (!params.file) throw new Error("ues_code document requires file");
|
|
3663
|
+
const document = await ingestDocument(ctx.cwd, params.file, {
|
|
3664
|
+
maxBytes: Math.min(Number(params.maxBytes || 4 * 1024 * 1024), 4 * 1024 * 1024),
|
|
3665
|
+
});
|
|
3666
|
+
const block = await compactContext(ctx.cwd, document.markdown, {
|
|
3667
|
+
kind: "document-ingestion",
|
|
3668
|
+
source: document.file,
|
|
3669
|
+
summary: `Normalized document from ${document.provider}`,
|
|
3670
|
+
});
|
|
3671
|
+
result = {
|
|
3672
|
+
provider: document.provider,
|
|
3673
|
+
file: document.file,
|
|
3674
|
+
bytes: document.bytes,
|
|
3675
|
+
optionalDependency: document.optionalDependency,
|
|
3676
|
+
contextRef: block.ref,
|
|
3677
|
+
originalChars: block.originalChars,
|
|
3678
|
+
summary: block.levels.T1,
|
|
3679
|
+
};
|
|
3680
|
+
} else if (params.action === "context-expand") {
|
|
3681
|
+
if (!params.ref) throw new Error("ues_code context-expand requires ref");
|
|
3682
|
+
const expanded = await expandContext(ctx.cwd, params.ref, { maxBytes: params.maxBytes || 16000 });
|
|
3683
|
+
return {
|
|
3684
|
+
content: [{ type: "text", text: expanded.content }],
|
|
3685
|
+
details: {
|
|
3686
|
+
action: params.action,
|
|
3687
|
+
mode: "parent-lite",
|
|
3688
|
+
controllerStarted: false,
|
|
3689
|
+
childSpawned: false,
|
|
3690
|
+
ref: expanded.ref,
|
|
3691
|
+
start: expanded.start,
|
|
3692
|
+
returnedBytes: expanded.returnedBytes,
|
|
3693
|
+
truncated: expanded.truncated,
|
|
3694
|
+
},
|
|
3695
|
+
};
|
|
3696
|
+
} else if (params.action === "context-search") {
|
|
3697
|
+
if (!params.ref || !params.query) throw new Error("ues_code context-search requires ref and query");
|
|
3698
|
+
result = await searchContext(ctx.cwd, params.ref, params.query, {
|
|
3699
|
+
maxBytes: params.maxBytes || 512000,
|
|
3700
|
+
maxMatches: 12,
|
|
3701
|
+
});
|
|
3702
|
+
} else {
|
|
3703
|
+
throw new Error("unsupported ues_code action");
|
|
3704
|
+
}
|
|
3705
|
+
|
|
3706
|
+
const payload = {
|
|
3707
|
+
...result,
|
|
3708
|
+
mode: result?.mode || "parent-lite",
|
|
3709
|
+
controllerStarted: false,
|
|
3710
|
+
childSpawned: false,
|
|
3711
|
+
};
|
|
3712
|
+
const encoded = JSON.stringify(payload, null, 2);
|
|
3713
|
+
const bounded = encoded.length > PARENT_CODE_VISIBLE_OUTPUT_LIMIT;
|
|
3714
|
+
let contextRef: string | null = null;
|
|
3715
|
+
let visible = encoded;
|
|
3716
|
+
if (bounded) {
|
|
3717
|
+
const preserved = await compactContext(ctx.cwd, encoded, {
|
|
3718
|
+
kind: "ues-code-result",
|
|
3719
|
+
source: `ues_code:${params.action}`,
|
|
3720
|
+
summary: `Full parent-lite result for ${params.action}; preserve exact JSON before model-visible bounding`,
|
|
3721
|
+
}).catch(() => null);
|
|
3722
|
+
contextRef = preserved?.ref || null;
|
|
3723
|
+
const pool = payload?.pool || payload?.lsp?.persistentPool || null;
|
|
3724
|
+
const poolSummary = pool && typeof pool === "object"
|
|
3725
|
+
? {
|
|
3726
|
+
enabled: pool.enabled ?? null,
|
|
3727
|
+
active: pool.active ?? null,
|
|
3728
|
+
busy: pool.busy ?? null,
|
|
3729
|
+
limits: pool.limits || null,
|
|
3730
|
+
metrics: pool.metrics || null,
|
|
3731
|
+
sessionCount: Array.isArray(pool.sessions) ? pool.sessions.length : null,
|
|
3732
|
+
}
|
|
3733
|
+
: null;
|
|
3734
|
+
const previewChars = Math.max(2_000, PARENT_CODE_VISIBLE_OUTPUT_LIMIT - 6_000);
|
|
3735
|
+
const metadataFirst = {
|
|
3736
|
+
schemaVersion: payload?.schemaVersion || 1,
|
|
3737
|
+
action: params.action,
|
|
3738
|
+
file: payload?.file || null,
|
|
3739
|
+
available: payload?.available ?? null,
|
|
3740
|
+
provider: payload?.provider || null,
|
|
3741
|
+
operation: payload?.operation || null,
|
|
3742
|
+
reason: payload?.reason || null,
|
|
3743
|
+
persistent: payload?.persistent ?? null,
|
|
3744
|
+
pool: poolSummary,
|
|
3745
|
+
mode: "parent-lite",
|
|
3746
|
+
controllerStarted: false,
|
|
3747
|
+
childSpawned: false,
|
|
3748
|
+
bounded: true,
|
|
3749
|
+
originalChars: encoded.length,
|
|
3750
|
+
contextRef,
|
|
3751
|
+
preview: encoded.slice(0, previewChars),
|
|
3752
|
+
};
|
|
3753
|
+
visible = JSON.stringify(metadataFirst, null, 2) +
|
|
3754
|
+
"\n...[full result preserved; use ues_code context-expand with contextRef when more evidence is needed]";
|
|
3755
|
+
}
|
|
3756
|
+
return {
|
|
3757
|
+
content: [{ type: "text", text: visible }],
|
|
3758
|
+
details: {
|
|
3759
|
+
action: params.action,
|
|
3760
|
+
mode: "parent-lite",
|
|
3761
|
+
controllerStarted: false,
|
|
3762
|
+
childSpawned: false,
|
|
3763
|
+
bounded,
|
|
3764
|
+
originalChars: encoded.length,
|
|
3765
|
+
contextRef,
|
|
3766
|
+
provider: payload?.provider || null,
|
|
3767
|
+
persistent: payload?.persistent ?? null,
|
|
3768
|
+
pool: payload?.pool || payload?.lsp?.persistentPool || null,
|
|
3769
|
+
},
|
|
3770
|
+
};
|
|
3771
|
+
} catch (error) {
|
|
3772
|
+
return {
|
|
3773
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
3774
|
+
details: {
|
|
3775
|
+
action: params.action,
|
|
3776
|
+
mode: "parent-lite",
|
|
3777
|
+
controllerStarted: false,
|
|
3778
|
+
childSpawned: false,
|
|
3779
|
+
},
|
|
3780
|
+
isError: true,
|
|
3781
|
+
};
|
|
3782
|
+
}
|
|
3783
|
+
},
|
|
3192
3784
|
});
|
|
3193
3785
|
|
|
3194
3786
|
pi.registerTool({
|
|
@@ -3344,6 +3936,60 @@ export default function (pi: ExtensionAPI) {
|
|
|
3344
3936
|
},
|
|
3345
3937
|
});
|
|
3346
3938
|
|
|
3939
|
+
pi.registerTool({
|
|
3940
|
+
name: "ues_session",
|
|
3941
|
+
label: "UES Session Control",
|
|
3942
|
+
description:
|
|
3943
|
+
"Control the single active Pi RPC specialist session without shell orchestration. Supports state inspection, steer vs follow-up queueing, abort, queue clearing, model/thinking changes, compaction, and bounded wait. Fails closed when zero or multiple child sessions are active.",
|
|
3944
|
+
parameters: Type.Object({
|
|
3945
|
+
action: Type.Union([
|
|
3946
|
+
Type.Literal("status"),
|
|
3947
|
+
Type.Literal("get-state"),
|
|
3948
|
+
Type.Literal("steer"),
|
|
3949
|
+
Type.Literal("follow-up"),
|
|
3950
|
+
Type.Literal("abort"),
|
|
3951
|
+
Type.Literal("clear-queue"),
|
|
3952
|
+
Type.Literal("set-model"),
|
|
3953
|
+
Type.Literal("set-thinking"),
|
|
3954
|
+
Type.Literal("compact"),
|
|
3955
|
+
Type.Literal("wait"),
|
|
3956
|
+
]),
|
|
3957
|
+
message: Type.Optional(Type.String({ maxLength: 12000 })),
|
|
3958
|
+
provider: Type.Optional(Type.String({ maxLength: 120 })),
|
|
3959
|
+
modelId: Type.Optional(Type.String({ maxLength: 240 })),
|
|
3960
|
+
thinkingLevel: Type.Optional(Type.String({ maxLength: 40 })),
|
|
3961
|
+
compactInstructions: Type.Optional(Type.String({ maxLength: 12000 })),
|
|
3962
|
+
timeoutMs: Type.Optional(Type.Number({ minimum: 500, maximum: 1800000 })),
|
|
3963
|
+
}),
|
|
3964
|
+
async execute(_toolCallId, params) {
|
|
3965
|
+
try {
|
|
3966
|
+
const action = String(params.action || "status");
|
|
3967
|
+
const result = action === "status"
|
|
3968
|
+
? { ok: true, action, ...RPC_POOL.status() }
|
|
3969
|
+
: await RPC_POOL.controlActive(action, {
|
|
3970
|
+
message: params.message,
|
|
3971
|
+
provider: params.provider,
|
|
3972
|
+
modelId: params.modelId,
|
|
3973
|
+
level: params.thinkingLevel,
|
|
3974
|
+
customInstructions: params.compactInstructions,
|
|
3975
|
+
timeoutMs: params.timeoutMs,
|
|
3976
|
+
});
|
|
3977
|
+
return {
|
|
3978
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
3979
|
+
details: result,
|
|
3980
|
+
isError: result?.ok === false,
|
|
3981
|
+
};
|
|
3982
|
+
} catch (error) {
|
|
3983
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3984
|
+
return {
|
|
3985
|
+
content: [{ type: "text", text: message }],
|
|
3986
|
+
details: { action: params.action, error: message },
|
|
3987
|
+
isError: true,
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
},
|
|
3991
|
+
});
|
|
3992
|
+
|
|
3347
3993
|
const uesExecuteTool: any = {
|
|
3348
3994
|
name: "ues_execute",
|
|
3349
3995
|
label: "UES Execute",
|
|
@@ -3396,6 +4042,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
3396
4042
|
profile: policy.executionProfile,
|
|
3397
4043
|
risk: policy.risk,
|
|
3398
4044
|
mode: policy.mode,
|
|
4045
|
+
decisionConfidence: policy.decision?.confidence ?? null,
|
|
4046
|
+
decisionReason: policy.decision?.reason ?? null,
|
|
3399
4047
|
inheritedDirtyCount: executionContract.inheritedDirty?.paths?.length || 0,
|
|
3400
4048
|
explicitPhaseCount: executionContract.phases?.length || 0,
|
|
3401
4049
|
localEnvWriteExplicitlyAllowed: executionContract.localEnvWriteExplicitlyAllowed === true,
|
|
@@ -3583,8 +4231,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
3583
4231
|
"",
|
|
3584
4232
|
"## Acceptance criteria proven",
|
|
3585
4233
|
deterministicPass
|
|
3586
|
-
? "All explicitly requested whitelisted Git inspection commands completed successfully."
|
|
3587
|
-
: "The requested deterministic inspection did not fully pass.",
|
|
4234
|
+
? "VERIFIED: All explicitly requested whitelisted Git inspection commands completed successfully."
|
|
4235
|
+
: "UNKNOWN: The requested deterministic inspection did not fully pass.",
|
|
3588
4236
|
"",
|
|
3589
4237
|
"## Failures",
|
|
3590
4238
|
failureText,
|
|
@@ -3644,6 +4292,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
3644
4292
|
1,
|
|
3645
4293
|
);
|
|
3646
4294
|
if (isAbortedRun(inspection)) return abortedResponse(inspection, "read-only-inspection");
|
|
4295
|
+
if (
|
|
4296
|
+
inspection.exitCode === 0 &&
|
|
4297
|
+
inspection.verdict === "PASS" &&
|
|
4298
|
+
!acceptanceEvidenceStatusPresent(inspection)
|
|
4299
|
+
) {
|
|
4300
|
+
inspection = await run(
|
|
4301
|
+
"ues-verifier",
|
|
4302
|
+
[
|
|
4303
|
+
"READ-ONLY VERIFICATION FORMAT RECOVERY. The previous verifier returned PASS but omitted mandatory evidence-status prefixes.",
|
|
4304
|
+
"Do not edit files. Re-check only what is needed to support the existing verdict.",
|
|
4305
|
+
"In ## Acceptance criteria proven, prefix every requested criterion with exactly VERIFIED:, INFERRED:, or UNKNOWN:.",
|
|
4306
|
+
"INFERRED or UNKNOWN criteria must also be listed under ## Unresolved gaps and cannot support PASS.",
|
|
4307
|
+
"",
|
|
4308
|
+
"Inspection request:",
|
|
4309
|
+
params.task,
|
|
4310
|
+
].join("\n"),
|
|
4311
|
+
1,
|
|
4312
|
+
"Previous verifier PASS omitted evidence-status markers.",
|
|
4313
|
+
);
|
|
4314
|
+
if (isAbortedRun(inspection)) return abortedResponse(inspection, "read-only-verification-format-recovery");
|
|
4315
|
+
}
|
|
3647
4316
|
}
|
|
3648
4317
|
|
|
3649
4318
|
const after = runtimeWorkspaceSnapshot(cwd);
|
|
@@ -3658,6 +4327,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
3658
4327
|
workspaceSnapshot: after,
|
|
3659
4328
|
behavioralReceipts: [],
|
|
3660
4329
|
requireBehavioralReceipt: false,
|
|
4330
|
+
requireClaimEvidenceStatus: true,
|
|
3661
4331
|
});
|
|
3662
4332
|
if (!unchanged) {
|
|
3663
4333
|
completionAudit.passed = false;
|
|
@@ -4422,7 +5092,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
4422
5092
|
agent: "ues-deterministic-verifier", task: params.task, cwd, exitCode: 0,
|
|
4423
5093
|
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"),
|
|
4424
5094
|
stderr: "", verdict: "PASS", durationMs: 0, toolCalls: 0, toolNames: [],
|
|
4425
|
-
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." } },
|
|
5095
|
+
report: { schemaVersion: 1, valid: true, verdict: "PASS", sections: { "checks-run": fastGate.behavioralReceipts.map((item: any) => item.command).join("\n"), "acceptance-criteria-proven": "VERIFIED: Fresh behavioral verification receipt(s) exist at the post-implementation workspace fingerprint.", "completion-evidence": "Deterministic PASS receipt captured after this implementation attempt." } },
|
|
4426
5096
|
optimizations: { fastDeterministicVerification: true, behavioralReceiptCount: fastGate.behavioralReceipts.length },
|
|
4427
5097
|
};
|
|
4428
5098
|
steps.push(verification);
|
|
@@ -4440,6 +5110,30 @@ export default function (pi: ExtensionAPI) {
|
|
|
4440
5110
|
].join("\n"), attempt, recentFailure || undefined,
|
|
4441
5111
|
);
|
|
4442
5112
|
if (isAbortedRun(verification)) return abortedResponse(verification, "verification");
|
|
5113
|
+
if (
|
|
5114
|
+
verification.exitCode === 0 &&
|
|
5115
|
+
verification.verdict === "PASS" &&
|
|
5116
|
+
!acceptanceEvidenceStatusPresent(verification)
|
|
5117
|
+
) {
|
|
5118
|
+
verification = await run(
|
|
5119
|
+
"ues-verifier",
|
|
5120
|
+
[
|
|
5121
|
+
"VERIFICATION FORMAT RECOVERY. The previous verifier returned PASS but omitted mandatory evidence-status prefixes.",
|
|
5122
|
+
"Do not edit files and do not re-run broad checks. Re-check only what is necessary to support the verdict.",
|
|
5123
|
+
"In ## Acceptance criteria proven, prefix every requested criterion with exactly VERIFIED:, INFERRED:, or UNKNOWN:.",
|
|
5124
|
+
"INFERRED or UNKNOWN criteria must also appear under ## Unresolved gaps and cannot support PASS.",
|
|
5125
|
+
"",
|
|
5126
|
+
"Original task:",
|
|
5127
|
+
params.task,
|
|
5128
|
+
"",
|
|
5129
|
+
"Previous verifier output (not proof by itself):",
|
|
5130
|
+
cap(verification.output, 5000),
|
|
5131
|
+
].join("\n"),
|
|
5132
|
+
attempt,
|
|
5133
|
+
"Previous verifier PASS omitted evidence-status markers.",
|
|
5134
|
+
);
|
|
5135
|
+
if (isAbortedRun(verification)) return abortedResponse(verification, "verification-format-recovery");
|
|
5136
|
+
}
|
|
4443
5137
|
}
|
|
4444
5138
|
const verified = verification.exitCode === 0 && verification.verdict === "PASS";
|
|
4445
5139
|
if (!verified) {
|
|
@@ -4526,6 +5220,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
4526
5220
|
workspaceSnapshot: completionSnapshot,
|
|
4527
5221
|
behavioralReceipts: freshReceipts,
|
|
4528
5222
|
requireBehavioralReceipt: policy.requireBehavioralReceipt !== false,
|
|
5223
|
+
requireClaimEvidenceStatus: true,
|
|
4529
5224
|
});
|
|
4530
5225
|
if (!completionAudit.passed) {
|
|
4531
5226
|
recentFailure = "Completion auditor rejected PASS: " + completionAudit.failures.join(", ");
|
|
@@ -4666,6 +5361,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
4666
5361
|
"Micro skills: " + (MICRO_SKILLS_ENABLED ? "on" : "off"),
|
|
4667
5362
|
"Turbo Fast Path: on",
|
|
4668
5363
|
"Parent UES tools hidden outside UES runs: on",
|
|
5364
|
+
"Parent Code Intelligence Lite: on (always-on read-only ues_code; no controller/child)",
|
|
5365
|
+
"Native Pi RPC session control: on (state/steer/follow-up/abort/model/thinking/compact/wait)",
|
|
5366
|
+
"Permission deny-and-continue recovery: on",
|
|
5367
|
+
"Provider empty-response recovery: on (per-incident parent retry + bounded total + child RPC recovery; no blind replay after tools)",
|
|
4669
5368
|
"Zero-friction engineering admission: " + (AUTO_ADMISSION_ENABLED ? "on (native / auto / high-risk + safe continuation)" : "off"),
|
|
4670
5369
|
"Git-root artifact guard: on",
|
|
4671
5370
|
"Inherited dirty-work guard: on",
|