@pentoshi/clai 2.0.38 → 2.0.43
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 +43 -34
- package/dist/agent/context-manager.d.ts +5 -5
- package/dist/agent/context-manager.js +34 -10
- package/dist/agent/context-manager.js.map +1 -1
- package/dist/agent/plan-tool.js +7 -1
- package/dist/agent/plan-tool.js.map +1 -1
- package/dist/agent/runner.js +122 -33
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/tool-call-parser.d.ts +16 -0
- package/dist/agent/tool-call-parser.js +100 -4
- package/dist/agent/tool-call-parser.js.map +1 -1
- package/dist/commands/update.js +1 -1
- package/dist/prompts/index.d.ts +2 -2
- package/dist/prompts/index.js +12 -5
- package/dist/prompts/index.js.map +1 -1
- package/dist/repl.js +19 -2
- package/dist/repl.js.map +1 -1
- package/dist/tools/registry.js +2 -2
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/wordlists.d.ts +0 -1
- package/dist/tools/wordlists.js +149 -67
- package/dist/tools/wordlists.js.map +1 -1
- package/dist/tui/App.js +7 -2
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/render-lines.js +20 -5
- package/dist/tui/render-lines.js.map +1 -1
- package/dist/ui/intro-card.js +47 -8
- package/dist/ui/intro-card.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -182,40 +182,49 @@ export OLLAMA_HOST=http://localhost:11434
|
|
|
182
182
|
|
|
183
183
|
## REPL Commands
|
|
184
184
|
|
|
185
|
-
| Command
|
|
186
|
-
|
|
187
|
-
| `/ask`
|
|
188
|
-
| `/agent`
|
|
189
|
-
| `/model`
|
|
190
|
-
| `/model <name\|#>`
|
|
191
|
-
| `/provider [name]`
|
|
192
|
-
| `/use <provider>`
|
|
193
|
-
| `/set <provider> [key]` | Store API key (masked input if key omitted)
|
|
194
|
-
| `/unset <provider>`
|
|
195
|
-
| `/keys`
|
|
196
|
-
| `/info [provider]`
|
|
197
|
-
| `/
|
|
198
|
-
| `/
|
|
199
|
-
| `/
|
|
200
|
-
| `/
|
|
201
|
-
| `/
|
|
202
|
-
| `/
|
|
203
|
-
| `/
|
|
204
|
-
| `/
|
|
205
|
-
| `/
|
|
206
|
-
| `/
|
|
207
|
-
| `/
|
|
208
|
-
| `/
|
|
209
|
-
| `/
|
|
210
|
-
| `/
|
|
211
|
-
| `/
|
|
212
|
-
| `/
|
|
213
|
-
| `/
|
|
214
|
-
| `/
|
|
215
|
-
| `/
|
|
216
|
-
| `
|
|
217
|
-
| `
|
|
218
|
-
| `
|
|
185
|
+
| Command | Action |
|
|
186
|
+
|---------|--------|
|
|
187
|
+
| `/ask` | Switch to read-only ask mode (suggests commands/steps but does not execute them) |
|
|
188
|
+
| `/agent` | Switch to active agent mode (proposes plans, executes commands, installs tools) |
|
|
189
|
+
| `/model` | Open the interactive model picker to select a model (press Enter to open) |
|
|
190
|
+
| `/model <name\|#>` | Switch active model by model name or index number (e.g. `/model 2`) |
|
|
191
|
+
| `/provider [name]` | Switch LLM provider or open interactive provider picker |
|
|
192
|
+
| `/use <provider>` | Alias for `/provider <name>` |
|
|
193
|
+
| `/set <provider> [key]` | Store API key for a provider (prompts with masked input if key is omitted) |
|
|
194
|
+
| `/unset <provider>` | Remove stored API key for a provider |
|
|
195
|
+
| `/keys` | List configured providers with their API keys masked |
|
|
196
|
+
| `/info [provider]` | Show model parameters, token/thinking limits, and usage details for a provider |
|
|
197
|
+
| `/search [provider]` | Switch search provider (Brave, Tavily, etc.) or open interactive picker |
|
|
198
|
+
| `/search-provider [name]`| Alias for `/search` |
|
|
199
|
+
| `/mouse [on\|off]` | Enable (`on`) or disable (`off`) REPL mouse tracking for scrolling vs native copy-paste selection |
|
|
200
|
+
| `/variants [on\|off\|none\|minimal\|low\|medium\|high\|xhigh]` | Configure reasoning effort. Use `on`/`off` to toggle, or set reasoning effort level (opens picker if no arg) |
|
|
201
|
+
| `/reasoning [...]` | Alias for `/variants` |
|
|
202
|
+
| `/think` / `/thinking` | Print the full, hidden reasoning/thinking trace from the last LLM response |
|
|
203
|
+
| `/output [last\|id\|list]`| Toggle full tool output pager (`Ctrl+O`) or list saved output files |
|
|
204
|
+
| `/clear` | Clear the current conversation messages and active state in memory |
|
|
205
|
+
| `/new` / `/clean` | Save current session to history and start a fresh session with cleared context |
|
|
206
|
+
| `/history` | Open interactive session browser to search and restore past conversation sessions |
|
|
207
|
+
| `/save <name>` | Manually save the current session under a custom name |
|
|
208
|
+
| `/reset` | Clear all saved history sessions permanently |
|
|
209
|
+
| `/cwd <path>` | Change the current working directory for shell and tool executions |
|
|
210
|
+
| `/allow <tool>` | Whitelist a tool for the current session to run without prompting for confirmation |
|
|
211
|
+
| `/disallow <tool>` | Revoke session authorization for a tool |
|
|
212
|
+
| `/freeonly [on\|off]` | Toggle (`on` to restrict, `off` to permit) paid providers when automatic fallback is active |
|
|
213
|
+
| `/fallback [on\|off]` | Toggle (`on` to try other providers after a primary failure, `off` to fail immediately) |
|
|
214
|
+
| `/compact` | Compress session history to fit context window constraints |
|
|
215
|
+
| `/context` | Display estimated current context size in tokens |
|
|
216
|
+
| `/plan` | View the current session plan checklist (also `Ctrl+P`) |
|
|
217
|
+
| `/implement` | Approve the proposed plan and begin automated execution |
|
|
218
|
+
| `/discard` | Discard the current plan and return to normal conversational mode |
|
|
219
|
+
| `/scope [show\|clear\|new\|add <targets>]` | View or adjust authorized penetration testing target scopes |
|
|
220
|
+
| `/privacy [status\|clear-history\|clear-logs\|clear-artifacts\|clear-all\|on\|off]` | Toggle private mode (`on` disables all disk writing, `off` enables) or purge logs/history |
|
|
221
|
+
| `/permissions [default\|allow-all]` | Set confirmation prompt behavior (`allow-all` bypasses confirm prompts for mutating tasks except keys) |
|
|
222
|
+
| `/update` | Check for updates and upgrade clai |
|
|
223
|
+
| `/exit` / `/quit` | Quit and close the REPL |
|
|
224
|
+
| `/help` | Print this command reference guide |
|
|
225
|
+
| `Ctrl+C` | Abort current response (second Ctrl+C exits) |
|
|
226
|
+
| `Ctrl+O` | Toggle full tool output (same keys on all OSes) |
|
|
227
|
+
| `Ctrl+P` | View the current session plan |
|
|
219
228
|
|
|
220
229
|
### Plan → Implement workflow
|
|
221
230
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ChatMessage } from "../types.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* over-
|
|
7
|
-
* to a provider context-window error.
|
|
3
|
+
* Per-char token estimator. Real tokenization varies by provider, but for
|
|
4
|
+
* budgeting a chars/3.3 heuristic is close enough for mixed text/code/JSON
|
|
5
|
+
* (which tokenizes less efficiently than pure English prose). We
|
|
6
|
+
* deliberately over-estimate — better to compact one turn too early than to
|
|
7
|
+
* lose state to a provider context-window error.
|
|
8
8
|
*/
|
|
9
9
|
export declare function estimateTokens(text: string): number;
|
|
10
10
|
export declare function estimateMessagesTokens(messages: ChatMessage[]): number;
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { redactSecrets } from "../llm/provider.js";
|
|
2
|
+
import { stripThinking } from "../ui/thinking.js";
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* over-
|
|
7
|
-
* to a provider context-window error.
|
|
4
|
+
* Per-char token estimator. Real tokenization varies by provider, but for
|
|
5
|
+
* budgeting a chars/3.3 heuristic is close enough for mixed text/code/JSON
|
|
6
|
+
* (which tokenizes less efficiently than pure English prose). We
|
|
7
|
+
* deliberately over-estimate — better to compact one turn too early than to
|
|
8
|
+
* lose state to a provider context-window error.
|
|
8
9
|
*/
|
|
9
10
|
export function estimateTokens(text) {
|
|
10
|
-
return Math.ceil(text.length /
|
|
11
|
+
return Math.ceil(text.length / 3.3);
|
|
11
12
|
}
|
|
12
13
|
export function estimateMessagesTokens(messages) {
|
|
13
14
|
let sum = 0;
|
|
14
15
|
for (const message of messages) {
|
|
15
16
|
sum += estimateTokens(message.content) + 4; // role overhead
|
|
17
|
+
// Images contribute tokens too — a typical image is ~1k tokens.
|
|
18
|
+
if (message.images) {
|
|
19
|
+
sum += message.images.length * 1000;
|
|
20
|
+
}
|
|
16
21
|
}
|
|
17
22
|
return sum;
|
|
18
23
|
}
|
|
19
24
|
const DEFAULT_BUDGET_TOKENS = 32_000;
|
|
20
|
-
const DEFAULT_KEEP_RECENT =
|
|
25
|
+
const DEFAULT_KEEP_RECENT = 6;
|
|
21
26
|
/**
|
|
22
27
|
* Content prefixes that mark a `role:"system"` message as compacted session
|
|
23
28
|
* memory (vs. the main system prompt or transient injected guidance). Exported
|
|
@@ -116,7 +121,15 @@ export async function compactMessagesWithSummary(messages, summarize, options =
|
|
|
116
121
|
};
|
|
117
122
|
}
|
|
118
123
|
const messageTranscript = older
|
|
119
|
-
.map((message) =>
|
|
124
|
+
.map((message) => {
|
|
125
|
+
let content = redactSecrets(message.content);
|
|
126
|
+
// Strip <think> tags from assistant messages so thinking content
|
|
127
|
+
// never leaks into the compaction summary or model context.
|
|
128
|
+
if (message.role === "assistant") {
|
|
129
|
+
content = stripThinking(content).visible;
|
|
130
|
+
}
|
|
131
|
+
return `${message.role.toUpperCase()}: ${content}`;
|
|
132
|
+
})
|
|
120
133
|
.join("\n\n");
|
|
121
134
|
const transcript = sessionTranscript?.trim()
|
|
122
135
|
? redactSecrets(sessionTranscript.trim())
|
|
@@ -131,14 +144,25 @@ export async function compactMessagesWithSummary(messages, summarize, options =
|
|
|
131
144
|
].join("\n");
|
|
132
145
|
// The summary is the only path. Any failure propagates to the caller —
|
|
133
146
|
// there is deliberately NO deterministic fallback.
|
|
134
|
-
|
|
147
|
+
// Strip <think> tags from the summary — the summarizer model may itself
|
|
148
|
+
// produce reasoning tags that would leak into the compacted context.
|
|
149
|
+
const rawSummary = redactSecrets((await summarize(prompt)).trim());
|
|
150
|
+
const summary = stripThinking(rawSummary).visible.trim();
|
|
135
151
|
if (!summary)
|
|
136
152
|
throw new Error("compaction failed: model returned an empty summary");
|
|
137
153
|
const head = start === 1 ? [messages[0]] : [];
|
|
154
|
+
// Strip <think> tags from tail messages so thinking content never
|
|
155
|
+
// survives compaction into the model's context.
|
|
156
|
+
const tail = messages.slice(tailStart).map((msg) => {
|
|
157
|
+
if (msg.role === "assistant" && /<think/i.test(msg.content)) {
|
|
158
|
+
return { ...msg, content: stripThinking(msg.content).visible };
|
|
159
|
+
}
|
|
160
|
+
return msg;
|
|
161
|
+
});
|
|
138
162
|
const compacted = [
|
|
139
163
|
...head,
|
|
140
164
|
{ role: "system", content: `${COMPACTION_MEMORY_PREFIX}\n\n${summary}` },
|
|
141
|
-
...
|
|
165
|
+
...tail,
|
|
142
166
|
];
|
|
143
167
|
const afterTokens = estimateMessagesTokens(compacted);
|
|
144
168
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-manager.js","sourceRoot":"","sources":["../../src/agent/context-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"context-manager.js","sourceRoot":"","sources":["../../src/agent/context-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/plan-tool.js
CHANGED
|
@@ -17,9 +17,15 @@ export function planContextMessage(plan, approved) {
|
|
|
17
17
|
lines.push(` ${i + 1}. [${t.id}] (${t.state}) ${t.title}`);
|
|
18
18
|
});
|
|
19
19
|
if (approved) {
|
|
20
|
+
const inProgress = plan.tasks.find((t) => t.state === "in_progress");
|
|
20
21
|
const firstPending = plan.tasks.find((t) => t.state === "pending");
|
|
21
22
|
lines.push("The user APPROVED this plan. Execute it task by task NOW.");
|
|
22
|
-
if (
|
|
23
|
+
if (inProgress) {
|
|
24
|
+
lines.push(`RESUME TASK ${inProgress.id} (${inProgress.title}) — it was started but interrupted. ` +
|
|
25
|
+
"Retry what was in progress; do NOT restart completed work from scratch. " +
|
|
26
|
+
"Do NOT re-do tasks already marked done, and do NOT skip ahead to later tasks.");
|
|
27
|
+
}
|
|
28
|
+
else if (firstPending) {
|
|
23
29
|
lines.push(`START WITH TASK ${firstPending.id} (${firstPending.title}). ` +
|
|
24
30
|
"Do NOT re-do tasks already marked done, and do NOT skip ahead to later tasks.");
|
|
25
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-tool.js","sourceRoot":"","sources":["../../src/agent/plan-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,GAGT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAG3D,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CAAC,IAAiB;IACrD,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAYD,2EAA2E;AAC3E,MAAM,UAAU,kBAAkB,CAAC,IAAiB,EAAE,QAAiB;IACrE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CACR,uCAAuC,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC,MAAM,IAAI,CAC7E,CAAC;IACF,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IACH,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;QACnE,KAAK,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QACxE,IAAI,YAAY,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"plan-tool.js","sourceRoot":"","sources":["../../src/agent/plan-tool.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/runner.js
CHANGED
|
@@ -15,15 +15,15 @@ import { auditLog } from "../store/logs.js";
|
|
|
15
15
|
import { loadProjectContext } from "../store/project.js";
|
|
16
16
|
import { loadScope, isScopeActive, targetInScope } from "../store/scope.js";
|
|
17
17
|
import { ensureProviderConfigured } from "../commands/providers.js";
|
|
18
|
-
import { createThinkingStreamParser, rememberThinkingFromText, renderThinkingSummary, } from "../ui/thinking.js";
|
|
18
|
+
import { createThinkingStreamParser, rememberThinkingFromText, renderThinkingSummary, stripThinking, } from "../ui/thinking.js";
|
|
19
19
|
import { renderMarkdown, indentAndWrapText } from "../ui/markdown.js";
|
|
20
20
|
import { startThinkingSpinner } from "../ui/spinner.js";
|
|
21
21
|
import { safeCwd } from "../os/cwd.js";
|
|
22
22
|
import { analyzeTask } from "./task-analyzer.js";
|
|
23
23
|
import { LoopGuard } from "./loop-guard.js";
|
|
24
24
|
import { loadPlan } from "../store/plan.js";
|
|
25
|
-
import { pathInsideSandbox } from "../tools/fs.js";
|
|
26
|
-
import { stripSentinelTokens, parseToolCall, recognizeBareToolJson, looksLikeTruncatedToolCall, countToolFences, parseAllToolCalls, groupToolCallsForExecution, buildTurnHistory, collapseRepeatedText, textBeforeToolCall, formatToolArgs, looksLikePentestTask, looksLikeBuildTask, looksLikeInformationalQuery, looksLikeActionNarration, looksLikePlanNarration, requiresFreshWebSearch, freshnessGuardMessage, buildWorkflowDirective, pentestWorkflowDirective, shouldDimToolChatter, looksLikePromptLeak, } from "./tool-call-parser.js";
|
|
25
|
+
import { pathInsideSandbox, fsWrite } from "../tools/fs.js";
|
|
26
|
+
import { stripSentinelTokens, parseToolCall, recognizeBareToolJson, looksLikeTruncatedToolCall, salvageTruncatedWrite, countToolFences, parseAllToolCalls, groupToolCallsForExecution, buildTurnHistory, collapseRepeatedText, textBeforeToolCall, formatToolArgs, looksLikePentestTask, looksLikeBuildTask, looksLikeInformationalQuery, looksLikeActionNarration, looksLikePlanNarration, requiresFreshWebSearch, freshnessGuardMessage, buildWorkflowDirective, pentestWorkflowDirective, shouldDimToolChatter, looksLikePromptLeak, } from "./tool-call-parser.js";
|
|
27
27
|
import { createSessionPolicy, isPreApprovalAllowedTool, isPlanApprovedByStatus, planHasOpenWork, isAbortError, shouldEnableImageOcr, } from "./session-policy.js";
|
|
28
28
|
import { saveToolOutput, summarizeOutput, formatToolContext, } from "./tool-output-formatting.js";
|
|
29
29
|
import { planContextMessage, handlePlanTool, } from "./plan-tool.js";
|
|
@@ -488,19 +488,7 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
488
488
|
!isPreApprovalAllowedTool(call.name) &&
|
|
489
489
|
!isScratchOnlyWrite(call, scratchDir);
|
|
490
490
|
if (isMutatingAction) {
|
|
491
|
-
if (!
|
|
492
|
-
const reason = `No active plan — ${call.name} is blocked. You must first create a plan using plan.create before executing mutating actions.`;
|
|
493
|
-
writeNotice("warn", reason, chalk.yellow(` ⚠ ${reason}\n`));
|
|
494
|
-
const result = { ok: false, output: reason, exitCode: 1 };
|
|
495
|
-
return {
|
|
496
|
-
ok: false,
|
|
497
|
-
call,
|
|
498
|
-
result,
|
|
499
|
-
contextOutput: reason,
|
|
500
|
-
blockOrCancel: true,
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
if (!session.planApproved.value) {
|
|
491
|
+
if (activePlan && !session.planApproved.value) {
|
|
504
492
|
const reason = `plan awaiting approval — ${call.name} is blocked until you /implement (or /discard)`;
|
|
505
493
|
writeNotice("warn", reason, chalk.yellow(` ⚠ ${reason}\n`));
|
|
506
494
|
const result = { ok: false, output: reason, exitCode: 1 };
|
|
@@ -822,8 +810,8 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
822
810
|
// what is done, and what remains. The estimate is chars/4; the budget is
|
|
823
811
|
// deliberately conservative so we compact a little early rather than hit a
|
|
824
812
|
// provider context-window error mid-task.
|
|
825
|
-
const AUTO_COMPACT_TOKEN_BUDGET =
|
|
826
|
-
const AUTO_COMPACT_KEEP_RECENT =
|
|
813
|
+
const AUTO_COMPACT_TOKEN_BUDGET = 200_000;
|
|
814
|
+
const AUTO_COMPACT_KEEP_RECENT = 6;
|
|
827
815
|
let lastCompactionMsgCount = 0;
|
|
828
816
|
const summarizeForCompaction = async (summaryPrompt) => {
|
|
829
817
|
const response = await completeWithProvider({
|
|
@@ -868,10 +856,13 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
868
856
|
});
|
|
869
857
|
}
|
|
870
858
|
lastCompactionMsgCount = messages.length;
|
|
871
|
-
|
|
859
|
+
// Report the compacted token count BEFORE plan re-injection so the
|
|
860
|
+
// compaction stats accurately show the reduction. Then report the
|
|
861
|
+
// final count (which is what the model actually receives) separately.
|
|
862
|
+
const compactedTokens = estimateMessagesTokens(messages);
|
|
872
863
|
await auditLog("agent.compact", {
|
|
873
864
|
newLength: messages.length,
|
|
874
|
-
estimatedTokens:
|
|
865
|
+
estimatedTokens: compactedTokens,
|
|
875
866
|
reason,
|
|
876
867
|
});
|
|
877
868
|
// Extract the inserted compaction memory so we can surface the
|
|
@@ -883,8 +874,12 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
883
874
|
const summaryText = insertedSummary.startsWith(`${COMPACTION_MEMORY_PREFIX}\n\n`)
|
|
884
875
|
? insertedText(insertedSummary, `${COMPACTION_MEMORY_PREFIX}\n\n`)
|
|
885
876
|
: insertedText(insertedSummary, COMPACTION_MEMORY_PREFIX);
|
|
877
|
+
const afterTokens = estimateMessagesTokens(messages);
|
|
886
878
|
writeCompacted(summaryText, beforeTokens, afterTokens);
|
|
887
|
-
|
|
879
|
+
const planNote = afterTokens > compactedTokens
|
|
880
|
+
? ` (compacted to ~${compactedTokens.toLocaleString()}, +plan → ~${afterTokens.toLocaleString()})`
|
|
881
|
+
: "";
|
|
882
|
+
writeNotice("info", `context auto-compacted to fit the window (~${beforeTokens.toLocaleString()} → ~${afterTokens.toLocaleString()} tokens${planNote})`, chalk.dim(` ℹ context auto-compacted (~${beforeTokens.toLocaleString()} → ~${afterTokens.toLocaleString()} tokens${planNote})\n`));
|
|
888
883
|
}
|
|
889
884
|
catch (error) {
|
|
890
885
|
if (error instanceof Error &&
|
|
@@ -987,6 +982,10 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
987
982
|
let accumulatedText = "";
|
|
988
983
|
const callIds = [];
|
|
989
984
|
let streamedCallsCount = 0;
|
|
985
|
+
// Deferred tool-call events: collect tool calls parsed from the stream
|
|
986
|
+
// and emit them AFTER thinking + assistant text, so the display order
|
|
987
|
+
// is correct: thinking → model text → tool-call cards.
|
|
988
|
+
const deferredToolCalls = [];
|
|
990
989
|
const deltaParser = writesDirectly
|
|
991
990
|
? undefined
|
|
992
991
|
: createThinkingStreamParser((text) => emit({ type: "assistant-delta", text }), (text) => {
|
|
@@ -1032,7 +1031,17 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
1032
1031
|
callIds.push(eventId);
|
|
1033
1032
|
alreadyPrintedIds.add(eventId);
|
|
1034
1033
|
const toolCallLine = chalk.cyan(` ▶ ${call.name}`) + chalk.gray(` ${formatToolArgs(call)}`);
|
|
1035
|
-
writeToolCall
|
|
1034
|
+
// Defer the writeToolCall emission — collect it so we can
|
|
1035
|
+
// emit after thinking + assistant text for correct order.
|
|
1036
|
+
deferredToolCalls.push({
|
|
1037
|
+
eventId,
|
|
1038
|
+
call,
|
|
1039
|
+
rendered: styleToolChatter(call, toolCallLine) + "\n",
|
|
1040
|
+
});
|
|
1041
|
+
// Still update spinner label for user feedback during streaming.
|
|
1042
|
+
if (!writesDirectly) {
|
|
1043
|
+
emit({ type: "status", text: call.name });
|
|
1044
|
+
}
|
|
1036
1045
|
streamedCallsCount += 1;
|
|
1037
1046
|
}
|
|
1038
1047
|
if (writesDirectly) {
|
|
@@ -1141,7 +1150,7 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
1141
1150
|
}
|
|
1142
1151
|
messages.push({
|
|
1143
1152
|
role: "assistant",
|
|
1144
|
-
content: collapseRepeatedText(completion.text),
|
|
1153
|
+
content: stripThinking(collapseRepeatedText(completion.text)).visible,
|
|
1145
1154
|
});
|
|
1146
1155
|
// Keep nudges SHORT — cheap models lose the key instruction in long text.
|
|
1147
1156
|
const buildNudge = buildLikeTurn && !activePlan
|
|
@@ -1233,23 +1242,62 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
1233
1242
|
continue;
|
|
1234
1243
|
}
|
|
1235
1244
|
// Detect a tool call that opened but was cut off by the token limit
|
|
1236
|
-
// (most common with
|
|
1237
|
-
//
|
|
1238
|
-
//
|
|
1245
|
+
// (most common with large fs.write/fs.writeMany for reports).
|
|
1246
|
+
// Instead of asking the model to retry (which will just truncate
|
|
1247
|
+
// again at the same limit), we SALVAGE the partial content from the
|
|
1248
|
+
// truncated JSON and write it, then tell the model to CONTINUE with
|
|
1249
|
+
// fs.append from where it was cut off.
|
|
1239
1250
|
if (looksLikeTruncatedToolCall(assistantText.visible)) {
|
|
1240
1251
|
truncatedToolRetries += 1;
|
|
1252
|
+
// Try to salvage a partial fs.write / fs.append from the truncated JSON.
|
|
1253
|
+
// The pattern is: {"name":"fs.write","args":{"path":"...","content":"...
|
|
1254
|
+
// We extract the path and whatever content was produced before truncation.
|
|
1255
|
+
const salvaged = salvageTruncatedWrite(assistantText.visible);
|
|
1256
|
+
if (salvaged && truncatedToolRetries <= 5) {
|
|
1257
|
+
// Write the salvaged partial content
|
|
1258
|
+
try {
|
|
1259
|
+
const writeResult = await fsWrite(salvaged.path, salvaged.content, {
|
|
1260
|
+
confirmed: true,
|
|
1261
|
+
});
|
|
1262
|
+
if (writeResult.ok) {
|
|
1263
|
+
const lineCount = salvaged.content.split("\n").length;
|
|
1264
|
+
writeNotice("info", `tool call was truncated — salvaged ${lineCount} lines and wrote to ${salvaged.path}`, chalk.cyan(` ℹ tool call was truncated — salvaged ${lineCount} lines to ${salvaged.path}\n`));
|
|
1265
|
+
messages.push({
|
|
1266
|
+
role: "assistant",
|
|
1267
|
+
content: stripThinking(assistantText.visible).visible,
|
|
1268
|
+
});
|
|
1269
|
+
messages.push({
|
|
1270
|
+
role: "user",
|
|
1271
|
+
content: `Your fs.write tool call was cut off at the token limit, but the system salvaged the partial content and wrote ${lineCount} lines to ${salvaged.path}. ` +
|
|
1272
|
+
`The file now exists with content up to: "${salvaged.lastLine}"\n\n` +
|
|
1273
|
+
`CONTINUE writing the rest of the content using fs.append:\n` +
|
|
1274
|
+
'```tool\n{"name":"fs.append","args":{"path":"' + salvaged.path + '","content":"...remaining content..."}}\n```\n' +
|
|
1275
|
+
`Write the NEXT section of content starting from where it was cut off. ` +
|
|
1276
|
+
`Keep each fs.append call to ~100 lines max so it fits in the output window. ` +
|
|
1277
|
+
`Use multiple fs.append calls if needed. Do NOT re-write content that was already saved.`,
|
|
1278
|
+
});
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
catch {
|
|
1283
|
+
// Salvage failed — fall through to standard retry
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1241
1286
|
if (truncatedToolRetries <= 3) {
|
|
1242
1287
|
writeNotice("warn", "tool call was cut off (output too long) — asking the model to retry safely", chalk.yellow(" ⚠ tool call was cut off (output too long) — asking the model to retry safely\n"));
|
|
1243
1288
|
messages.push({
|
|
1244
1289
|
role: "assistant",
|
|
1245
|
-
content: assistantText.visible,
|
|
1290
|
+
content: stripThinking(assistantText.visible).visible,
|
|
1246
1291
|
});
|
|
1247
1292
|
messages.push({
|
|
1248
1293
|
role: "user",
|
|
1249
1294
|
content: "Your previous tool call was cut off before it finished — the JSON was incomplete, so NOTHING ran. " +
|
|
1250
|
-
"
|
|
1251
|
-
"
|
|
1252
|
-
"
|
|
1295
|
+
"Your output token limit is ~32k tokens. For LARGE files (reports, docs, long code), you MUST write in chunks:\n" +
|
|
1296
|
+
"1. Use fs.write to create the file with the FIRST ~100 lines\n" +
|
|
1297
|
+
"2. Use fs.append to add the NEXT ~100 lines\n" +
|
|
1298
|
+
"3. Repeat fs.append for each remaining section\n" +
|
|
1299
|
+
"Keep your reasoning SHORT — emit the ```tool block as early as possible to maximize content space. " +
|
|
1300
|
+
"Do NOT try to write the entire file in one call. Do NOT claim any file was written until a tool call actually succeeds.",
|
|
1253
1301
|
});
|
|
1254
1302
|
continue;
|
|
1255
1303
|
}
|
|
@@ -1267,19 +1315,51 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
1267
1315
|
const hasFencedCallShape = countToolFences(assistantText.visible) > 0 &&
|
|
1268
1316
|
/```tool\s*\n[\s\S]*?"(?:name|args)"\s*:/i.test(assistantText.visible);
|
|
1269
1317
|
if (hasFencedCallShape) {
|
|
1318
|
+
// Before treating as a generic malformed fence, check if this is
|
|
1319
|
+
// actually a truncated write call that should be salvaged.
|
|
1320
|
+
const salvaged = salvageTruncatedWrite(assistantText.visible);
|
|
1321
|
+
if (salvaged) {
|
|
1322
|
+
try {
|
|
1323
|
+
const writeResult = await fsWrite(salvaged.path, salvaged.content, {
|
|
1324
|
+
confirmed: true,
|
|
1325
|
+
});
|
|
1326
|
+
if (writeResult.ok) {
|
|
1327
|
+
const lineCount = salvaged.content.split("\n").length;
|
|
1328
|
+
writeNotice("info", `malformed tool call salvaged — wrote ${lineCount} lines to ${salvaged.path}`, chalk.cyan(` ℹ malformed tool call salvaged — wrote ${lineCount} lines to ${salvaged.path}\n`));
|
|
1329
|
+
messages.push({
|
|
1330
|
+
role: "assistant",
|
|
1331
|
+
content: stripThinking(assistantText.visible).visible,
|
|
1332
|
+
});
|
|
1333
|
+
messages.push({
|
|
1334
|
+
role: "user",
|
|
1335
|
+
content: `The system extracted and wrote ${lineCount} lines to ${salvaged.path} from your malformed tool call. ` +
|
|
1336
|
+
`The file content ends at: "${salvaged.lastLine}"\n\n` +
|
|
1337
|
+
`If the file is complete, proceed with the next step. ` +
|
|
1338
|
+
`If more content is needed, use fs.append to add the remaining sections (~100 lines per call).`,
|
|
1339
|
+
});
|
|
1340
|
+
continue;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
catch {
|
|
1344
|
+
// Salvage failed — fall through to standard malformed retry
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1270
1347
|
malformedFenceRetries += 1;
|
|
1271
1348
|
if (malformedFenceRetries <= 3) {
|
|
1272
1349
|
writeNotice("warn", "tool block present but its JSON didn't parse — asking the model to re-emit valid JSON", chalk.yellow(" ⚠ tool block present but its JSON didn't parse — asking the model to re-emit valid JSON\n"));
|
|
1273
1350
|
messages.push({
|
|
1274
1351
|
role: "assistant",
|
|
1275
|
-
content: assistantText.visible,
|
|
1352
|
+
content: stripThinking(assistantText.visible).visible,
|
|
1276
1353
|
});
|
|
1277
1354
|
messages.push({
|
|
1278
1355
|
role: "user",
|
|
1279
1356
|
content: "Your previous message contained a ```tool block, but its JSON was INVALID, so NOTHING ran. " +
|
|
1280
|
-
"Common causes: an extra or missing `}` / `]`,
|
|
1357
|
+
"Common causes: unescaped newlines or quotes inside a string value, an extra or missing `}` / `]`, or content too large for the output window. " +
|
|
1281
1358
|
'Re-emit ONE valid ```tool block of the exact form {"name":"<tool>","args":{...}} with balanced braces. ' +
|
|
1282
|
-
"
|
|
1359
|
+
"IMPORTANT: For large file content (reports, docs), write in chunks:\n" +
|
|
1360
|
+
"1. fs.write with the FIRST ~100 lines only\n" +
|
|
1361
|
+
"2. fs.append for each subsequent ~100-line section\n" +
|
|
1362
|
+
"Keep reasoning SHORT to maximize output space for the tool call JSON. " +
|
|
1283
1363
|
"Do NOT claim any file was written until a tool call actually succeeds.",
|
|
1284
1364
|
});
|
|
1285
1365
|
continue;
|
|
@@ -1484,6 +1564,11 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
1484
1564
|
if (beforeTool) {
|
|
1485
1565
|
writeAssistantMessage(beforeTool);
|
|
1486
1566
|
}
|
|
1567
|
+
// Now emit deferred tool-call events (collected during streaming)
|
|
1568
|
+
// so the display order is: thinking → text → tool-call cards.
|
|
1569
|
+
for (const deferred of deferredToolCalls) {
|
|
1570
|
+
writeToolCall(deferred.eventId, deferred.call, deferred.rendered);
|
|
1571
|
+
}
|
|
1487
1572
|
let allCalls = parseAllToolCalls(assistantText.visible || assistantText.thinkContent);
|
|
1488
1573
|
if (allCalls.length === 0 && call) {
|
|
1489
1574
|
allCalls = [call];
|
|
@@ -1539,6 +1624,10 @@ export async function runAgentLoop(prompt, options = {}) {
|
|
|
1539
1624
|
content: `Tool ${res.call.name} result (exit=${res.result.exitCode ?? 0}, ok=${res.result.ok}):\n${res.contextOutput}`,
|
|
1540
1625
|
});
|
|
1541
1626
|
productiveSteps += 1;
|
|
1627
|
+
// Reset retry counters — they track consecutive failures, not cumulative.
|
|
1628
|
+
truncatedToolRetries = 0;
|
|
1629
|
+
malformedFenceRetries = 0;
|
|
1630
|
+
bareToolJsonRetries = 0;
|
|
1542
1631
|
if (res.ok && res.call.name === "shell.start")
|
|
1543
1632
|
sawServerStart = true;
|
|
1544
1633
|
if (res.ok && res.call.name === "shell.tail")
|