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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"vitest": "^5.0.1"
},
"dependencies": {
"@agentclientprotocol/sdk": "~1.5.0",
"@agentclientprotocol/sdk": "~1.8.0",
"@openai/codex": "^0.160.1",
"cross-spawn": "^7.0.6",
"diff": "^9.0.0",
Expand Down
11 changes: 7 additions & 4 deletions src/ACPSessionConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,13 @@ export class AcpV2Connection {
* is no v1 shape for them, so this bypasses `toV2SessionUpdates` entirely.
*/
async startReplayMessage(sessionId: string, kind: ReplayMessageKind, messageId: string): Promise<void> {
await this.client.notify(acpV2.methods.client.session.update, {
sessionId,
update: {sessionUpdate: kind, messageId, content: []},
});
// One literal per kind: TypeScript does not match a union-typed tag against the v2 union.
const message = {messageId, content: []};
const update: acpV2.SessionUpdate =
kind === "user_message" ? {sessionUpdate: kind, ...message}
: kind === "agent_message" ? {sessionUpdate: kind, ...message}
: {sessionUpdate: kind, ...message};
await this.client.notify(acpV2.methods.client.session.update, {sessionId, update});
}

/** `updateState`, with send failures caught and logged instead of propagated. */
Expand Down
4 changes: 3 additions & 1 deletion src/AcpV2Prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,14 @@ export function toV1PromptRequest(params: acpV2.PromptRequest): acp.PromptReques
* negotiated it).
*/
export function toV2IdleState(response: acp.PromptResponse): acpV2.StateUpdate {
// Every v1 stop reason is a v2 one. The v2 type is a union per stop reason, which TypeScript
// does not match against a union-typed `stopReason`, hence the cast.
return {
state: "idle",
stopReason: response.stopReason,
...(response.usage != null ? {usage: response.usage} : {}),
...(response._meta != null ? {_meta: response._meta} : {}),
};
} as acpV2.StateUpdate;
}

/**
Expand Down
13 changes: 8 additions & 5 deletions src/AcpV2SessionUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ export function toV2SessionUpdate(update: AcpSessionUpdate): acpV2.SessionUpdate
case "available_commands_update":
return {
...update,
availableCommands: update.availableCommands.map((command) => ({
availableCommands: update.availableCommands.map(({input, ...command}) => ({
...command,
...(command.input != null ? {input: {...command.input, type: "text" as const}} : {}),
...(input !== undefined ? {input: input && {...input, type: "text" as const}} : {}),
})),
};
// v2 removed the modes API. codex-acp never emits this (mode changes go out as
Expand Down Expand Up @@ -114,9 +114,9 @@ export function toV2SessionUpdate(update: AcpSessionUpdate): acpV2.SessionUpdate
...(content !== undefined ? {content: content && content.map(toV2ToolCallContent)} : {}),
};
}
// Subagent RFD (spec PR #1992, unmerged) uses a single upsert-style update. Sent under a
// `_`-prefixed tag because the RFD's `subagent_update` isn't in the v2 unstable schema yet;
// rename to `subagent_update` once it lands there. The AIR `nativeSubagentSessions` gate
// The subagent RFD uses a single upsert-style update. Sent under a `_`-prefixed tag because
// this payload predates the `subagent_update` now in the v2 unstable schema and does not
// have its fields yet; rename once it does. The AIR `nativeSubagentSessions` gate
// already ran upstream (whatever created this update), so no gate check is needed here.
case "subagent_spawned": {
const {subagentSessionId, name, task, _meta} = update;
Expand Down Expand Up @@ -145,6 +145,9 @@ export function toV2SessionUpdate(update: AcpSessionUpdate): acpV2.SessionUpdate
case "async_task_state_update":
return {...update, sessionUpdate: "_async_task_state_update"};
// Declared as a type but never emitted; no v2 rendering to give it yet.
case "subagent_update":
case "session_message":
case "session_message_chunk":
case "async_task_progress":
throw acp.RequestError.internalError(
undefined,
Expand Down
8 changes: 4 additions & 4 deletions src/CodexAcpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1461,10 +1461,10 @@ export class CodexAcpServer {
if (sessionState.codexReportedRunningTurnId === event.params.turn.id) {
sessionState.codexReportedRunningTurnId = null;
}
await this.reportUnownedTurnState(sessionState.sessionId, {
state: "idle",
stopReason: stopReasonForUnownedTurn(event.params.turn.status),
});
await this.reportUnownedTurnState(
sessionState.sessionId,
toV2IdleState({stopReason: stopReasonForUnownedTurn(event.params.turn.status)}),
);
}

/**
Expand Down
12 changes: 6 additions & 6 deletions src/CodexAuthMethod.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import type {AuthenticateRequest, AuthMethod, ClientCapabilities} from "@agentclientprotocol/sdk";
import type {AuthenticateRequest, AuthMethodAgent, ClientCapabilities} from "@agentclientprotocol/sdk";
import type * as acpV2 from "@agentclientprotocol/sdk/experimental/v2";
import {clientSupportsUrlElicitation} from "./ElicitationCapabilities";

Expand All @@ -15,7 +15,7 @@ export interface ApiKeyAuthRequest extends AuthenticateRequest {
} | null;
}

const ApiKeyAuthMethod: AuthMethod = {
const ApiKeyAuthMethod: AuthMethodAgent = {
id: "api-key",
name: "API Key",
description: "Use an API key to authenticate",
Expand All @@ -26,7 +26,7 @@ const ApiKeyAuthMethod: AuthMethod = {
}
}

const ChatGptAuthMethod: AuthMethod = {
const ChatGptAuthMethod: AuthMethodAgent = {
id: "chat-gpt",
name: "ChatGPT",
description: "Use ChatGPT to authenticate"
Expand All @@ -36,7 +36,7 @@ export interface ChatGPTAuthRequest extends AuthenticateRequest {
methodId: "chat-gpt";
}

const ChatGptDeviceCodeAuthMethod: AuthMethod = {
const ChatGptDeviceCodeAuthMethod: AuthMethodAgent = {
id: "chat-gpt-device-code",
name: "ChatGPT (device code)",
description: "Sign in to ChatGPT by opening a verification page and entering a one-time code"
Expand Down Expand Up @@ -69,8 +69,8 @@ export interface GatewayAuthRequest extends AuthenticateRequest {
};
}

export function getCodexAuthMethods(clientCapabilities?: ClientCapabilities | null, env: NodeJS.ProcessEnv = process.env): AuthMethod[] {
const authMethods: AuthMethod[] = [ApiKeyAuthMethod];
export function getCodexAuthMethods(clientCapabilities?: ClientCapabilities | null, env: NodeJS.ProcessEnv = process.env): AuthMethodAgent[] {
const authMethods: AuthMethodAgent[] = [ApiKeyAuthMethod];
if (!env["NO_BROWSER"]) {
authMethods.push(ChatGptAuthMethod);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
{
"name": "review",
"description": "Review changes",
"_meta": {
"kind": "hint"
},
"input": {
"hint": "focus",
"type": "text"
},
"_meta": {
"kind": "hint"
}
},
{
Expand Down