@nghyane/arcane 0.1.29 → 0.1.30
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/package.json +4 -4
- package/src/cli/config-cli.ts +1 -1
- package/src/config/settings-schema.ts +19 -27
- package/src/config/settings.ts +3 -4
- package/src/extensibility/custom-tools/types.ts +0 -12
- package/src/extensibility/extensions/index.ts +0 -5
- package/src/extensibility/extensions/runner.ts +6 -26
- package/src/extensibility/extensions/types.ts +1 -77
- package/src/extensibility/hooks/runner.ts +5 -24
- package/src/extensibility/hooks/types.ts +1 -77
- package/src/index.ts +2 -13
- package/src/modes/components/footer.ts +4 -11
- package/src/modes/components/index.ts +0 -1
- package/src/modes/components/status-line/segments.ts +1 -2
- package/src/modes/components/status-line/types.ts +0 -1
- package/src/modes/components/status-line.ts +0 -6
- package/src/modes/components/tree-selector.ts +0 -8
- package/src/modes/controllers/command-controller.ts +2 -98
- package/src/modes/controllers/event-controller.ts +46 -52
- package/src/modes/controllers/extension-ui-controller.ts +0 -42
- package/src/modes/controllers/input-controller.ts +0 -23
- package/src/modes/controllers/selector-controller.ts +0 -5
- package/src/modes/interactive-mode.ts +3 -24
- package/src/modes/print-mode.ts +0 -16
- package/src/modes/rpc/rpc-client.ts +0 -16
- package/src/modes/rpc/rpc-mode.ts +0 -32
- package/src/modes/rpc/rpc-types.ts +0 -9
- package/src/modes/types.ts +1 -13
- package/src/modes/utils/ui-helpers.ts +2 -118
- package/src/sdk.ts +0 -15
- package/src/session/agent-session.ts +89 -650
- package/src/session/compaction/branch-summarization.ts +5 -13
- package/src/session/compaction/index.ts +0 -1
- package/src/session/compaction/utils.ts +94 -2
- package/src/session/messages.ts +0 -37
- package/src/session/retry-utils.ts +1 -1
- package/src/session/session-manager.ts +8 -108
- package/src/session/session-types.ts +4 -25
- package/src/session/stats.ts +2 -39
- package/src/slash-commands/builtin-registry.ts +0 -11
- package/src/task/executor.ts +0 -8
- package/examples/hooks/custom-compaction.ts +0 -116
- package/src/modes/components/compaction-summary-message.ts +0 -59
- package/src/prompts/compaction/compaction-short-summary.md +0 -9
- package/src/prompts/compaction/compaction-summary-context.md +0 -5
- package/src/prompts/compaction/compaction-summary.md +0 -41
- package/src/prompts/compaction/compaction-turn-prefix.md +0 -17
- package/src/prompts/compaction/compaction-update-summary.md +0 -45
- package/src/session/compaction/compaction.ts +0 -864
- package/src/session/compaction/pruning.ts +0 -91
package/src/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { ModelRegistry } from "./config/model-registry";
|
|
|
13
13
|
// Prompt templates
|
|
14
14
|
export type { PromptTemplate } from "./config/prompt-templates";
|
|
15
15
|
export { renderPromptTemplate } from "./config/prompt-templates";
|
|
16
|
-
export type {
|
|
16
|
+
export type { RetrySettings, SkillsSettings } from "./config/settings";
|
|
17
17
|
export { Settings, settings } from "./config/settings";
|
|
18
18
|
// Custom commands
|
|
19
19
|
export type {
|
|
@@ -114,7 +114,6 @@ export {
|
|
|
114
114
|
BashExecutionComponent,
|
|
115
115
|
BorderedLoader,
|
|
116
116
|
BranchSummaryMessageComponent,
|
|
117
|
-
CompactionSummaryMessageComponent,
|
|
118
117
|
CustomEditor,
|
|
119
118
|
CustomMessageComponent,
|
|
120
119
|
DynamicBorder,
|
|
@@ -181,39 +180,29 @@ export {
|
|
|
181
180
|
} from "./session/agent-session";
|
|
182
181
|
// Auth and model registry
|
|
183
182
|
export { type ApiKeyCredential, type AuthCredential, AuthStorage, type OAuthCredential } from "./session/auth-storage";
|
|
184
|
-
//
|
|
183
|
+
// Branch summarization and utilities
|
|
185
184
|
export {
|
|
186
185
|
type BranchPreparation,
|
|
187
186
|
type BranchSummaryResult,
|
|
188
187
|
type CollectEntriesResult,
|
|
189
|
-
type CompactionResult,
|
|
190
|
-
type CutPointResult,
|
|
191
188
|
calculateContextTokens,
|
|
192
189
|
collectEntriesForBranchSummary,
|
|
193
|
-
compact,
|
|
194
|
-
DEFAULT_COMPACTION_SETTINGS,
|
|
195
190
|
estimateTokens,
|
|
196
191
|
type FileOperations,
|
|
197
|
-
findCutPoint,
|
|
198
|
-
findTurnStartIndex,
|
|
199
192
|
type GenerateBranchSummaryOptions,
|
|
200
193
|
generateBranchSummary,
|
|
201
|
-
generateSummary,
|
|
202
194
|
getLastAssistantUsage,
|
|
203
195
|
prepareBranchEntries,
|
|
204
196
|
serializeConversation,
|
|
205
|
-
shouldCompact,
|
|
206
197
|
} from "./session/compaction";
|
|
207
198
|
export { convertToLlm } from "./session/messages";
|
|
208
199
|
export {
|
|
209
200
|
type BranchSummaryEntry,
|
|
210
201
|
buildSessionContext,
|
|
211
|
-
type CompactionEntry,
|
|
212
202
|
CURRENT_SESSION_VERSION,
|
|
213
203
|
type CustomEntry,
|
|
214
204
|
type CustomMessageEntry,
|
|
215
205
|
type FileEntry,
|
|
216
|
-
getLatestCompactionEntry,
|
|
217
206
|
type ModeChangeEntry,
|
|
218
207
|
type ModelChangeEntry,
|
|
219
208
|
migrateSessionEntries,
|
|
@@ -45,15 +45,10 @@ export class FooterComponent implements Component {
|
|
|
45
45
|
#cachedBranch: string | null | undefined = undefined; // undefined = not checked yet, null = not in git repo, string = branch name
|
|
46
46
|
#gitWatcher: fs.FSWatcher | null = null;
|
|
47
47
|
#onBranchChange: (() => void) | null = null;
|
|
48
|
-
#autoCompactEnabled: boolean = true;
|
|
49
48
|
#extensionStatuses: Map<string, string> = new Map();
|
|
50
49
|
|
|
51
50
|
constructor(private readonly session: AgentSession) {}
|
|
52
51
|
|
|
53
|
-
setAutoCompactEnabled(enabled: boolean): void {
|
|
54
|
-
this.#autoCompactEnabled = enabled;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
52
|
/**
|
|
58
53
|
* Set extension status text to display in the footer.
|
|
59
54
|
* Text is sanitized (newlines/tabs replaced with spaces) and truncated to terminal width.
|
|
@@ -157,7 +152,7 @@ export class FooterComponent implements Component {
|
|
|
157
152
|
render(width: number): string[] {
|
|
158
153
|
const state = this.session.state;
|
|
159
154
|
|
|
160
|
-
// Calculate cumulative usage from ALL session entries
|
|
155
|
+
// Calculate cumulative usage from ALL session entries
|
|
161
156
|
let totalInput = 0;
|
|
162
157
|
let totalOutput = 0;
|
|
163
158
|
let totalCacheRead = 0;
|
|
@@ -174,8 +169,7 @@ export class FooterComponent implements Component {
|
|
|
174
169
|
}
|
|
175
170
|
}
|
|
176
171
|
|
|
177
|
-
// Calculate context usage from session
|
|
178
|
-
// After compaction, tokens are unknown until the next LLM response.
|
|
172
|
+
// Calculate context usage from session.
|
|
179
173
|
const contextUsage = this.session.getContextUsage();
|
|
180
174
|
const contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;
|
|
181
175
|
const contextPercentValue = contextUsage?.percent ?? 0;
|
|
@@ -227,11 +221,10 @@ export class FooterComponent implements Component {
|
|
|
227
221
|
|
|
228
222
|
// Colorize context percentage based on usage
|
|
229
223
|
let contextPercentStr: string;
|
|
230
|
-
const autoIndicator = this.#autoCompactEnabled ? " (auto)" : "";
|
|
231
224
|
const contextPercentDisplay =
|
|
232
225
|
contextPercent === "?"
|
|
233
|
-
? `?/${formatTokens(contextWindow)}
|
|
234
|
-
: `${contextPercent}%/${formatTokens(contextWindow)}
|
|
226
|
+
? `?/${formatTokens(contextWindow)}`
|
|
227
|
+
: `${contextPercent}%/${formatTokens(contextWindow)}`;
|
|
235
228
|
if (contextPercentValue > 90) {
|
|
236
229
|
contextPercentStr = theme.fg("error", contextPercentDisplay);
|
|
237
230
|
} else if (contextPercentValue > 70) {
|
|
@@ -3,7 +3,6 @@ export { AssistantMessageComponent } from "./assistant-message";
|
|
|
3
3
|
export { BashExecutionComponent } from "./bash-execution";
|
|
4
4
|
export { BorderedLoader } from "./bordered-loader";
|
|
5
5
|
export { BranchSummaryMessageComponent } from "./branch-summary-message";
|
|
6
|
-
export { CompactionSummaryMessageComponent } from "./compaction-summary-message";
|
|
7
6
|
export { CountdownTimer } from "./countdown-timer";
|
|
8
7
|
export { CustomEditor } from "./custom-editor";
|
|
9
8
|
export { CustomMessageComponent } from "./custom-message";
|
|
@@ -211,8 +211,7 @@ const contextPctSegment: StatusLineSegment = {
|
|
|
211
211
|
const pct = ctx.contextPercent;
|
|
212
212
|
const window = ctx.contextWindow;
|
|
213
213
|
|
|
214
|
-
const
|
|
215
|
-
const text = `${pct.toFixed(1)}%/${formatTokens(window)}${autoIcon}`;
|
|
214
|
+
const text = `${pct.toFixed(1)}%/${formatTokens(window)}`;
|
|
216
215
|
|
|
217
216
|
let content: string;
|
|
218
217
|
if (pct > 90) {
|
|
@@ -65,7 +65,6 @@ export class StatusLineComponent implements Component {
|
|
|
65
65
|
#cachedBranch: string | null | undefined = undefined;
|
|
66
66
|
#gitWatcher: fs.FSWatcher | null = null;
|
|
67
67
|
#onBranchChange: (() => void) | null = null;
|
|
68
|
-
#autoCompactEnabled: boolean = true;
|
|
69
68
|
#hookStatuses: Map<string, string> = new Map();
|
|
70
69
|
#subagentCount: number = 0;
|
|
71
70
|
#sessionStartTime: number = Date.now();
|
|
@@ -89,10 +88,6 @@ export class StatusLineComponent implements Component {
|
|
|
89
88
|
this.#settings = settings;
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
setAutoCompactEnabled(enabled: boolean): void {
|
|
93
|
-
this.#autoCompactEnabled = enabled;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
91
|
setSubagentCount(count: number): void {
|
|
97
92
|
this.#subagentCount = count;
|
|
98
93
|
}
|
|
@@ -258,7 +253,6 @@ export class StatusLineComponent implements Component {
|
|
|
258
253
|
usageStats,
|
|
259
254
|
contextPercent,
|
|
260
255
|
contextWindow,
|
|
261
|
-
autoCompactEnabled: this.#autoCompactEnabled,
|
|
262
256
|
subagentCount: this.#subagentCount,
|
|
263
257
|
sessionStartTime: this.#sessionStartTime,
|
|
264
258
|
git: {
|
|
@@ -372,9 +372,6 @@ class TreeList implements Component {
|
|
|
372
372
|
}
|
|
373
373
|
break;
|
|
374
374
|
}
|
|
375
|
-
case "compaction":
|
|
376
|
-
parts.push("compaction");
|
|
377
|
-
break;
|
|
378
375
|
case "branch_summary":
|
|
379
376
|
parts.push("branch summary", entry.summary);
|
|
380
377
|
break;
|
|
@@ -573,11 +570,6 @@ class TreeList implements Component {
|
|
|
573
570
|
result = theme.fg("customMessageLabel", `[${entry.customType}]: `) + normalize(content);
|
|
574
571
|
break;
|
|
575
572
|
}
|
|
576
|
-
case "compaction": {
|
|
577
|
-
const tokens = Math.round(entry.tokensBefore / 1000);
|
|
578
|
-
result = theme.fg("borderAccent", `[compaction: ${tokens}k tokens]`);
|
|
579
|
-
break;
|
|
580
|
-
}
|
|
581
573
|
case "branch_summary":
|
|
582
574
|
result = theme.fg("warning", `[branch summary]: `) + normalize(entry.summary);
|
|
583
575
|
break;
|
|
@@ -9,14 +9,13 @@ import {
|
|
|
9
9
|
type UsageReport,
|
|
10
10
|
} from "@nghyane/arcane-ai";
|
|
11
11
|
import { copyToClipboard } from "@nghyane/arcane-natives";
|
|
12
|
-
import {
|
|
12
|
+
import { Markdown, padding, Spacer, Text, visibleWidth } from "@nghyane/arcane-tui";
|
|
13
13
|
import { Snowflake } from "@nghyane/arcane-utils";
|
|
14
14
|
import { setProjectDir } from "@nghyane/arcane-utils/dirs";
|
|
15
15
|
import { $ } from "bun";
|
|
16
16
|
import { reset as resetCapabilities } from "../../capability";
|
|
17
17
|
import { formatKeyHint, type KeyId } from "../../config/keybindings";
|
|
18
18
|
import { loadCustomShare } from "../../export/custom-share";
|
|
19
|
-
import type { CompactOptions } from "../../extensibility/extensions/types";
|
|
20
19
|
import { getGatewayStatus } from "../../ipy/gateway-coordinator";
|
|
21
20
|
import { BashExecutionComponent } from "../../modes/components/bash-execution";
|
|
22
21
|
import { BorderedLoader } from "../../modes/components/bordered-loader";
|
|
@@ -24,8 +23,7 @@ import { DynamicBorder } from "../../modes/components/dynamic-border";
|
|
|
24
23
|
import { PythonExecutionComponent } from "../../modes/components/python-execution";
|
|
25
24
|
import type { InteractiveModeContext } from "../../modes/types";
|
|
26
25
|
import type { AuthStorage } from "../../session/auth-storage";
|
|
27
|
-
import {
|
|
28
|
-
import { getMarkdownTheme, getSymbolTheme, theme } from "../../theme/theme";
|
|
26
|
+
import { getMarkdownTheme, theme } from "../../theme/theme";
|
|
29
27
|
import { outputMeta } from "../../tools/output-meta";
|
|
30
28
|
import { resolveToCwd } from "../../tools/path-utils";
|
|
31
29
|
import { getChangelogPath, parseChangelog } from "../../utils/changelog";
|
|
@@ -425,12 +423,6 @@ export class CommandController {
|
|
|
425
423
|
}
|
|
426
424
|
this.ctx.statusContainer.clear();
|
|
427
425
|
|
|
428
|
-
if (this.ctx.session.isCompacting) {
|
|
429
|
-
this.ctx.session.abortCompaction();
|
|
430
|
-
while (this.ctx.session.isCompacting) {
|
|
431
|
-
await Bun.sleep(10);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
426
|
await this.ctx.session.newSession();
|
|
435
427
|
|
|
436
428
|
this.ctx.statusLine.invalidate();
|
|
@@ -438,7 +430,6 @@ export class CommandController {
|
|
|
438
430
|
|
|
439
431
|
this.ctx.chatContainer.clear();
|
|
440
432
|
this.ctx.pendingMessagesContainer.clear();
|
|
441
|
-
this.ctx.compactionQueuedMessages = [];
|
|
442
433
|
this.ctx.streamingComponent = undefined;
|
|
443
434
|
this.ctx.streamingMessage = undefined;
|
|
444
435
|
this.ctx.pendingTools.clear();
|
|
@@ -604,92 +595,6 @@ export class CommandController {
|
|
|
604
595
|
this.ctx.ui.requestRender();
|
|
605
596
|
}
|
|
606
597
|
|
|
607
|
-
async handleCompactCommand(customInstructions?: string): Promise<void> {
|
|
608
|
-
const entries = this.ctx.sessionManager.getEntries();
|
|
609
|
-
const messageCount = entries.filter(e => e.type === "message").length;
|
|
610
|
-
|
|
611
|
-
if (messageCount < 2) {
|
|
612
|
-
this.ctx.showWarning("Nothing to compact (no messages yet)");
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
await this.executeCompaction(customInstructions, false);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
async handleSkillCommand(skillPath: string, args: string): Promise<void> {
|
|
620
|
-
try {
|
|
621
|
-
const content = await Bun.file(skillPath).text();
|
|
622
|
-
const body = content.replace(/^---\n[\s\S]*?\n---\n/, "").trim();
|
|
623
|
-
const metaLines = [`Skill: ${skillPath}`];
|
|
624
|
-
if (args) {
|
|
625
|
-
metaLines.push(`User: ${args}`);
|
|
626
|
-
}
|
|
627
|
-
const message = `${body}\n\n---\n\n${metaLines.join("\n")}`;
|
|
628
|
-
await this.ctx.session.prompt(message);
|
|
629
|
-
} catch (err) {
|
|
630
|
-
this.ctx.showError(`Failed to load skill: ${err instanceof Error ? err.message : String(err)}`);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
async executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto = false): Promise<void> {
|
|
635
|
-
if (this.ctx.loadingAnimation) {
|
|
636
|
-
this.ctx.loadingAnimation.stop();
|
|
637
|
-
this.ctx.loadingAnimation = undefined;
|
|
638
|
-
}
|
|
639
|
-
this.ctx.statusContainer.clear();
|
|
640
|
-
|
|
641
|
-
const originalOnEscape = this.ctx.editor.onEscape;
|
|
642
|
-
this.ctx.editor.onEscape = () => {
|
|
643
|
-
this.ctx.session.abortCompaction();
|
|
644
|
-
};
|
|
645
|
-
|
|
646
|
-
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
647
|
-
const label = isAuto ? "Auto-compacting context... (esc to cancel)" : "Compacting context... (esc to cancel)";
|
|
648
|
-
const compactingLoader = new Loader(
|
|
649
|
-
this.ctx.ui,
|
|
650
|
-
spinner => theme.fg("accent", spinner),
|
|
651
|
-
text => theme.fg("muted", text),
|
|
652
|
-
label,
|
|
653
|
-
getSymbolTheme().spinnerFrames,
|
|
654
|
-
);
|
|
655
|
-
this.ctx.statusContainer.addChild(compactingLoader);
|
|
656
|
-
this.ctx.ui.requestRender();
|
|
657
|
-
|
|
658
|
-
try {
|
|
659
|
-
const instructions = typeof customInstructionsOrOptions === "string" ? customInstructionsOrOptions : undefined;
|
|
660
|
-
const options =
|
|
661
|
-
customInstructionsOrOptions && typeof customInstructionsOrOptions === "object"
|
|
662
|
-
? customInstructionsOrOptions
|
|
663
|
-
: undefined;
|
|
664
|
-
const result = await this.ctx.session.compact(instructions, options);
|
|
665
|
-
|
|
666
|
-
this.ctx.rebuildChatFromMessages();
|
|
667
|
-
|
|
668
|
-
const msg = createCompactionSummaryMessage(
|
|
669
|
-
result.summary,
|
|
670
|
-
result.tokensBefore,
|
|
671
|
-
new Date().toISOString(),
|
|
672
|
-
result.shortSummary,
|
|
673
|
-
);
|
|
674
|
-
this.ctx.addMessageToChat(msg);
|
|
675
|
-
|
|
676
|
-
this.ctx.statusLine.invalidate();
|
|
677
|
-
this.ctx.updateEditorTopBorder();
|
|
678
|
-
} catch (error) {
|
|
679
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
680
|
-
if (message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError")) {
|
|
681
|
-
this.ctx.showError("Compaction cancelled");
|
|
682
|
-
} else {
|
|
683
|
-
this.ctx.showError(`Compaction failed: ${message}`);
|
|
684
|
-
}
|
|
685
|
-
} finally {
|
|
686
|
-
compactingLoader.stop();
|
|
687
|
-
this.ctx.statusContainer.clear();
|
|
688
|
-
this.ctx.editor.onEscape = originalOnEscape;
|
|
689
|
-
}
|
|
690
|
-
await this.ctx.flushCompactionQueue({ willRetry: false });
|
|
691
|
-
}
|
|
692
|
-
|
|
693
598
|
async handleHandoffCommand(customInstructions?: string): Promise<void> {
|
|
694
599
|
const entries = this.ctx.sessionManager.getEntries();
|
|
695
600
|
const messageCount = entries.filter(e => e.type === "message").length;
|
|
@@ -772,7 +677,6 @@ function formatDurationShort(ms: number): string {
|
|
|
772
677
|
const hrs = hours % 24;
|
|
773
678
|
if (days > 0) return `${days}d${hrs > 0 ? ` ${hrs}h` : ""}`;
|
|
774
679
|
if (hours > 0) return `${hours}h${mins > 0 ? ` ${mins}m` : ""}`;
|
|
775
|
-
if (minutes > 0) return `${minutes}m`;
|
|
776
680
|
return `${totalSeconds}s`;
|
|
777
681
|
}
|
|
778
682
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AgentTool, toolDetails } from "@nghyane/arcane-agent";
|
|
2
|
-
import { Loader, TERMINAL } from "@nghyane/arcane-tui";
|
|
2
|
+
import { Loader, TERMINAL, Text } from "@nghyane/arcane-tui";
|
|
3
3
|
import { settings } from "../../config/settings";
|
|
4
4
|
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
5
5
|
import { ContextGroupComponent } from "../../modes/components/context-group";
|
|
@@ -259,57 +259,6 @@ export class EventController {
|
|
|
259
259
|
this.sendCompletionNotification();
|
|
260
260
|
break;
|
|
261
261
|
|
|
262
|
-
case "auto_compaction_start": {
|
|
263
|
-
this.ctx.autoCompactionEscapeHandler = this.ctx.editor.onEscape;
|
|
264
|
-
this.ctx.editor.onEscape = () => {
|
|
265
|
-
this.ctx.session.abortCompaction();
|
|
266
|
-
};
|
|
267
|
-
this.ctx.statusContainer.clear();
|
|
268
|
-
const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
|
|
269
|
-
this.ctx.autoCompactionLoader = new Loader(
|
|
270
|
-
this.ctx.ui,
|
|
271
|
-
spinner => theme.fg("accent", spinner),
|
|
272
|
-
text => theme.fg("muted", text),
|
|
273
|
-
`${reasonText}Auto-compacting… (esc to cancel)`,
|
|
274
|
-
getSymbolTheme().spinnerFrames,
|
|
275
|
-
);
|
|
276
|
-
this.ctx.statusContainer.addChild(this.ctx.autoCompactionLoader);
|
|
277
|
-
this.ctx.ui.requestRender();
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
case "auto_compaction_end": {
|
|
282
|
-
if (this.ctx.autoCompactionEscapeHandler) {
|
|
283
|
-
this.ctx.editor.onEscape = this.ctx.autoCompactionEscapeHandler;
|
|
284
|
-
this.ctx.autoCompactionEscapeHandler = undefined;
|
|
285
|
-
}
|
|
286
|
-
if (this.ctx.autoCompactionLoader) {
|
|
287
|
-
this.ctx.autoCompactionLoader.stop();
|
|
288
|
-
this.ctx.autoCompactionLoader = undefined;
|
|
289
|
-
this.ctx.statusContainer.clear();
|
|
290
|
-
}
|
|
291
|
-
if (event.aborted) {
|
|
292
|
-
this.ctx.showStatus("Auto-compaction cancelled");
|
|
293
|
-
} else if (event.result) {
|
|
294
|
-
this.ctx.chatContainer.clear();
|
|
295
|
-
this.ctx.rebuildChatFromMessages();
|
|
296
|
-
this.ctx.addMessageToChat({
|
|
297
|
-
role: "compactionSummary",
|
|
298
|
-
tokensBefore: event.result.tokensBefore,
|
|
299
|
-
summary: event.result.summary,
|
|
300
|
-
shortSummary: event.result.shortSummary,
|
|
301
|
-
timestamp: Date.now(),
|
|
302
|
-
});
|
|
303
|
-
this.ctx.statusLine.invalidate();
|
|
304
|
-
this.ctx.updateEditorTopBorder();
|
|
305
|
-
} else {
|
|
306
|
-
this.ctx.showWarning("Auto-compaction failed; continuing without compaction");
|
|
307
|
-
}
|
|
308
|
-
await this.ctx.flushCompactionQueue({ willRetry: event.willRetry });
|
|
309
|
-
this.ctx.ui.requestRender();
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
262
|
case "auto_retry_start": {
|
|
314
263
|
this.ctx.retryEscapeHandler = this.ctx.editor.onEscape;
|
|
315
264
|
this.ctx.editor.onEscape = () => {
|
|
@@ -348,6 +297,51 @@ export class EventController {
|
|
|
348
297
|
break;
|
|
349
298
|
}
|
|
350
299
|
|
|
300
|
+
case "context_warning": {
|
|
301
|
+
this.ctx.statusContainer.clear();
|
|
302
|
+
const warningMsg = `Context usage at ${event.percent}% — session will auto-handoff soon`;
|
|
303
|
+
this.ctx.statusContainer.addChild(
|
|
304
|
+
new Text(theme.fg("warning", `${theme.status.warning} ${warningMsg}`), 0, 0),
|
|
305
|
+
);
|
|
306
|
+
this.ctx.ui.requestRender();
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
case "auto_handoff_start": {
|
|
311
|
+
this.ctx.statusContainer.clear();
|
|
312
|
+
this.ctx.handoffLoader = new Loader(
|
|
313
|
+
this.ctx.ui,
|
|
314
|
+
spinner => theme.fg("warning", spinner),
|
|
315
|
+
text => theme.fg("muted", text),
|
|
316
|
+
"Auto-handoff in progress…",
|
|
317
|
+
getSymbolTheme().spinnerFrames,
|
|
318
|
+
);
|
|
319
|
+
this.ctx.statusContainer.addChild(this.ctx.handoffLoader);
|
|
320
|
+
this.ctx.ui.requestRender();
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
case "auto_handoff_end": {
|
|
325
|
+
if (this.ctx.handoffLoader) {
|
|
326
|
+
this.ctx.handoffLoader.stop();
|
|
327
|
+
this.ctx.handoffLoader = undefined;
|
|
328
|
+
this.ctx.statusContainer.clear();
|
|
329
|
+
}
|
|
330
|
+
if (event.success) {
|
|
331
|
+
this.ctx.statusContainer.addChild(
|
|
332
|
+
new Text(
|
|
333
|
+
theme.fg("success", `${theme.status.success} Session handed off — continuing in new session`),
|
|
334
|
+
0,
|
|
335
|
+
0,
|
|
336
|
+
),
|
|
337
|
+
);
|
|
338
|
+
} else if (event.error) {
|
|
339
|
+
this.ctx.showError(`Auto-handoff failed: ${event.error}`);
|
|
340
|
+
}
|
|
341
|
+
this.ctx.ui.requestRender();
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
|
|
351
345
|
case "ttsr_triggered": {
|
|
352
346
|
this.#finalizeContextGroup();
|
|
353
347
|
const component = new TtsrNotificationComponent(event.rules);
|
|
@@ -133,12 +133,6 @@ export class ExtensionUiController {
|
|
|
133
133
|
// Signal shutdown request (will be handled by main loop)
|
|
134
134
|
},
|
|
135
135
|
getContextUsage: () => this.ctx.session.getContextUsage(),
|
|
136
|
-
compact: async instructionsOrOptions => {
|
|
137
|
-
const instructions = typeof instructionsOrOptions === "string" ? instructionsOrOptions : undefined;
|
|
138
|
-
const options =
|
|
139
|
-
instructionsOrOptions && typeof instructionsOrOptions === "object" ? instructionsOrOptions : undefined;
|
|
140
|
-
await this.ctx.session.compact(instructions, options);
|
|
141
|
-
},
|
|
142
136
|
getSystemPrompt: () => this.ctx.session.systemPrompt,
|
|
143
137
|
};
|
|
144
138
|
const commandActions: ExtensionCommandContextActions = {
|
|
@@ -174,7 +168,6 @@ export class ExtensionUiController {
|
|
|
174
168
|
// Clear UI state
|
|
175
169
|
this.ctx.chatContainer.clear();
|
|
176
170
|
this.ctx.pendingMessagesContainer.clear();
|
|
177
|
-
this.ctx.compactionQueuedMessages = [];
|
|
178
171
|
this.ctx.streamingComponent = undefined;
|
|
179
172
|
this.ctx.streamingMessage = undefined;
|
|
180
173
|
this.ctx.pendingTools.clear();
|
|
@@ -220,16 +213,6 @@ export class ExtensionUiController {
|
|
|
220
213
|
|
|
221
214
|
return { cancelled: false };
|
|
222
215
|
},
|
|
223
|
-
compact: async instructionsOrOptions => {
|
|
224
|
-
const instructions = typeof instructionsOrOptions === "string" ? instructionsOrOptions : undefined;
|
|
225
|
-
const options =
|
|
226
|
-
instructionsOrOptions && typeof instructionsOrOptions === "object" ? instructionsOrOptions : undefined;
|
|
227
|
-
if (this.ctx.isBackgrounded) {
|
|
228
|
-
await this.ctx.session.compact(instructions, options);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
await this.ctx.executeCompaction(instructionsOrOptions, false);
|
|
232
|
-
},
|
|
233
216
|
switchSession: async sessionPath => {
|
|
234
217
|
const result = await this.ctx.session.switchSession(sessionPath);
|
|
235
218
|
if (!result) {
|
|
@@ -322,12 +305,6 @@ export class ExtensionUiController {
|
|
|
322
305
|
// Signal shutdown request (will be handled by main loop)
|
|
323
306
|
},
|
|
324
307
|
getContextUsage: () => this.ctx.session.getContextUsage(),
|
|
325
|
-
compact: async instructionsOrOptions => {
|
|
326
|
-
const instructions = typeof instructionsOrOptions === "string" ? instructionsOrOptions : undefined;
|
|
327
|
-
const options =
|
|
328
|
-
instructionsOrOptions && typeof instructionsOrOptions === "object" ? instructionsOrOptions : undefined;
|
|
329
|
-
await this.ctx.session.compact(instructions, options);
|
|
330
|
-
},
|
|
331
308
|
getSystemPrompt: () => this.ctx.session.systemPrompt,
|
|
332
309
|
};
|
|
333
310
|
const commandActions: ExtensionCommandContextActions = {
|
|
@@ -369,7 +346,6 @@ export class ExtensionUiController {
|
|
|
369
346
|
// Clear UI state
|
|
370
347
|
this.ctx.chatContainer.clear();
|
|
371
348
|
this.ctx.pendingMessagesContainer.clear();
|
|
372
|
-
this.ctx.compactionQueuedMessages = [];
|
|
373
349
|
this.ctx.streamingComponent = undefined;
|
|
374
350
|
this.ctx.streamingMessage = undefined;
|
|
375
351
|
this.ctx.pendingTools.clear();
|
|
@@ -421,16 +397,6 @@ export class ExtensionUiController {
|
|
|
421
397
|
|
|
422
398
|
return { cancelled: false };
|
|
423
399
|
},
|
|
424
|
-
compact: async instructionsOrOptions => {
|
|
425
|
-
const instructions = typeof instructionsOrOptions === "string" ? instructionsOrOptions : undefined;
|
|
426
|
-
const options =
|
|
427
|
-
instructionsOrOptions && typeof instructionsOrOptions === "object" ? instructionsOrOptions : undefined;
|
|
428
|
-
if (this.ctx.isBackgrounded) {
|
|
429
|
-
await this.ctx.session.compact(instructions, options);
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
await this.ctx.executeCompaction(instructionsOrOptions, false);
|
|
433
|
-
},
|
|
434
400
|
switchSession: async sessionPath => {
|
|
435
401
|
if (this.ctx.isBackgrounded) {
|
|
436
402
|
return { cancelled: true };
|
|
@@ -497,14 +463,6 @@ export class ExtensionUiController {
|
|
|
497
463
|
await registeredTool.definition.onSession(event, {
|
|
498
464
|
ui: uiContext,
|
|
499
465
|
getContextUsage: () => this.ctx.session.getContextUsage(),
|
|
500
|
-
compact: async instructionsOrOptions => {
|
|
501
|
-
const instructions = typeof instructionsOrOptions === "string" ? instructionsOrOptions : undefined;
|
|
502
|
-
const options =
|
|
503
|
-
instructionsOrOptions && typeof instructionsOrOptions === "object"
|
|
504
|
-
? instructionsOrOptions
|
|
505
|
-
: undefined;
|
|
506
|
-
await this.ctx.session.compact(instructions, options);
|
|
507
|
-
},
|
|
508
466
|
hasUI: !this.ctx.isBackgrounded,
|
|
509
467
|
cwd: this.ctx.sessionManager.getCwd(),
|
|
510
468
|
sessionManager: this.ctx.session.sessionManager,
|
|
@@ -30,13 +30,9 @@ export class InputController {
|
|
|
30
30
|
Boolean(
|
|
31
31
|
this.ctx.loadingAnimation ||
|
|
32
32
|
this.ctx.session.isStreaming ||
|
|
33
|
-
this.ctx.session.isCompacting ||
|
|
34
33
|
this.ctx.session.isGeneratingHandoff ||
|
|
35
34
|
this.ctx.session.isBashRunning ||
|
|
36
35
|
this.ctx.session.isPythonRunning ||
|
|
37
|
-
this.ctx.autoCompactionLoader ||
|
|
38
|
-
this.ctx.retryLoader ||
|
|
39
|
-
this.ctx.autoCompactionEscapeHandler ||
|
|
40
36
|
this.ctx.retryEscapeHandler,
|
|
41
37
|
);
|
|
42
38
|
this.ctx.editor.onEscape = () => {
|
|
@@ -270,16 +266,6 @@ export class InputController {
|
|
|
270
266
|
}
|
|
271
267
|
}
|
|
272
268
|
|
|
273
|
-
// Queue input during compaction
|
|
274
|
-
if (this.ctx.session.isCompacting) {
|
|
275
|
-
if (this.ctx.pendingImages.length > 0) {
|
|
276
|
-
this.ctx.showStatus("Compaction in progress. Retry after it completes to send images.");
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
this.ctx.queueCompactionMessage(text, "steer");
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
269
|
// If streaming, use prompt() with steer behavior
|
|
284
270
|
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
285
271
|
if (this.ctx.session.isStreaming) {
|
|
@@ -365,11 +351,6 @@ export class InputController {
|
|
|
365
351
|
const text = this.ctx.editor.getText().trim();
|
|
366
352
|
if (!text) return;
|
|
367
353
|
|
|
368
|
-
if (this.ctx.session.isCompacting) {
|
|
369
|
-
this.ctx.queueCompactionMessage(text, "followUp");
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
354
|
if (this.ctx.session.isStreaming) {
|
|
374
355
|
this.ctx.editor.addToHistory(text);
|
|
375
356
|
this.ctx.editor.setText("");
|
|
@@ -427,10 +408,6 @@ export class InputController {
|
|
|
427
408
|
this.ctx.loadingAnimation.stop();
|
|
428
409
|
this.ctx.loadingAnimation = undefined;
|
|
429
410
|
}
|
|
430
|
-
if (this.ctx.autoCompactionLoader) {
|
|
431
|
-
this.ctx.autoCompactionLoader.stop();
|
|
432
|
-
this.ctx.autoCompactionLoader = undefined;
|
|
433
|
-
}
|
|
434
411
|
if (this.ctx.retryLoader) {
|
|
435
412
|
this.ctx.retryLoader.stop();
|
|
436
413
|
this.ctx.retryLoader = undefined;
|
|
@@ -179,10 +179,6 @@ export class SelectorController {
|
|
|
179
179
|
|
|
180
180
|
switch (id) {
|
|
181
181
|
// Session-managed settings (not in SettingsManager)
|
|
182
|
-
case "autoCompact":
|
|
183
|
-
this.ctx.session.setAutoCompactionEnabled(value as boolean);
|
|
184
|
-
this.ctx.statusLine.setAutoCompactEnabled(value as boolean);
|
|
185
|
-
break;
|
|
186
182
|
case "steeringMode":
|
|
187
183
|
this.ctx.session.setSteeringMode(value as "all" | "one-at-a-time");
|
|
188
184
|
break;
|
|
@@ -536,7 +532,6 @@ export class SelectorController {
|
|
|
536
532
|
|
|
537
533
|
// Clear UI state
|
|
538
534
|
this.ctx.pendingMessagesContainer.clear();
|
|
539
|
-
this.ctx.compactionQueuedMessages = [];
|
|
540
535
|
this.ctx.streamingComponent = undefined;
|
|
541
536
|
this.ctx.streamingMessage = undefined;
|
|
542
537
|
this.ctx.pendingTools.clear();
|