@oh-my-pi/pi-coding-agent 13.9.6 → 13.9.11
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/CHANGELOG.md +31 -0
- package/package.json +7 -7
- package/src/modes/components/tool-execution.ts +9 -5
- package/src/modes/controllers/event-controller.ts +8 -2
- package/src/modes/utils/ui-helpers.ts +5 -1
- package/src/prompts/agents/explore.md +1 -0
- package/src/prompts/agents/librarian.md +2 -0
- package/src/prompts/system/handoff-document.md +46 -0
- package/src/prompts/system/subagent-system-prompt.md +3 -9
- package/src/prompts/system/system-prompt.md +2 -1
- package/src/prompts/tools/bash.md +2 -0
- package/src/session/agent-session.ts +55 -59
- package/src/tools/bash.ts +147 -7
- package/src/tools/fetch.ts +47 -30
- package/src/web/scrapers/docs-rs.ts +653 -0
- package/src/web/scrapers/index.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [13.9.10] - 2026-03-08
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- Added `env` parameter to bash tool to pass environment variables safely without shell re-parsing, preventing quote and special character bugs with multiline or untrusted values
|
|
9
|
+
- Added support for rendering partial `env` assignments in command preview while tool arguments are still streaming
|
|
10
|
+
- Added `env` support to the bash tool so commands can reference safe shell variables without inline quoting bugs for multiline or quote-heavy values
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Changed bash tool to display environment variable assignments in command preview when `env` parameter is used
|
|
15
|
+
|
|
16
|
+
## [13.9.8] - 2026-03-08
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- Added docs.rs scraper for extracting Rust crate documentation from rustdoc JSON, including support for modules, functions, structs, traits, enums, and other Rust items with caching
|
|
20
|
+
|
|
21
|
+
## [13.9.7] - 2026-03-08
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Added `skipPostPromptRecoveryWait` option to handoff operations to defer recovery work until after handoff completion
|
|
26
|
+
- Added deferred auto-compaction scheduling to allow threshold-triggered handoffs to complete while the original prompt is still unwinding
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Extracted handoff document template to dedicated prompt file for improved maintainability and template variable support
|
|
31
|
+
- Changed handoff prompt generation to use template rendering with support for custom focus instructions
|
|
32
|
+
- Refactored internal prompt-in-flight tracking from boolean flag to counter to properly handle nested prompt operations
|
|
33
|
+
- Moved llms.txt endpoint discovery to fallback strategy when rendered page content is low quality, prioritizing page-specific content over site-wide files
|
|
34
|
+
- Enhanced llms.txt endpoint detection to scope candidates to the requested URL path, searching section-specific files before site-wide ones
|
|
35
|
+
|
|
5
36
|
## [13.9.6] - 2026-03-08
|
|
6
37
|
|
|
7
38
|
### Added
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "13.9.
|
|
4
|
+
"version": "13.9.11",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@mozilla/readability": "^0.6",
|
|
44
|
-
"@oh-my-pi/omp-stats": "13.9.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "13.9.
|
|
46
|
-
"@oh-my-pi/pi-ai": "13.9.
|
|
47
|
-
"@oh-my-pi/pi-natives": "13.9.
|
|
48
|
-
"@oh-my-pi/pi-tui": "13.9.
|
|
49
|
-
"@oh-my-pi/pi-utils": "13.9.
|
|
44
|
+
"@oh-my-pi/omp-stats": "13.9.11",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "13.9.11",
|
|
46
|
+
"@oh-my-pi/pi-ai": "13.9.11",
|
|
47
|
+
"@oh-my-pi/pi-natives": "13.9.11",
|
|
48
|
+
"@oh-my-pi/pi-tui": "13.9.11",
|
|
49
|
+
"@oh-my-pi/pi-utils": "13.9.11",
|
|
50
50
|
"@sinclair/typebox": "^0.34",
|
|
51
51
|
"@xterm/headless": "^6.0",
|
|
52
52
|
"ajv": "^8.18",
|
|
@@ -478,7 +478,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
478
478
|
},
|
|
479
479
|
this.#renderState,
|
|
480
480
|
theme,
|
|
481
|
-
this.#
|
|
481
|
+
this.#getCallArgsForRender(),
|
|
482
482
|
);
|
|
483
483
|
if (resultComponent) {
|
|
484
484
|
this.#contentBox.addChild(ensureInvalidate(resultComponent));
|
|
@@ -560,10 +560,14 @@ export class ToolExecutionComponent extends Container {
|
|
|
560
560
|
return Math.max(1, Math.min(maxSeconds, value));
|
|
561
561
|
};
|
|
562
562
|
|
|
563
|
-
if (this.#toolName === "bash"
|
|
564
|
-
//
|
|
565
|
-
|
|
566
|
-
|
|
563
|
+
if (this.#toolName === "bash") {
|
|
564
|
+
// Bash needs render context even before a result exists. The renderer uses the pending-call args
|
|
565
|
+
// plus this context to keep the inline command preview visible while tool-call JSON is still streaming.
|
|
566
|
+
if (this.#result) {
|
|
567
|
+
// Pass raw output and expanded state - renderer handles width-aware truncation
|
|
568
|
+
const output = this.#getTextOutput().trimEnd();
|
|
569
|
+
context.output = output;
|
|
570
|
+
}
|
|
567
571
|
context.expanded = this.#expanded;
|
|
568
572
|
context.previewLines = BASH_DEFAULT_PREVIEW_LINES;
|
|
569
573
|
context.timeout = normalizeTimeoutSeconds(this.#args?.timeout, 3600);
|
|
@@ -184,13 +184,19 @@ export class EventController {
|
|
|
184
184
|
continue;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
// Preserve the raw partial JSON for renderers that need to surface fields before the JSON object closes.
|
|
188
|
+
// Bash uses this to show inline env assignments during streaming instead of popping them in at completion.
|
|
189
|
+
const renderArgs =
|
|
190
|
+
"partialJson" in content
|
|
191
|
+
? { ...content.arguments, __partialJson: content.partialJson }
|
|
192
|
+
: content.arguments;
|
|
187
193
|
if (!this.ctx.pendingTools.has(content.id)) {
|
|
188
194
|
this.#resetReadGroup();
|
|
189
195
|
this.ctx.chatContainer.addChild(new Text("", 0, 0));
|
|
190
196
|
const tool = this.ctx.session.getToolByName(content.name);
|
|
191
197
|
const component = new ToolExecutionComponent(
|
|
192
198
|
content.name,
|
|
193
|
-
|
|
199
|
+
renderArgs,
|
|
194
200
|
{
|
|
195
201
|
showImages: settings.get("terminal.showImages"),
|
|
196
202
|
editFuzzyThreshold: settings.get("edit.fuzzyThreshold"),
|
|
@@ -206,7 +212,7 @@ export class EventController {
|
|
|
206
212
|
} else {
|
|
207
213
|
const component = this.ctx.pendingTools.get(content.id);
|
|
208
214
|
if (component) {
|
|
209
|
-
component.updateArgs(
|
|
215
|
+
component.updateArgs(renderArgs, content.id);
|
|
210
216
|
}
|
|
211
217
|
}
|
|
212
218
|
}
|
|
@@ -272,9 +272,13 @@ export class UiHelpers {
|
|
|
272
272
|
|
|
273
273
|
readGroup = null;
|
|
274
274
|
const tool = this.ctx.session.getToolByName(content.name);
|
|
275
|
+
const renderArgs =
|
|
276
|
+
"partialJson" in content
|
|
277
|
+
? { ...content.arguments, __partialJson: content.partialJson }
|
|
278
|
+
: content.arguments;
|
|
275
279
|
const component = new ToolExecutionComponent(
|
|
276
280
|
content.name,
|
|
277
|
-
|
|
281
|
+
renderArgs,
|
|
278
282
|
{
|
|
279
283
|
showImages: settings.get("terminal.showImages"),
|
|
280
284
|
editFuzzyThreshold: settings.get("edit.fuzzyThreshold"),
|
|
@@ -99,6 +99,7 @@ Given a task, you rapidly investigate the codebase and return structured finding
|
|
|
99
99
|
<directives>
|
|
100
100
|
- You **MUST** use tools for broad pattern matching / code search as much as possible.
|
|
101
101
|
- You **SHOULD** invoke tools in parallel when possible—this is a short investigation, and you are supposed to finish in a few seconds.
|
|
102
|
+
- If a search returns empty results, you **MUST** try at least one alternate strategy (different pattern, broader path, or AST search) before concluding the target doesn't exist.
|
|
102
103
|
</directives>
|
|
103
104
|
|
|
104
105
|
<thoroughness>
|
|
@@ -111,6 +111,8 @@ Before acting, determine what kind of question this is:
|
|
|
111
111
|
- If you discover undocumented behavior or gotchas, you **MUST** populate `caveats`.
|
|
112
112
|
- When local `node_modules` has the package, you **SHOULD** prefer it over cloning — it reflects the version the project actually uses.
|
|
113
113
|
- You **SHOULD** use `web_search` to find the canonical repo URL and to check for known issues, but the definitive answer **MUST** come from reading source code.
|
|
114
|
+
- If a search or lookup returns empty or unexpectedly few results, you **MUST** try at least 2 fallback strategies (broader query, alternate path, different source) before concluding nothing exists.
|
|
115
|
+
- If the package is absent from local `node_modules` and cloning fails, you **MUST** fall back to `web_search` for official API documentation before reporting failure.
|
|
114
116
|
</directives>
|
|
115
117
|
|
|
116
118
|
<critical>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<critical>
|
|
2
|
+
Write a comprehensive handoff document for another instance of yourself.
|
|
3
|
+
The handoff **MUST** be sufficient for seamless continuation without access to this conversation.
|
|
4
|
+
Output ONLY the handoff document. No preamble, no commentary, no wrapper text.
|
|
5
|
+
</critical>
|
|
6
|
+
|
|
7
|
+
<instruction>
|
|
8
|
+
Capture exact technical state, not abstractions.
|
|
9
|
+
Include concrete file paths, symbol names, commands run, test results, observed failures, decisions made, and any partial work that materially affects the next step.
|
|
10
|
+
</instruction>
|
|
11
|
+
|
|
12
|
+
<output>
|
|
13
|
+
Use exactly this structure:
|
|
14
|
+
|
|
15
|
+
## Goal
|
|
16
|
+
[What the user is trying to accomplish]
|
|
17
|
+
|
|
18
|
+
## Constraints & Preferences
|
|
19
|
+
- [Any constraints, preferences, or requirements mentioned]
|
|
20
|
+
|
|
21
|
+
## Progress
|
|
22
|
+
### Done
|
|
23
|
+
- [x] [Completed tasks with specifics]
|
|
24
|
+
|
|
25
|
+
### In Progress
|
|
26
|
+
- [ ] [Current work if any]
|
|
27
|
+
|
|
28
|
+
### Pending
|
|
29
|
+
- [ ] [Tasks mentioned but not started]
|
|
30
|
+
|
|
31
|
+
## Key Decisions
|
|
32
|
+
- **[Decision]**: [Rationale]
|
|
33
|
+
|
|
34
|
+
## Critical Context
|
|
35
|
+
- [Code snippets, file paths, function/type names, error messages, or data essential to continue]
|
|
36
|
+
- [Repository state if relevant]
|
|
37
|
+
|
|
38
|
+
## Next Steps
|
|
39
|
+
1. [What should happen next]
|
|
40
|
+
</output>
|
|
41
|
+
|
|
42
|
+
{{#if additionalFocus}}
|
|
43
|
+
<instruction>
|
|
44
|
+
Additional focus: {{additionalFocus}}
|
|
45
|
+
</instruction>
|
|
46
|
+
{{/if}}
|
|
@@ -29,13 +29,7 @@ Your result **MUST** match this TypeScript interface:
|
|
|
29
29
|
{{/if}}
|
|
30
30
|
|
|
31
31
|
{{SECTION_SEPERATOR "Giving Up"}}
|
|
32
|
-
|
|
32
|
+
Giving up is a last resort. If truly blocked, you **MUST** call `submit_result` exactly once with `result.error` describing what you tried and the exact blocker.
|
|
33
|
+
You **MUST NOT** give up due to uncertainty, missing information obtainable via tools or repo context, or needing a design decision you can derive yourself.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
You **MUST NOT** give up due to uncertainty or missing information obtainable via tools or repo context.
|
|
36
|
-
You **MUST NOT** give up due to requiring a design, you can derive that yourself, more than capable of that.
|
|
37
|
-
|
|
38
|
-
Proceed with the best approach using the most reasonable option.
|
|
39
|
-
|
|
40
|
-
You **MUST** keep going until this ticket is closed.
|
|
41
|
-
This matters.
|
|
35
|
+
You **MUST** keep going until this ticket is closed. This matters.
|
|
@@ -313,8 +313,9 @@ Today is '{{date}}', and your work begins now. Get it right.
|
|
|
313
313
|
- You **MUST** use the most specialized tool, **NEVER** `cat` if there's tool.bash, `rg/grep`:tool.grep, `find`:tool.find, `sed`:tool.edit…
|
|
314
314
|
- Every turn **MUST** materially advance the deliverable.
|
|
315
315
|
- You **MUST** default to action. You **MUST NOT** ask for confirmation to continue work. If you hit an error, you **MUST** fix it. If you know the next step, you **MUST** take it. The user will intervene if needed.
|
|
316
|
-
- You **MUST NOT** make speculative edits before understanding the surrounding design.
|
|
317
316
|
- You **MUST** default to informed action. You **MUST NOT** ask for confirmation to continue work. If you hit an error, you **MUST** fix it. If you know the next step, you **MUST** take it. The user will intervene if needed.
|
|
317
|
+
- You **MUST NOT** make speculative edits before understanding the surrounding design.
|
|
318
|
+
- You **MUST NOT** stop calling tools to save round-trips when the task is incomplete. Completeness beats efficiency.
|
|
318
319
|
- You **MUST NOT** ask when the answer may be obtained from available tools or repo context/files.
|
|
319
320
|
- You **MUST** verify the effect. When a task involves a behavioral change, you **MUST** confirm the change is observable before yielding: run the specific test, command, or scenario that covers your change.
|
|
320
321
|
</critical>
|
|
@@ -2,6 +2,8 @@ Executes bash command in shell session for terminal operations like git, bun, ca
|
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
4
|
- You **MUST** use `cwd` parameter to set working directory instead of `cd dir && …`
|
|
5
|
+
- Prefer `env: { NAME: "…" }` for multiline, quote-heavy, or untrusted values instead of inlining them into shell syntax; reference them from the command as `$NAME`
|
|
6
|
+
- Quote variable expansions like `"$NAME"` to preserve exact content and avoid shell parsing bugs
|
|
5
7
|
- PTY mode is opt-in: set `pty: true` only when command expects a real terminal (for example `sudo`, `ssh` where you need input from the user); default is `false`
|
|
6
8
|
- You **MUST** use `;` only when later commands should run regardless of earlier failures
|
|
7
9
|
- `skill://` URIs are auto-resolved to filesystem paths before execution
|
|
@@ -89,6 +89,7 @@ import { getCurrentThemeName, theme } from "../modes/theme/theme";
|
|
|
89
89
|
import { normalizeDiff, normalizeToLF, ParseError, previewPatch, stripBom } from "../patch";
|
|
90
90
|
import type { PlanModeState } from "../plan-mode/state";
|
|
91
91
|
import autoHandoffThresholdFocusPrompt from "../prompts/system/auto-handoff-threshold-focus.md" with { type: "text" };
|
|
92
|
+
import handoffDocumentPrompt from "../prompts/system/handoff-document.md" with { type: "text" };
|
|
92
93
|
import planModeActivePrompt from "../prompts/system/plan-mode-active.md" with { type: "text" };
|
|
93
94
|
import planModeReferencePrompt from "../prompts/system/plan-mode-reference.md" with { type: "text" };
|
|
94
95
|
import planModeToolDecisionReminderPrompt from "../prompts/system/plan-mode-tool-decision-reminder.md" with {
|
|
@@ -260,6 +261,7 @@ export interface HandoffResult {
|
|
|
260
261
|
interface HandoffOptions {
|
|
261
262
|
autoTriggered?: boolean;
|
|
262
263
|
signal?: AbortSignal;
|
|
264
|
+
skipPostPromptRecoveryWait?: boolean;
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
/** Internal marker for hook messages queued through the agent loop */
|
|
@@ -397,7 +399,7 @@ export class AgentSession {
|
|
|
397
399
|
#streamingEditAbortTriggered = false;
|
|
398
400
|
#streamingEditCheckedLineCounts = new Map<string, number>();
|
|
399
401
|
#streamingEditFileCache = new Map<string, string>();
|
|
400
|
-
#
|
|
402
|
+
#promptInFlightCount = 0;
|
|
401
403
|
#obfuscator: SecretObfuscator | undefined;
|
|
402
404
|
#pendingActionStore: PendingActionStore | undefined;
|
|
403
405
|
#checkpointState: CheckpointState | undefined = undefined;
|
|
@@ -1560,7 +1562,7 @@ export class AgentSession {
|
|
|
1560
1562
|
|
|
1561
1563
|
/** Whether agent is currently streaming a response */
|
|
1562
1564
|
get isStreaming(): boolean {
|
|
1563
|
-
return this.agent.state.isStreaming || this.#
|
|
1565
|
+
return this.agent.state.isStreaming || this.#promptInFlightCount > 0;
|
|
1564
1566
|
}
|
|
1565
1567
|
|
|
1566
1568
|
/** Wait until streaming and deferred recovery work are fully settled. */
|
|
@@ -1999,7 +2001,7 @@ export class AgentSession {
|
|
|
1999
2001
|
skipPostPromptRecoveryWait?: boolean;
|
|
2000
2002
|
},
|
|
2001
2003
|
): Promise<void> {
|
|
2002
|
-
this.#
|
|
2004
|
+
this.#promptInFlightCount++;
|
|
2003
2005
|
const generation = this.#promptGeneration;
|
|
2004
2006
|
try {
|
|
2005
2007
|
// Flush any pending bash messages before the new prompt
|
|
@@ -2109,7 +2111,7 @@ export class AgentSession {
|
|
|
2109
2111
|
await this.#waitForPostPromptRecovery();
|
|
2110
2112
|
}
|
|
2111
2113
|
} finally {
|
|
2112
|
-
this.#
|
|
2114
|
+
this.#promptInFlightCount = Math.max(0, this.#promptInFlightCount - 1);
|
|
2113
2115
|
}
|
|
2114
2116
|
}
|
|
2115
2117
|
|
|
@@ -2508,11 +2510,10 @@ export class AgentSession {
|
|
|
2508
2510
|
this.#cancelPostPromptTasks();
|
|
2509
2511
|
this.agent.abort();
|
|
2510
2512
|
await this.agent.waitForIdle();
|
|
2511
|
-
// Clear
|
|
2512
|
-
// block runs
|
|
2513
|
-
//
|
|
2514
|
-
|
|
2515
|
-
this.#promptInFlight = false;
|
|
2513
|
+
// Clear prompt-in-flight state: waitForIdle resolves when the agent loop's finally
|
|
2514
|
+
// block runs, but nested prompt setup/finalizers may still be unwinding. Without this,
|
|
2515
|
+
// a subsequent prompt() can incorrectly observe the session as busy after an abort.
|
|
2516
|
+
this.#promptInFlightCount = 0;
|
|
2516
2517
|
}
|
|
2517
2518
|
|
|
2518
2519
|
/**
|
|
@@ -3194,41 +3195,9 @@ export class AgentSession {
|
|
|
3194
3195
|
}
|
|
3195
3196
|
|
|
3196
3197
|
// Build the handoff prompt
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
## Goal
|
|
3202
|
-
[What the user is trying to accomplish]
|
|
3203
|
-
|
|
3204
|
-
## Constraints & Preferences
|
|
3205
|
-
- [Any constraints, preferences, or requirements mentioned]
|
|
3206
|
-
|
|
3207
|
-
## Progress
|
|
3208
|
-
### Done
|
|
3209
|
-
- [x] [Completed tasks with specifics]
|
|
3210
|
-
|
|
3211
|
-
### In Progress
|
|
3212
|
-
- [ ] [Current work if any]
|
|
3213
|
-
|
|
3214
|
-
### Pending
|
|
3215
|
-
- [ ] [Tasks mentioned but not started]
|
|
3216
|
-
|
|
3217
|
-
## Key Decisions
|
|
3218
|
-
- **[Decision]**: [Rationale]
|
|
3219
|
-
|
|
3220
|
-
## Critical Context
|
|
3221
|
-
- [Code snippets, file paths, error messages, or data essential to continue]
|
|
3222
|
-
- [Repository state if relevant]
|
|
3223
|
-
|
|
3224
|
-
## Next Steps
|
|
3225
|
-
1. [What should happen next]
|
|
3226
|
-
|
|
3227
|
-
Be thorough - include exact file paths, function names, error messages, and technical details. Output ONLY the handoff document, no other text.`;
|
|
3228
|
-
|
|
3229
|
-
if (customInstructions) {
|
|
3230
|
-
handoffPrompt += `\n\nAdditional focus: ${customInstructions}`;
|
|
3231
|
-
}
|
|
3198
|
+
const handoffPrompt = renderPromptTemplate(handoffDocumentPrompt, {
|
|
3199
|
+
additionalFocus: customInstructions,
|
|
3200
|
+
});
|
|
3232
3201
|
|
|
3233
3202
|
// Create a promise that resolves when the agent completes
|
|
3234
3203
|
let handoffText: string | undefined;
|
|
@@ -3273,11 +3242,16 @@ Be thorough - include exact file paths, function names, error messages, and tech
|
|
|
3273
3242
|
if (handoffSignal.aborted) {
|
|
3274
3243
|
throw new Error("Handoff cancelled");
|
|
3275
3244
|
}
|
|
3276
|
-
await this
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3245
|
+
await this.#promptWithMessage(
|
|
3246
|
+
{
|
|
3247
|
+
role: "developer",
|
|
3248
|
+
content: [{ type: "text", text: handoffPrompt }],
|
|
3249
|
+
attribution: "agent",
|
|
3250
|
+
timestamp: Date.now(),
|
|
3251
|
+
},
|
|
3252
|
+
handoffPrompt,
|
|
3253
|
+
{ skipCompactionCheck: true, skipPostPromptRecoveryWait: options?.skipPostPromptRecoveryWait },
|
|
3254
|
+
);
|
|
3281
3255
|
await completionPromise;
|
|
3282
3256
|
|
|
3283
3257
|
if (handoffCancelled || handoffSignal.aborted) {
|
|
@@ -3730,11 +3704,22 @@ Be thorough - include exact file paths, function names, error messages, and tech
|
|
|
3730
3704
|
/**
|
|
3731
3705
|
* Internal: Run auto-compaction with events.
|
|
3732
3706
|
*/
|
|
3733
|
-
async #runAutoCompaction(reason: "overflow" | "threshold", willRetry: boolean): Promise<void> {
|
|
3707
|
+
async #runAutoCompaction(reason: "overflow" | "threshold", willRetry: boolean, deferred = false): Promise<void> {
|
|
3734
3708
|
const compactionSettings = this.settings.getGroup("compaction");
|
|
3735
|
-
|
|
3736
3709
|
if (!compactionSettings.enabled || compactionSettings.strategy === "off") return;
|
|
3737
3710
|
const generation = this.#promptGeneration;
|
|
3711
|
+
if (!deferred && reason !== "overflow" && compactionSettings.strategy === "handoff") {
|
|
3712
|
+
this.#schedulePostPromptTask(
|
|
3713
|
+
async signal => {
|
|
3714
|
+
await Promise.resolve();
|
|
3715
|
+
if (signal.aborted) return;
|
|
3716
|
+
await this.#runAutoCompaction(reason, willRetry, true);
|
|
3717
|
+
},
|
|
3718
|
+
{ generation },
|
|
3719
|
+
);
|
|
3720
|
+
return;
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3738
3723
|
let action: "context-full" | "handoff" =
|
|
3739
3724
|
compactionSettings.strategy === "handoff" && reason !== "overflow" ? "handoff" : "context-full";
|
|
3740
3725
|
await this.#emitSessionEvent({ type: "auto_compaction_start", reason, action });
|
|
@@ -3750,6 +3735,7 @@ Be thorough - include exact file paths, function names, error messages, and tech
|
|
|
3750
3735
|
const handoffResult = await this.handoff(handoffFocus, {
|
|
3751
3736
|
autoTriggered: true,
|
|
3752
3737
|
signal: this.#autoCompactionAbortController.signal,
|
|
3738
|
+
skipPostPromptRecoveryWait: true,
|
|
3753
3739
|
});
|
|
3754
3740
|
if (!handoffResult) {
|
|
3755
3741
|
const aborted = this.#autoCompactionAbortController.signal.aborted;
|
|
@@ -4028,15 +4014,25 @@ Be thorough - include exact file paths, function names, error messages, and tech
|
|
|
4028
4014
|
await this.#emitSessionEvent({ type: "auto_compaction_end", action, result, aborted: false, willRetry });
|
|
4029
4015
|
|
|
4030
4016
|
if (!willRetry && compactionSettings.autoContinue !== false) {
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4017
|
+
const continuePrompt = async () => {
|
|
4018
|
+
await this.#promptWithMessage(
|
|
4019
|
+
{
|
|
4020
|
+
role: "developer",
|
|
4021
|
+
content: [{ type: "text", text: "Continue if you have next steps." }],
|
|
4022
|
+
attribution: "agent",
|
|
4023
|
+
timestamp: Date.now(),
|
|
4024
|
+
},
|
|
4025
|
+
"Continue if you have next steps.",
|
|
4026
|
+
{ skipPostPromptRecoveryWait: true },
|
|
4027
|
+
);
|
|
4028
|
+
};
|
|
4029
|
+
this.#schedulePostPromptTask(
|
|
4030
|
+
async signal => {
|
|
4031
|
+
await Promise.resolve();
|
|
4032
|
+
if (signal.aborted) return;
|
|
4033
|
+
await continuePrompt();
|
|
4037
4034
|
},
|
|
4038
|
-
|
|
4039
|
-
{ skipPostPromptRecoveryWait: true },
|
|
4035
|
+
{ generation },
|
|
4040
4036
|
);
|
|
4041
4037
|
}
|
|
4042
4038
|
|