Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/CodexAcpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {Disposable} from "vscode-jsonrpc";
import type {
ClientInfo,
ReasoningEffort,
ServiceTier,
ServerNotification
} from "./app-server";
import type {JsonValue} from "./app-server/serde_json/JsonValue";
Expand Down Expand Up @@ -220,6 +221,7 @@ export class CodexAcpClient {
sessionId: request.sessionId,
currentModelId: currentModelId,
models: codexModels,
currentServiceTier: response.serviceTier ?? null,
}
}

Expand All @@ -242,6 +244,7 @@ export class CodexAcpClient {
sessionId: request.sessionId,
currentModelId: currentModelId,
models: codexModels,
currentServiceTier: response.serviceTier ?? null,
thread: response.thread,
};
}
Expand Down Expand Up @@ -271,6 +274,7 @@ export class CodexAcpClient {
sessionId: response.thread.id,
currentModelId: currentModelId,
models: codexModels,
currentServiceTier: response.serviceTier ?? null,
};
}

Expand Down Expand Up @@ -394,6 +398,7 @@ export class CodexAcpClient {
request: acp.PromptRequest,
agentMode: AgentMode,
modelId: ModelId,
serviceTier: ServiceTier | null,
disableSummary: boolean,
cwd: string,
): Promise<TurnCompletedNotification> {
Expand All @@ -412,6 +417,7 @@ export class CodexAcpClient {
cwd: null,
effort: effort,
model: modelId.model,
serviceTier: serviceTier,
});
}

Expand Down Expand Up @@ -605,6 +611,7 @@ export type SessionMetadata = {
sessionId: string,
currentModelId: string,
models: Model[],
currentServiceTier?: ServiceTier | null,
}

export type SessionMetadataWithThread = SessionMetadata & {
Expand Down
60 changes: 56 additions & 4 deletions src/CodexAcpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ import {
createFileChangeUpdate,
createMcpToolCallUpdate,
} from "./CodexToolCallMapper";
import {
createFastModeConfigOption,
FAST_MODE_CONFIG_ID,
FAST_MODE_OFF,
FAST_MODE_ON,
modelSupportsFast,
resolveFastServiceTier,
} from "./FastModeConfig";

export interface SessionState {
sessionId: string,
Expand All @@ -46,6 +54,8 @@ export interface SessionState {
rateLimits: RateLimitsMap | null;
account: Account | null;
cwd: string;
fastModeEnabled: boolean;
currentModelSupportsFast: boolean;
sessionMcpServers?: Array<string>;
}

Expand Down Expand Up @@ -163,6 +173,7 @@ export class CodexAcpServer implements acp.Agent {
const {sessionId, currentModelId, models} = sessionMetadata;
const sessionMcpServers = this.resolveSessionMcpServers(requestedMcpServers, "sessionId" in request);
const currentModel = this.findCurrentModel(models, currentModelId);
const currentModelSupportsFast = modelSupportsFast(currentModel);
const sessionState: SessionState = {
sessionId: sessionId,
currentModelId: currentModelId,
Expand All @@ -176,6 +187,8 @@ export class CodexAcpServer implements acp.Agent {
rateLimits: null,
account: account,
cwd: request.cwd,
fastModeEnabled: sessionMetadata.currentServiceTier === "fast",
currentModelSupportsFast: currentModelSupportsFast,
sessionMcpServers: sessionMcpServers,
}
this.sessions.set(sessionId, sessionState);
Expand Down Expand Up @@ -221,7 +234,8 @@ export class CodexAcpServer implements acp.Agent {
});
return {
models: modelState,
modes: modeState
modes: modeState,
configOptions: this.createSessionConfigOptions(this.getSessionState(sessionId)),
};
}

Expand All @@ -236,7 +250,8 @@ export class CodexAcpServer implements acp.Agent {
});
return {
models: modelState,
modes: modeState
modes: modeState,
configOptions: this.createSessionConfigOptions(this.getSessionState(sessionId)),
};
}

Expand All @@ -261,7 +276,8 @@ export class CodexAcpServer implements acp.Agent {
return {
sessionId: sessionId,
models: modelState,
modes: modeState
modes: modeState,
configOptions: this.createSessionConfigOptions(this.getSessionState(sessionId)),
};
}

Expand Down Expand Up @@ -302,6 +318,28 @@ export class CodexAcpServer implements acp.Agent {
return {};
}

