@pentoshi/clai 3.8.21 → 3.8.22
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/dist/agent/confirm-port.d.ts +5 -2
- package/dist/agent/confirm-port.js +11 -5
- package/dist/agent/confirm-port.js.map +1 -1
- package/dist/agent/plan-decision.js +7 -3
- package/dist/agent/plan-decision.js.map +1 -1
- package/dist/agent/plan-tool.js +63 -20
- package/dist/agent/plan-tool.js.map +1 -1
- package/dist/agent/progress-pause-policy.d.ts +21 -0
- package/dist/agent/progress-pause-policy.js +28 -0
- package/dist/agent/progress-pause-policy.js.map +1 -0
- package/dist/agent/runner.js +117 -28
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/stop-summary.js +3 -1
- package/dist/agent/stop-summary.js.map +1 -1
- package/dist/agent/tool-output-formatting.js +16 -0
- package/dist/agent/tool-output-formatting.js.map +1 -1
- package/dist/app/ports/confirm-port.d.ts +1 -1
- package/dist/prompts/embedded.js +1 -1
- package/dist/prompts/embedded.js.map +1 -1
- package/dist/prompts/index.js +6 -0
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/system.agent.md +2 -0
- package/dist/tools/web/search.js +22 -3
- package/dist/tools/web/search.js.map +1 -1
- package/dist/tui-v2/bootstrap/overlay-ports.js +7 -2
- package/dist/tui-v2/bootstrap/overlay-ports.js.map +1 -1
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +1 -1
package/dist/agent/runner.js
CHANGED
|
@@ -37,6 +37,7 @@ import { fsWrite, isOutsideWorkingDirectory, resolveFsToolPath, } from "../tools
|
|
|
37
37
|
import { stripSentinelTokens, parseToolCall, recognizeBareToolJson, looksLikeTruncatedToolCall, salvageTruncatedWrite, salvageTruncatedWriteFromNative, countToolFences, parseAllToolCalls, groupToolCallsForExecution, buildTurnHistory, collapseRepeatedText, textBeforeToolCall, formatToolArgs, looksLikePentestTask, looksLikeBuildTask, looksLikeInformationalQuery, looksLikeIdleOrSocialPrompt, looksLikeActionNarration, looksLikeWebActionNarration, looksLikePlanNarration, looksLikeErrorDiagnosisWithFixIntent, localHttpProbeIsFailure, localHttpProbeIsSuccess, requiresFreshWebSearch, freshnessGuardMessage, buildWorkflowDirective, narrowNmapOperationDirective, pentestWorkflowDirective, pentestNoLocalServerDirective, shouldDimToolChatter, looksLikePromptLeak, } from "./tool-call-parser.js";
|
|
38
38
|
import { createSessionPolicy, isPreApprovalAllowedTool, isPlanModeAllowedShellCommand, isPlanModeAllowedTool, isPlanApprovedByStatus, planHasOpenWork, isAbortError, shouldEnableImageOcr, } from "./session-policy.js";
|
|
39
39
|
import { saveToolOutput, summarizeOutput, formatToolContext, } from "./tool-output-formatting.js";
|
|
40
|
+
import { codingSessionFromContext, isProtocolPlaceholderOutput, progressPauseMode, } from "./progress-pause-policy.js";
|
|
40
41
|
import { renderPlanForTerminal, planContextMessage, handlePlanTool, resolvePlanTaskId, } from "./plan-tool.js";
|
|
41
42
|
import { absorbLooseWorkIntoLedger, applyDestinationCwd, canMarkTaskDone, hasLocalRuntimeProof, hasRemoteWorkProof, isDevServerCall, isEvidenceWorkTool, isFeatureImplementationCall, isPackageInstallCommand, isPlanPreflightTool, isPortListeningOutput, isReadOnlyReconTool, isRemoteActiveTestCall, isRemoteObservationTask, isRemoteReconToolCall, isRuntimeObservationTask, isScaffoldCreateCommand, isServerReadyOutput, ledgerFromTaskEvidence, pickPendingTaskForToolCall, recordTaskWorkSuccess, resolveUserDestinationHint, taskEvidenceFromLedger, TOOL_ABORT_GRACE_MS, toolHardBudgetMs, toolStallBudgetMs, userAskedForFeatureApp, } from "./task-evidence.js";
|
|
42
43
|
import { buildSessionStateBlock, inferNextHint, upsertSessionStateMessage, } from "./session-state.js";
|
|
@@ -793,6 +794,15 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
793
794
|
const hasHistory = (options.history?.length ?? 0) > 0;
|
|
794
795
|
const buildLike = buildLikeTurn;
|
|
795
796
|
const pentestLike = looksLikePentestTask(prompt, options.history);
|
|
797
|
+
/** Coding/build sessions never hard-pause mid-turn for the progress governor. */
|
|
798
|
+
let codingSession = codingSessionFromContext({
|
|
799
|
+
buildLike,
|
|
800
|
+
planKind: activePlan?.kind,
|
|
801
|
+
});
|
|
802
|
+
let pauseMode = progressPauseMode({
|
|
803
|
+
codingSession,
|
|
804
|
+
autoConfirm: Boolean(options.autoConfirm),
|
|
805
|
+
});
|
|
796
806
|
const continueExistingOutcome = /^(?:continue|resume|proceed|keep\s+going|finish|next)\b/i.test(prompt.trim()) ||
|
|
797
807
|
Boolean(activePlan && !isPlanTerminal(activePlan));
|
|
798
808
|
const outcomeState = await openOutcomeState({
|
|
@@ -1767,27 +1777,52 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
1767
1777
|
((call.name === "shell.exec" || call.name === "shell.start") &&
|
|
1768
1778
|
isPackageInstallCommand(String(call.args.command ?? "")));
|
|
1769
1779
|
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1780
|
+
// Protocol-repair placeholders are not live work — never let them
|
|
1781
|
+
// accumulate into a mid-turn pause (they used to look like failed tools).
|
|
1782
|
+
if (!isProtocolPlaceholderOutput(result.output)) {
|
|
1783
|
+
const governed = governProgress(governorState, "activity", {
|
|
1784
|
+
evidenceDelta: newEvidence.length,
|
|
1785
|
+
hypothesisDelta,
|
|
1786
|
+
repetitionScore: loopGuard.getAttemptCount(call.name, call.args) > 1 ? 1 : 0,
|
|
1787
|
+
policy: {
|
|
1788
|
+
resourceEnvelope: Math.max(12, maxSteps),
|
|
1789
|
+
// Coding builds get a much higher ceiling; never use the tight
|
|
1790
|
+
// default that stopped multi-file scaffolds after a handful of steps.
|
|
1791
|
+
emergencyCeiling: codingSession
|
|
1792
|
+
? Math.max(200, maxSteps * 5)
|
|
1793
|
+
: Math.max(70, maxSteps * 3),
|
|
1794
|
+
reflectionAfterNoDelta: codingSession ? 5 : 3,
|
|
1795
|
+
pauseAfterNoDelta: codingSession ? 24 : 6,
|
|
1796
|
+
repetitionThreshold: 0.8,
|
|
1797
|
+
},
|
|
1787
1798
|
});
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1799
|
+
governorState = governed.state;
|
|
1800
|
+
if (governed.recommendation === "reflect") {
|
|
1801
|
+
deferredPostToolMessages.push({
|
|
1802
|
+
role: "system",
|
|
1803
|
+
content: `PROGRESS GOVERNOR: ${governed.reason}. Reassess the current premise and choose the next action that can produce criterion-linked evidence.` +
|
|
1804
|
+
(codingSession
|
|
1805
|
+
? " Keep working — coding builds do not stop for a continue prompt."
|
|
1806
|
+
: ""),
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
else if (governed.recommendation === "paused_budget") {
|
|
1810
|
+
if (pauseMode === "never") {
|
|
1811
|
+
// Soft reset so we do not re-trip every subsequent tool.
|
|
1812
|
+
governorState = {
|
|
1813
|
+
...governed.state,
|
|
1814
|
+
consecutiveNoDelta: 0,
|
|
1815
|
+
};
|
|
1816
|
+
deferredPostToolMessages.push({
|
|
1817
|
+
role: "system",
|
|
1818
|
+
content: `PROGRESS GOVERNOR (soft, coding build): ${governed.reason}. ` +
|
|
1819
|
+
"Change approach if stuck, but keep implementing — do not stop for user confirmation.",
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
else {
|
|
1823
|
+
governorPauseReason = governed.reason;
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1791
1826
|
}
|
|
1792
1827
|
await saveOutcomeState(outcomeState);
|
|
1793
1828
|
loopGuard.recordAttempt(step, call.name, call.args, result.ok, result.exitCode);
|
|
@@ -2033,14 +2068,53 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
2033
2068
|
// advances when the previous iteration actually executed a tool.
|
|
2034
2069
|
step = productiveSteps;
|
|
2035
2070
|
if (governorPauseReason) {
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2071
|
+
// Non-coding: always ask continue/stop. Coding never sets this reason
|
|
2072
|
+
// (pauseMode === "never"), but guard anyway.
|
|
2073
|
+
if (pauseMode === "never") {
|
|
2074
|
+
governorPauseReason = undefined;
|
|
2075
|
+
governorState = {
|
|
2076
|
+
...governorState,
|
|
2077
|
+
consecutiveNoDelta: 0,
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
else {
|
|
2081
|
+
const confirmPort = options.confirm;
|
|
2082
|
+
let keepGoing = false;
|
|
2083
|
+
if (confirmPort?.confirmContinue) {
|
|
2084
|
+
try {
|
|
2085
|
+
keepGoing = await confirmPort.confirmContinue(productiveSteps, governorPauseReason);
|
|
2086
|
+
}
|
|
2087
|
+
catch {
|
|
2088
|
+
keepGoing = false;
|
|
2089
|
+
}
|
|
2090
|
+
finally {
|
|
2091
|
+
restoreInteractiveStdin();
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
if (keepGoing) {
|
|
2095
|
+
writeNotice("info", "continuing after progress pause", chalk.dim(` ℹ continuing after pause (${governorPauseReason}) — change approach if stuck\n`));
|
|
2096
|
+
deferredPostToolMessages.push({
|
|
2097
|
+
role: "system",
|
|
2098
|
+
content: `User chose CONTINUE after progress pause (${governorPauseReason}). ` +
|
|
2099
|
+
"Do not repeat the same failing step; change approach and produce new evidence.",
|
|
2100
|
+
});
|
|
2101
|
+
governorPauseReason = undefined;
|
|
2102
|
+
governorState = {
|
|
2103
|
+
...governorState,
|
|
2104
|
+
consecutiveNoDelta: 0,
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
else {
|
|
2108
|
+
const richSummary = await buildRichStopSummary(messages, session, productiveSteps);
|
|
2109
|
+
outcomeState.outcome.status = "paused_budget";
|
|
2110
|
+
await saveOutcomeState(outcomeState);
|
|
2111
|
+
moveTurn("paused_budget", governorPauseReason);
|
|
2112
|
+
lastAnswer = richSummary;
|
|
2113
|
+
return finishTurn(lastAnswer, productiveSteps, "paused_budget", outcomeState.outcome.criteria
|
|
2114
|
+
.filter((criterion) => criterion.required && criterion.status !== "proven")
|
|
2115
|
+
.map((criterion) => criterion.statement), governorPauseReason);
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2044
2118
|
}
|
|
2045
2119
|
options.signal?.throwIfAborted();
|
|
2046
2120
|
let call;
|
|
@@ -3216,6 +3290,19 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3216
3290
|
else {
|
|
3217
3291
|
session.planApproved.value = true;
|
|
3218
3292
|
}
|
|
3293
|
+
// Re-derive pause policy from the new plan kind (coding builds
|
|
3294
|
+
// must not hard-pause even if the free-text prompt was generic).
|
|
3295
|
+
const kindArg = typeof res.call.args.kind === "string"
|
|
3296
|
+
? res.call.args.kind
|
|
3297
|
+
: undefined;
|
|
3298
|
+
codingSession = codingSessionFromContext({
|
|
3299
|
+
buildLike,
|
|
3300
|
+
planKind: kindArg,
|
|
3301
|
+
});
|
|
3302
|
+
pauseMode = progressPauseMode({
|
|
3303
|
+
codingSession,
|
|
3304
|
+
autoConfirm: Boolean(options.autoConfirm),
|
|
3305
|
+
});
|
|
3219
3306
|
}
|
|
3220
3307
|
// User Esc/Ctrl+C only — never cancel siblings because a delete failed
|
|
3221
3308
|
// or a confirm was declined; the model must see every tool result.
|
|
@@ -3335,6 +3422,8 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3335
3422
|
}
|
|
3336
3423
|
}
|
|
3337
3424
|
}
|
|
3425
|
+
// Hard iteration ceiling (hundreds of steps) — rare. Mid-turn governor
|
|
3426
|
+
// pauses already confirm for non-coding; coding never hard-pauses there.
|
|
3338
3427
|
const richSummary = await buildRichStopSummary(messages, session, productiveSteps);
|
|
3339
3428
|
lastAnswer = richSummary;
|
|
3340
3429
|
outcomeState.outcome.status = "paused_budget";
|