mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-11-02 15:31:50 +00:00
fix: report the fresh context's usage when ExitPlanMode clears context (#1484)
Choosing one of `ExitPlanMode`'s "clear context" options restarts Claude's conversation with only the plan. The ACP session ID and the turn stay the same, and the adapter resets its context count to 0, but it didn't tell the client. Clients kept showing the old context's usage until the fresh context first reported its own, so nothing on the client side showed that the context had been cleared. `publishSessionState` now sends a `usage_update` for the empty fresh context (`used: 0`, the fresh session's context window as `size`) right after the `current_mode_update` and `config_option_update` it already sends. `used: 0` slightly understates the fresh context, which already holds the system prompt and the plan, until Claude's next usage report. Testing: - `npm run build`, `npm run test:run`, and `npm run check` pass. - `clear-context-coordinator.test.ts` checks the update's order and values.
This commit is contained in:
@@ -45,6 +45,7 @@ export type ClearContextSession<Turn extends ClearContextTurn = ClearContextTurn
|
||||
turnQueue?: Turn[];
|
||||
pendingExitPlanContextReset?: ClearContextReset;
|
||||
contextUsedTokens?: number;
|
||||
contextWindowSize: number;
|
||||
sentUserUuids?: Set<string>;
|
||||
input: { push(message: SDKUserMessage): unknown };
|
||||
};
|
||||
@@ -61,10 +62,13 @@ export type ClearContextCoordinatorHost<
|
||||
): Promise<Session>;
|
||||
applyFastMode(session: Session, enabled: boolean): Promise<void>;
|
||||
applyUltracode(session: Session, enabled: boolean): Promise<void>;
|
||||
/** Publishes the fresh context's mode, config options, and usage: the
|
||||
* context starts empty in a window of `contextWindowSize` tokens. */
|
||||
publishSessionState(
|
||||
sessionId: string,
|
||||
mode: PermissionMode,
|
||||
configOptions: SessionConfigOption[],
|
||||
contextWindowSize: number,
|
||||
): Promise<void>;
|
||||
continuationMessage(sessionId: string, plan: string, promptUuid: string): SDKUserMessage;
|
||||
ensureConsumer(session: Session, sessionId: string): void;
|
||||
@@ -165,7 +169,12 @@ export async function continuePlanInFreshContext<
|
||||
freshSession.contextUsedTokens = 0;
|
||||
|
||||
try {
|
||||
await host.publishSessionState(sessionId, reset.mode, freshSession.configOptions);
|
||||
await host.publishSessionState(
|
||||
sessionId,
|
||||
reset.mode,
|
||||
freshSession.configOptions,
|
||||
freshSession.contextWindowSize,
|
||||
);
|
||||
} catch (error) {
|
||||
host.logError("Failed to publish clear-context session state:", error);
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ export class ExitPlanCoordinator<
|
||||
try {
|
||||
const clearContextHost: ClearContextCoordinatorHost<Session, Turn> = {
|
||||
...this.host,
|
||||
publishSessionState: async (id, mode, configOptions) => {
|
||||
publishSessionState: async (id, mode, configOptions, contextWindowSize) => {
|
||||
await this.host.sessionUpdate({
|
||||
sessionId: id,
|
||||
update: { sessionUpdate: "current_mode_update", currentModeId: mode },
|
||||
@@ -222,6 +222,12 @@ export class ExitPlanCoordinator<
|
||||
sessionId: id,
|
||||
update: { sessionUpdate: "config_option_update", configOptions },
|
||||
});
|
||||
// Otherwise the client shows the old context's usage until the fresh
|
||||
// context first reports its own.
|
||||
await this.host.sessionUpdate({
|
||||
sessionId: id,
|
||||
update: { sessionUpdate: "usage_update", used: 0, size: contextWindowSize },
|
||||
});
|
||||
// The approved plan becomes the session's plan once the fresh
|
||||
// context that carries it out exists. Its ExitPlanMode ended with
|
||||
// an error result, so toAcpNotifications did not publish it.
|
||||
|
||||
@@ -28,6 +28,7 @@ function testSession(overrides: Partial<TestSession> = {}): TestSession {
|
||||
},
|
||||
},
|
||||
models: { currentModelId: "default" },
|
||||
contextWindowSize: 200_000,
|
||||
configOptions: [],
|
||||
currentAgent: "default",
|
||||
fastModeEnabled: false,
|
||||
@@ -464,6 +465,7 @@ describe("ExitPlanCoordinator", () => {
|
||||
expect(order).toEqual([
|
||||
"current_mode_update",
|
||||
"config_option_update",
|
||||
"usage_update",
|
||||
...(supportsPlanOperations
|
||||
? [
|
||||
"plan_update " +
|
||||
@@ -476,6 +478,10 @@ describe("ExitPlanCoordinator", () => {
|
||||
: []),
|
||||
"continuation",
|
||||
]);
|
||||
expect(host.sessionUpdate).toHaveBeenCalledWith({
|
||||
sessionId: "public-session",
|
||||
update: { sessionUpdate: "usage_update", used: 0, size: 200_000 },
|
||||
});
|
||||
if (airClient) {
|
||||
expect(host.sessionUpdate).toHaveBeenCalledWith({
|
||||
sessionId: "public-session",
|
||||
|
||||
Reference in New Issue
Block a user