Files
tkmind_go/ui/goose2/src/shared/api/acpApi.ts
T
2026-04-21 16:19:20 +00:00

194 lines
5.5 KiB
TypeScript

import type {
ContentBlock,
NewSessionResponse,
LoadSessionResponse,
PromptResponse,
} from "@agentclientprotocol/sdk";
import { getClient } from "./acpConnection";
import { perfLog } from "@/shared/lib/perfLog";
export interface AcpProvider {
id: string;
label: string;
}
export interface AcpSessionInfo {
sessionId: string;
title: string | null;
updatedAt: string | null;
messageCount: number;
}
const DEPRECATED_PROVIDER_IDS = new Set(["claude-code", "codex", "gemini-cli"]);
const DEFAULT_PROVIDER: AcpProvider = {
id: "goose",
label: "Goose (Default)",
};
export async function listProviders(): Promise<AcpProvider[]> {
const client = await getClient();
const result = await client.goose.GooseProvidersList({
providerIds: [],
});
const providers = result.entries
.filter((entry) => !DEPRECATED_PROVIDER_IDS.has(entry.providerId))
.map((entry) => ({
id: entry.providerId,
label: entry.providerName,
}));
return [DEFAULT_PROVIDER, ...providers];
}
export async function listSessions(): Promise<AcpSessionInfo[]> {
const client = await getClient();
// GooseClient.unstable_listSessions doesn't work with SDK 0.19 (renamed to listSessions).
// Bypass GooseClient and call the connection directly. Fix when ui/acp is updated.
// biome-ignore lint/suspicious/noExplicitAny: SDK doesn't expose conn property
const conn = (client as any).conn;
const response = await conn.listSessions({});
return response.sessions.map(
(info: {
sessionId: string;
title?: string;
updatedAt?: string;
_meta?: Record<string, unknown>;
}) => ({
sessionId: info.sessionId,
title: info.title ?? null,
updatedAt: info.updatedAt ?? null,
messageCount: (info._meta?.messageCount as number) ?? 0,
}),
);
}
export async function exportSession(sessionId: string): Promise<string> {
const client = await getClient();
const result = await client.goose.GooseSessionExport({ sessionId });
// biome-ignore lint/suspicious/noExplicitAny: SDK doesn't expose data field on export result
return (result as any).data;
}
export async function importSession(json: string): Promise<AcpSessionInfo> {
const client = await getClient();
const result = await client.goose.GooseSessionImport({ data: json });
return result as unknown as AcpSessionInfo;
}
export async function forkSession(sessionId: string): Promise<AcpSessionInfo> {
const client = await getClient();
const response = await client.unstable_forkSession({
sessionId,
cwd: "~/.goose/artifacts",
});
return {
sessionId: response.sessionId,
title: (response._meta?.title as string) ?? null,
updatedAt: null,
messageCount: (response._meta?.messageCount as number) ?? 0,
};
}
export async function setModel(
sessionId: string,
modelId: string,
): Promise<void> {
const sid = sessionId.slice(0, 8);
const tClient = performance.now();
const client = await getClient();
const tCall = performance.now();
await client.setSessionConfigOption({
sessionId,
configId: "model",
value: modelId,
});
perfLog(
`[perf:api] ${sid} setModel(${modelId}) getClient=${(tCall - tClient).toFixed(1)}ms wire=${(performance.now() - tCall).toFixed(1)}ms`,
);
}
export async function setProvider(
sessionId: string,
providerId: string,
): Promise<void> {
const sid = sessionId.slice(0, 8);
const tClient = performance.now();
const client = await getClient();
const tCall = performance.now();
await client.setSessionConfigOption({
sessionId,
configId: "provider",
value: providerId,
});
perfLog(
`[perf:api] ${sid} setProvider(${providerId}) getClient=${(tCall - tClient).toFixed(1)}ms wire=${(performance.now() - tCall).toFixed(1)}ms`,
);
}
export async function updateWorkingDir(
sessionId: string,
workingDir: string,
): Promise<void> {
const client = await getClient();
await client.extMethod("goose/working_dir/update", { sessionId, workingDir });
}
export async function cancelSession(sessionId: string): Promise<void> {
const client = await getClient();
await client.cancel({ sessionId });
}
export async function newSession(
workingDir: string,
providerId?: string,
): Promise<NewSessionResponse> {
const tClient = performance.now();
const client = await getClient();
const request: Parameters<typeof client.newSession>[0] & {
meta?: Record<string, string>;
} = {
cwd: workingDir,
mcpServers: [],
};
if (providerId) {
request.meta = { provider: providerId };
}
const tCall = performance.now();
const response = await client.newSession(request);
const sid = response.sessionId.slice(0, 8);
perfLog(
`[perf:api] ${sid} newSession getClient=${(tCall - tClient).toFixed(1)}ms wire=${(performance.now() - tCall).toFixed(1)}ms`,
);
return response;
}
export async function loadSession(
sessionId: string,
workingDir: string,
): Promise<LoadSessionResponse> {
const sid = sessionId.slice(0, 8);
const tClient = performance.now();
const client = await getClient();
const tCall = performance.now();
const response = await client.loadSession({
sessionId,
cwd: workingDir,
mcpServers: [],
});
perfLog(
`[perf:api] ${sid} loadSession getClient=${(tCall - tClient).toFixed(1)}ms wire=${(performance.now() - tCall).toFixed(1)}ms`,
);
return response;
}
export async function prompt(
sessionId: string,
content: ContentBlock[],
): Promise<PromptResponse> {
const client = await getClient();
return client.prompt({ sessionId, prompt: content });
}