refactor(packages/coding-agent): restructured acp 0.25 session state

- Removed `userMessageId` from `AcpAgent` prompt state and response payloads.
- Removed `models` from new/load/resume/fork session responses and deleted model-state building.
- Removed `unstable_setSessionModel` and routed model changes through `setSessionConfigOption`.
This commit is contained in:
can1357
2026-06-13 00:20:05 +02:00
parent 074857fea9
commit 5691a039de
2 changed files with 13 additions and 59 deletions
@@ -31,14 +31,11 @@ import {
type ResumeSessionResponse,
type SessionConfigOption,
type SessionInfo,
type SessionModelState,
type SessionModeState,
type SessionNotification,
type SessionUpdate,
type SetSessionConfigOptionRequest,
type SetSessionConfigOptionResponse,
type SetSessionModelRequest,
type SetSessionModelResponse,
type SetSessionModeRequest,
type SetSessionModeResponse,
type Usage,
@@ -121,7 +118,6 @@ type PromptQueueState = {
type PromptLifecycleError = Error & { readonly code: "ACP_SESSION_CLOSED" };
type PromptTurnState = {
userMessageId: string;
cancelRequested: boolean;
settled: boolean;
/**
@@ -465,7 +461,6 @@ export class AcpAgent implements Agent {
const response: NewSessionResponse = {
sessionId: record.session.sessionId,
configOptions: this.#buildConfigOptions(record.session),
models: this.#buildModelState(record.session),
modes: this.#buildModeState(record.session),
};
this.#scheduleBootstrapUpdates(record.session.sessionId);
@@ -478,7 +473,6 @@ export class AcpAgent implements Agent {
await this.#replaySessionHistory(record);
const response: LoadSessionResponse = {
configOptions: this.#buildConfigOptions(record.session),
models: this.#buildModelState(record.session),
modes: this.#buildModeState(record.session),
};
this.#scheduleBootstrapUpdates(record.session.sessionId);
@@ -507,7 +501,6 @@ export class AcpAgent implements Agent {
const record = await this.#resumeManagedSession(params.sessionId, params.cwd, params.mcpServers ?? []);
const response: ResumeSessionResponse = {
configOptions: this.#buildConfigOptions(record.session),
models: this.#buildModelState(record.session),
modes: this.#buildModeState(record.session),
};
this.#scheduleBootstrapUpdates(record.session.sessionId);
@@ -520,7 +513,6 @@ export class AcpAgent implements Agent {
const response: ForkSessionResponse = {
sessionId: record.session.sessionId,
configOptions: this.#buildConfigOptions(record.session),
models: this.#buildModelState(record.session),
modes: this.#buildModeState(record.session),
};
this.#scheduleBootstrapUpdates(record.session.sessionId);
@@ -588,13 +580,6 @@ export class AcpAgent implements Agent {
return { configOptions: this.#buildConfigOptions(record.session) };
}
async unstable_setSessionModel(params: SetSessionModelRequest): Promise<SetSessionModelResponse> {
const record = this.#getSessionRecord(params.sessionId);
await this.#setModelById(record.session, params.modelId);
await this.#pushConfigOptionUpdate(record);
return {};
}
async prompt(params: PromptRequest): Promise<PromptResponse> {
const record = this.#getSessionRecord(params.sessionId);
const activeTurn = record.promptTurn;
@@ -633,7 +618,6 @@ export class AcpAgent implements Agent {
const converted = this.#convertPromptBlocks(params.prompt);
const pendingPrompt = Promise.withResolvers<PromptResponse>();
record.promptTurn = {
userMessageId: params.messageId ?? crypto.randomUUID(),
cancelRequested: false,
settled: false,
cleanup: undefined,
@@ -766,7 +750,6 @@ export class AcpAgent implements Agent {
this.#cloneUsageStatistics(record.session.sessionManager.getUsageStatistics()),
record.session.sessionManager.getUsageStatistics(),
),
userMessageId: promptTurn?.userMessageId,
});
return;
}
@@ -844,7 +827,6 @@ export class AcpAgent implements Agent {
this.#finishPrompt(record, {
stopReason: "cancelled",
usage: this.#buildTurnUsage(promptTurn.usageBaseline, record.session.sessionManager.getUsageStatistics()),
userMessageId: promptTurn.userMessageId,
});
return cleanup;
}
@@ -1162,7 +1144,6 @@ export class AcpAgent implements Agent {
this.#finishPrompt(record, {
stopReason: this.#resolveStopReason(event, promptTurn.cancelRequested),
usage: this.#buildTurnUsage(promptTurn.usageBaseline, record.session.sessionManager.getUsageStatistics()),
userMessageId: promptTurn.userMessageId,
});
}
}
@@ -1385,28 +1366,6 @@ export class AcpAgent implements Agent {
return configOptions;
}
#buildModelState(session: AgentSession): SessionModelState | undefined {
const models = session.getAvailableModels();
if (models.length === 0) {
return undefined;
}
const availableModels = models.map(model => ({
modelId: this.#toModelId(model),
name: model.name,
description: `${model.provider}/${model.id}`,
}));
const currentModelId = session.model ? this.#toModelId(session.model) : availableModels[0]?.modelId;
if (!currentModelId) {
return undefined;
}
return {
availableModels,
currentModelId,
};
}
#buildThinkingOptions(session: AgentSession): Array<{ value: string; name: string; description?: string }> {
return [
{ value: THINKING_OFF, name: "Off" },
+13 -18
View File
@@ -488,13 +488,16 @@ describe("ACP agent", () => {
expectAcpStructure(zNewSessionResponse, first);
expectAcpStructure(zNewSessionResponse, second);
expect(first.models?.availableModels.map(model => model.modelId)).toEqual(
const modelOption = first.configOptions?.find(opt => opt.id === "model");
expect(modelOption?.type).toBe("select");
expect((modelOption as any).options?.map((opt: any) => opt.value)).toEqual(
TEST_MODELS.map(model => `${model.provider}/${model.id}`),
);
await harness.agent.unstable_setSessionModel({
await harness.agent.setSessionConfigOption({
sessionId: first.sessionId,
modelId: `${TEST_MODELS[1]!.provider}/${TEST_MODELS[1]!.id}`,
configId: "model",
value: `${TEST_MODELS[1]!.provider}/${TEST_MODELS[1]!.id}`,
});
await harness.agent.setSessionConfigOption({
sessionId: first.sessionId,
@@ -914,16 +917,14 @@ describe("ACP agent", () => {
const live = await harness.agent.newSession({ cwd: harness.cwdB, mcpServers: [] });
const response = await harness.agent.prompt({
sessionId: live.sessionId,
messageId: "05b17a6f-b310-4be7-b767-6b4f3a84eb63",
prompt: [{ type: "text", text: "ping" }],
} as PromptRequest);
});
expectAcpStructure(zPromptResponse, response);
expectAcpNotifications(harness.updates);
const liveChunks = harness.updates.filter(
update => update.sessionId === live.sessionId && update.update.sessionUpdate === "agent_message_chunk",
);
expect(response.userMessageId).toBe("05b17a6f-b310-4be7-b767-6b4f3a84eb63");
expect(response.usage).toEqual({
inputTokens: 10,
outputTokens: 5,
@@ -1508,9 +1509,8 @@ describe("ACP agent", () => {
const firstPrompt = harness.agent.prompt({
sessionId: created.sessionId,
messageId: "00000000-0000-4000-8000-000000000029",
prompt: [{ type: "text", text: "wait for cleanup" }],
} as PromptRequest);
});
await idleBlocked;
try {
@@ -1519,8 +1519,7 @@ describe("ACP agent", () => {
expect(session.waitForIdleCalls).toBe(1);
unblockIdle();
const response = await firstPrompt;
expect(response.userMessageId).toBe("00000000-0000-4000-8000-000000000029");
await firstPrompt;
} finally {
unblockIdle();
harness.abortController.abort();
@@ -1548,9 +1547,8 @@ describe("ACP agent", () => {
const prompt = harness.agent.prompt({
sessionId: created.sessionId,
messageId: "00000000-0000-4000-8000-000000000047",
prompt: [{ type: "text", text: "wait for async delivery" }],
} as PromptRequest);
});
await deliveryBlocked.promise;
try {
@@ -1559,8 +1557,7 @@ describe("ACP agent", () => {
expect(session.waitForIdleCalls).toBe(1);
releaseDelivery();
const response = await prompt;
expect(response.userMessageId).toBe("00000000-0000-4000-8000-000000000047");
await prompt;
expect(session.waitForIdleCalls).toBe(2);
expect(drainCalls).toBe(2);
} finally {
@@ -1903,16 +1900,14 @@ describe("ACP agent", () => {
const created = await harness.agent.newSession({ cwd: harness.cwdA, mcpServers: [] });
const session = harness.findSession(created.sessionId)!;
const response = await harness.agent.prompt({
await harness.agent.prompt({
sessionId: created.sessionId,
messageId: "00000000-0000-4000-8000-000000000002",
prompt: [{ type: "text", text: "/fast status" }],
} as PromptRequest);
});
const chunks = harness.updates.filter(
update => update.sessionId === created.sessionId && update.update.sessionUpdate === "agent_message_chunk",
);
expect(response.userMessageId).toBe("00000000-0000-4000-8000-000000000002");
expect(session.promptCalls).toEqual([]);
expect(
chunks.some(