Skip to content
Merged
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
15 changes: 14 additions & 1 deletion src/AcpExtensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
} from "@agentclientprotocol/sdk";

export const LEGACY_SET_SESSION_MODEL_METHOD = "session/set_model";
export const GOAL_CONTROL_METHOD = "_codex/session/goal_control";

export type LegacySessionModel = {
modelId: string;
Expand Down Expand Up @@ -42,11 +43,13 @@ export type ExtMethodRequest =
AuthenticationStatusRequest
| AuthenticationLogoutRequest
| LegacySetSessionModelExtRequest
| GoalControlExtRequest

export function isExtMethodRequest(request: { method: string, params: Record<string, unknown> }): request is ExtMethodRequest {
return request.method === "authentication/status"
|| request.method === "authentication/logout"
|| request.method === LEGACY_SET_SESSION_MODEL_METHOD;
|| request.method === LEGACY_SET_SESSION_MODEL_METHOD
|| request.method === GOAL_CONTROL_METHOD;
}

export type AuthenticationStatusRequest = { method: "authentication/status", params: {} }
Expand All @@ -60,6 +63,16 @@ export type LegacySetSessionModelExtRequest = {
params: LegacySetSessionModelRequest;
}

export type GoalControlRequest = {
sessionId: SessionId;
action: "pause" | "clear";
}

export type GoalControlExtRequest = {
method: typeof GOAL_CONTROL_METHOD;
params: GoalControlRequest;
}

export async function legacySetSessionModel(
connection: Pick<ClientContext, "request">,
params: LegacySetSessionModelRequest,
Expand Down
37 changes: 35 additions & 2 deletions src/CodexAcpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ import type {
SkillsListResponse,
SandboxPolicy,
Thread,
ThreadGoal,
ThreadGoalStatus,
ThreadSourceKind,
TurnCompletedNotification,
UserInput,
} from "./app-server/v2";
import packageJson from "../package.json";
import type {AuthenticationStatusResponse} from "./AcpExtensions";
import {createCodexCollaborationMode} from "./CollaborationModeConfig";
import type {ModeKind} from "./app-server/ModeKind";

/**
* Well-known provider id for the client-configurable custom LLM gateway.
Expand Down Expand Up @@ -84,7 +87,10 @@ export class CodexAcpClient {

async initialize(request: acp.InitializeRequest): Promise<void> {
await this.codexClient.initialize({
capabilities: null,
capabilities: {
experimentalApi: true,
requestAttestation: false,
},
clientInfo: {
name: request.clientInfo?.name ?? this.defaultClientInfo.name,
version: request.clientInfo?.version ?? this.defaultClientInfo.version,
Expand Down Expand Up @@ -330,6 +336,7 @@ export class CodexAcpClient {
sessionId: request.sessionId,
currentModelId: currentModelId,
models: codexModels,
collaborationMode: this.getCollaborationMode(response.thread.id),
modelProvider: response.modelProvider,
currentServiceTier: response.serviceTier as ServiceTier ?? null,
additionalDirectories,
Expand Down Expand Up @@ -357,6 +364,7 @@ export class CodexAcpClient {
sessionId: request.sessionId,
currentModelId: currentModelId,
models: codexModels,
collaborationMode: this.getCollaborationMode(response.thread.id),
modelProvider: response.modelProvider,
currentServiceTier: response.serviceTier as ServiceTier ?? null,
thread: historyResponse.thread,
Expand All @@ -383,6 +391,7 @@ export class CodexAcpClient {
sessionId: response.thread.id,
currentModelId: currentModelId,
models: codexModels,
collaborationMode: this.getCollaborationMode(response.thread.id),
modelProvider: response.modelProvider,
currentServiceTier: response.serviceTier as ServiceTier ?? null,
additionalDirectories,
Expand Down Expand Up @@ -417,6 +426,11 @@ export class CodexAcpClient {
await this.codexClient.runCompact({threadId: sessionId});
}

async getGoal(sessionId: string): Promise<ThreadGoal | null> {
const response = await this.codexClient.threadGoalGet({threadId: sessionId});
return response?.goal ?? null;
}

async setGoal(
sessionId: string,
objective: string,
Expand All @@ -429,11 +443,18 @@ export class CodexAcpClient {
}, onTurnStarted);
}

async setGoalStatus(sessionId: string, status: ThreadGoalStatus): Promise<void> {
async setGoalStatus(sessionId: string, status: ThreadGoalStatus): Promise<ThreadGoal> {
let updatedGoal: ThreadGoal | null = null;
await this.codexClient.runGoalSet({
threadId: sessionId,
status,
}, undefined, undefined, (goal) => {
updatedGoal = goal;
});
if (updatedGoal === null) {
throw new Error(`Goal update for session ${sessionId} returned no goal`);
}
return updatedGoal;
}

async resumeGoal(
Expand Down Expand Up @@ -679,6 +700,17 @@ export class CodexAcpClient {
}, onTurnStarted);
}

async setCollaborationMode(sessionId: string, mode: ModeKind, currentModelId: string): Promise<void> {
await this.codexClient.threadSettingsUpdate({
threadId: sessionId,
collaborationMode: createCodexCollaborationMode(mode, currentModelId),
});
}

private getCollaborationMode(sessionId: string): ModeKind {
return this.codexClient.getThreadSettings(sessionId)?.collaborationMode.mode ?? "default";
}

resolveTurnInterrupted(params: { threadId: string, turnId: string }): void {
this.codexClient.resolveTurnInterrupted(params.threadId, params.turnId);
}
Expand Down Expand Up @@ -845,6 +877,7 @@ export type SessionMetadata = {
sessionId: string,
currentModelId: string,
models: Model[],
collaborationMode: ModeKind,
modelProvider?: string | null,
currentServiceTier?: ServiceTier | null,
additionalDirectories: string[],
Expand Down
Loading