async setSessionConfigOption(params: acp.SetSessionConfigOptionRequest): Promise<acp.SetSessionConfigOptionResponse> {
logger.log("Set session config option requested", {
sessionId: params.sessionId,
configId: params.configId,
});
const sessionState = this.sessions.get(params.sessionId);
if (!sessionState) throw new Error(`Session ${params.sessionId} not found`);

if (params.configId !== FAST_MODE_CONFIG_ID || ("type" in params && params.type === "boolean")) {
throw RequestError.invalidParams();
}

if (params.value !== FAST_MODE_ON && params.value !== FAST_MODE_OFF) {
throw RequestError.invalidParams();
}

sessionState.fastModeEnabled = params.value === FAST_MODE_ON;
return {
configOptions: this.createSessionConfigOptions(sessionState),
};
}

async unstable_setSessionModel(params: acp.SetSessionModelRequest): Promise<acp.SetSessionModelResponse | void> {
logger.log("Set session model requested", {
sessionId: params.sessionId,
Expand Down Expand Up @@ -337,10 +375,17 @@ export class CodexAcpServer implements acp.Agent {
sessionState.currentModelId = ModelId.fromComponents(model, reasoningEffort).toString();
sessionState.supportedReasoningEfforts = model.supportedReasoningEfforts;
sessionState.supportedInputModalities = model.inputModalities;
sessionState.currentModelSupportsFast = modelSupportsFast(model);

return {};
}

private createSessionConfigOptions(sessionState: SessionState): Array<acp.SessionConfigOption> {
return [
createFastModeConfigOption(sessionState.fastModeEnabled),
];
}

private publishAvailableCommandsAsync(sessionId: string) {
void this.availableCommands.publish(sessionId);
}
Expand Down Expand Up @@ -388,6 +433,7 @@ export class CodexAcpServer implements acp.Agent {
const {sessionId, currentModelId, models, thread} = sessionMetadata;
const sessionMcpServers = this.resolveSessionMcpServers(requestedMcpServers, true);
const currentModel = this.findCurrentModel(models, currentModelId);
const currentModelSupportsFast = modelSupportsFast(currentModel);
const sessionState: SessionState = {
sessionId: sessionId,
currentModelId: currentModelId,
Expand All @@ -401,6 +447,8 @@ export class CodexAcpServer implements acp.Agent {
rateLimits: null,
account: account,
cwd: request.cwd,
fastModeEnabled: sessionMetadata.currentServiceTier === "fast",
currentModelSupportsFast: currentModelSupportsFast,
sessionMcpServers: sessionMcpServers,
};
this.sessions.set(sessionId, sessionState);
Expand Down Expand Up @@ -767,8 +815,12 @@ export class CodexAcpServer implements acp.Agent {
throw RequestError.invalidRequest("The current model does not support image input");
}
const agentMode = sessionState.agentMode;
const serviceTier = resolveFastServiceTier(
sessionState.fastModeEnabled,
sessionState.currentModelSupportsFast,
);
const turnCompleted = await this.runWithProcessCheck(
() => this.codexAcpClient.sendPrompt(params, agentMode, modelId, disableSummary, sessionState.cwd));
() => this.codexAcpClient.sendPrompt(params, agentMode, modelId, serviceTier, disableSummary, sessionState.cwd));

// Check if turn was interrupted (cancelled)
if (turnCompleted.turn.status === "interrupted") {
Expand Down
40 changes: 40 additions & 0 deletions src/FastModeConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type {SessionConfigOption} from "@agentclientprotocol/sdk";
import type {ServiceTier} from "./app-server";
import type {Model} from "./app-server/v2";

export const FAST_MODE_CONFIG_ID = "fast-mode";
export const FAST_MODE_ON = "on";
export const FAST_MODE_OFF = "off";

const FAST_MODE_DESCRIPTION = "1.5x speed, increased usage";

export function modelSupportsFast(model: Model | undefined): boolean {
return model?.additionalSpeedTiers?.includes("fast") ?? false;
}

export function resolveFastServiceTier(fastModeEnabled: boolean, currentModelSupportsFast: boolean): ServiceTier | null {
return fastModeEnabled && currentModelSupportsFast ? "fast" : null;
}

export function createFastModeConfigOption(fastModeEnabled: boolean): SessionConfigOption {
return {
id: FAST_MODE_CONFIG_ID,
name: "Fast mode",
description: FAST_MODE_DESCRIPTION,
category: FAST_MODE_CONFIG_ID,
type: "select",
currentValue: fastModeEnabled ? FAST_MODE_ON : FAST_MODE_OFF,
options: [
{
value: FAST_MODE_OFF,
name: "Off",
description: "Default speed, normal usage",
},
{
value: FAST_MODE_ON,
name: "On",
description: FAST_MODE_DESCRIPTION,
},
],
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
"personality": null,
"cwd": "cwd",
"effort": "effort",
"model": "model"
"model": "model",
"serviceTier": null
}
}
{
Expand Down
Loading
Loading