mirror of
https://github.com/cline/cline.git
synced 2026-09-21 05:10:09 +08:00
Add compaction sidecar kill switch
This commit is contained in:
@@ -327,6 +327,73 @@ describe("createInteractiveSessionRuntime", () => {
|
||||
expect(runtime.getActiveSessionId()).toBe(sessionId);
|
||||
});
|
||||
|
||||
it("manual compact skips sidecar writes when the sidecar flag is off", async () => {
|
||||
const sessionId = "sess-active-sidecar-off";
|
||||
const messages = [
|
||||
{ id: "u1", role: "user" as const, content: "hello" },
|
||||
{ id: "a1", role: "assistant" as const, content: "world" },
|
||||
];
|
||||
const compactionState = createSessionCompactionState({
|
||||
sourceMessages: messages,
|
||||
compactedMessages: [
|
||||
{ id: "summary", role: "user" as const, content: "summary" },
|
||||
],
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
});
|
||||
const manager = {
|
||||
start: vi.fn().mockResolvedValue({
|
||||
sessionId,
|
||||
manifest: createManifest(sessionId),
|
||||
manifestPath: "/tmp/session.json",
|
||||
messagesPath: "/tmp/session.messages.json",
|
||||
}),
|
||||
readMessages: vi.fn().mockResolvedValue(messages),
|
||||
updateSessionCompactionState: vi.fn(),
|
||||
stop: vi.fn().mockResolvedValue(undefined),
|
||||
dispose: vi.fn().mockResolvedValue(undefined),
|
||||
ingestHookEvent: vi.fn().mockResolvedValue(undefined),
|
||||
get: vi.fn(),
|
||||
list: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
send: vi.fn(),
|
||||
getAccumulatedUsage: vi.fn(),
|
||||
};
|
||||
createCliCoreMock.mockResolvedValue(manager);
|
||||
compactInteractiveMessagesMock.mockResolvedValue({
|
||||
compacted: true,
|
||||
canonicalMessages: messages,
|
||||
compactionState,
|
||||
});
|
||||
const { createInteractiveSessionRuntime } = await importRuntime();
|
||||
const runtime = createInteractiveSessionRuntime({
|
||||
config: createConfig(),
|
||||
providerSettingsManager: createProviderSettingsManager(),
|
||||
chatCommandState: createChatCommandState(),
|
||||
requestToolApproval: vi.fn(),
|
||||
resolveToolPolicy: () => ({ autoApprove: true }),
|
||||
askQuestionRef: { current: null },
|
||||
resolveMistakeLimitDecision: undefined,
|
||||
switchToActModeTool: {} as never,
|
||||
onAgentEvent: vi.fn(),
|
||||
onTeamEvent: vi.fn(),
|
||||
onPendingPrompts: vi.fn(),
|
||||
onPendingPromptSubmitted: vi.fn(),
|
||||
isCompactionSidecarEnabled: () => false,
|
||||
});
|
||||
|
||||
await runtime.ensureReady();
|
||||
const result = await runtime.compactCurrentSession();
|
||||
|
||||
expect(result).toEqual({
|
||||
messagesBefore: messages.length,
|
||||
messagesAfter: messages.length,
|
||||
workingContextMessagesAfter: compactionState.messages.length,
|
||||
compacted: true,
|
||||
});
|
||||
expect(manager.updateSessionCompactionState).not.toHaveBeenCalled();
|
||||
expect(runtime.getActiveSessionId()).toBe(sessionId);
|
||||
});
|
||||
|
||||
it("rejects manual compact while the active session is running", async () => {
|
||||
const sessionId = "sess-running";
|
||||
const messages = [{ role: "user" as const, content: "hello" }];
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
type AgentHooks,
|
||||
type CheckpointEntry,
|
||||
createSessionCompactionState,
|
||||
createSessionCompactionSidecarEnabledResolver,
|
||||
isSessionNotFoundError,
|
||||
type PendingPromptMutationResult,
|
||||
type ProviderSettingsManager,
|
||||
@@ -96,8 +97,12 @@ export function createInteractiveSessionRuntime(input: {
|
||||
onTeamEvent: (event: TeamEvent) => void;
|
||||
onPendingPrompts: (event: PendingPromptSnapshot) => void;
|
||||
onPendingPromptSubmitted: (event: PendingPromptSubmittedEvent) => void;
|
||||
isCompactionSidecarEnabled?: () => boolean;
|
||||
}) {
|
||||
let sessionManager: CliCore | undefined;
|
||||
const isCompactionSidecarEnabled =
|
||||
input.isCompactionSidecarEnabled ??
|
||||
createSessionCompactionSidecarEnabledResolver();
|
||||
let runtimeHooks: RuntimeHooks | undefined;
|
||||
let unsubscribeAgent = () => {};
|
||||
let unsubscribePendingPrompts = () => {};
|
||||
@@ -210,7 +215,9 @@ export function createInteractiveSessionRuntime(input: {
|
||||
toolPolicies: input.config.toolPolicies,
|
||||
interactive: true,
|
||||
initialMessages: initial,
|
||||
...(initialCompactionState ? { initialCompactionState } : {}),
|
||||
...(isCompactionSidecarEnabled() && initialCompactionState
|
||||
? { initialCompactionState }
|
||||
: {}),
|
||||
...(sessionMetadata ? { sessionMetadata } : {}),
|
||||
localRuntime: {
|
||||
onTeamRestored: () => {},
|
||||
@@ -291,6 +298,9 @@ export function createInteractiveSessionRuntime(input: {
|
||||
const readCompactionState = async (
|
||||
sessionId: string,
|
||||
): Promise<SessionCompactionState | undefined> => {
|
||||
if (!isCompactionSidecarEnabled()) {
|
||||
return undefined;
|
||||
}
|
||||
const manager = sessionManager;
|
||||
if (!manager) {
|
||||
return undefined;
|
||||
@@ -624,6 +634,14 @@ export function createInteractiveSessionRuntime(input: {
|
||||
compacted: false,
|
||||
};
|
||||
}
|
||||
if (!isCompactionSidecarEnabled()) {
|
||||
return {
|
||||
messagesBefore,
|
||||
messagesAfter: result.canonicalMessages.length,
|
||||
workingContextMessagesAfter: result.compactionState.messages.length,
|
||||
compacted: true,
|
||||
};
|
||||
}
|
||||
const updated = await manager.updateSessionCompactionState(
|
||||
sourceSessionId,
|
||||
result.compactionState,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
getCurrentContextSize,
|
||||
createSessionCompactionSidecarEnabledResolver,
|
||||
type ProviderSettings,
|
||||
ProviderSettingsManager,
|
||||
type UserInstructionConfigService,
|
||||
@@ -25,6 +26,7 @@ import { disableOpenTuiGraphicsProbe } from "../tui/opentui-env";
|
||||
import type { QueuedPromptItem } from "../tui/types";
|
||||
import { type ChatCommandState, chatCommandHost } from "../utils/chat-commands";
|
||||
import { applyCliCompactionMode } from "../utils/compaction-mode";
|
||||
import { getCliFeatureFlagsService } from "../utils/feature-flags";
|
||||
import {
|
||||
shouldZeroClineFreeModelCost,
|
||||
zeroCliAgentEventCost,
|
||||
@@ -201,6 +203,8 @@ export async function runInteractive(
|
||||
onPendingPromptSubmitted: (event) => {
|
||||
uiEvents.emit("pending-prompt-submitted", event);
|
||||
},
|
||||
isCompactionSidecarEnabled:
|
||||
createSessionCompactionSidecarEnabledResolver(getCliFeatureFlagsService()),
|
||||
});
|
||||
let modeChangePromise: Promise<void> | undefined;
|
||||
let modeChangeTarget: "plan" | "act" | undefined;
|
||||
|
||||
Reference in New Issue
Block a user