overhaul provider inventory and agent/model selection (#8652)
Signed-off-by: Bradley Axen <baxen@squareup.com>
This commit is contained in:
@@ -16,7 +16,7 @@ vi.mock("../acpConnection", () => ({
|
||||
}));
|
||||
|
||||
describe("dictation SDK wiring", () => {
|
||||
let client: any;
|
||||
let client: { goose: Record<string, ReturnType<typeof vi.fn>> };
|
||||
beforeEach(() => {
|
||||
client = {
|
||||
goose: {
|
||||
@@ -33,7 +33,9 @@ describe("dictation SDK wiring", () => {
|
||||
GooseDictationTranscribe: vi.fn().mockResolvedValue({ text: "hello" }),
|
||||
},
|
||||
};
|
||||
vi.mocked(getClient).mockResolvedValue(client);
|
||||
vi.mocked(getClient).mockResolvedValue(
|
||||
client as unknown as Awaited<ReturnType<typeof getClient>>,
|
||||
);
|
||||
});
|
||||
|
||||
it("getDictationConfig calls GooseDictationConfig and returns providers map", async () => {
|
||||
@@ -46,7 +48,7 @@ describe("dictation SDK wiring", () => {
|
||||
const result = await transcribeDictation({
|
||||
audio: "base64==",
|
||||
mimeType: "audio/webm",
|
||||
provider: "openai" as any,
|
||||
provider: "openai",
|
||||
});
|
||||
expect(client.goose.GooseDictationTranscribe).toHaveBeenCalledWith({
|
||||
audio: "base64==",
|
||||
@@ -58,7 +60,7 @@ describe("dictation SDK wiring", () => {
|
||||
|
||||
it("saveDictationModelSelection calls GooseDictationModelSelect", async () => {
|
||||
client.goose.GooseDictationModelSelect = vi.fn().mockResolvedValue({});
|
||||
await saveDictationModelSelection("local" as any, "tiny");
|
||||
await saveDictationModelSelection("local", "tiny");
|
||||
expect(client.goose.GooseDictationModelSelect).toHaveBeenCalledWith({
|
||||
provider: "local",
|
||||
modelId: "tiny",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { ContentBlock } from "@agentclientprotocol/sdk";
|
||||
import * as directAcp from "./acpApi";
|
||||
import * as sessionTracker from "./acpSessionTracker";
|
||||
import {
|
||||
getCatalogEntry,
|
||||
resolveAgentProviderCatalogId,
|
||||
} from "@/features/providers/providerCatalog";
|
||||
import {
|
||||
setActiveMessageId,
|
||||
clearActiveMessageId,
|
||||
@@ -25,9 +29,31 @@ export interface AcpPrepareSessionOptions {
|
||||
personaId?: string;
|
||||
}
|
||||
|
||||
export interface AcpCreateSessionOptions extends AcpPrepareSessionOptions {
|
||||
modelId?: string | null;
|
||||
}
|
||||
|
||||
/** Discover ACP providers installed on the system. */
|
||||
export async function discoverAcpProviders(): Promise<AcpProvider[]> {
|
||||
return directAcp.listProviders();
|
||||
const providers = await directAcp.listProviders();
|
||||
const seen = new Set<string>();
|
||||
|
||||
return providers
|
||||
.map((provider) => {
|
||||
const catalogId = resolveAgentProviderCatalogId(
|
||||
provider.id,
|
||||
provider.label,
|
||||
);
|
||||
if (!catalogId || seen.has(catalogId)) {
|
||||
return null;
|
||||
}
|
||||
seen.add(catalogId);
|
||||
return {
|
||||
id: catalogId,
|
||||
label: getCatalogEntry(catalogId)?.displayName ?? provider.label,
|
||||
};
|
||||
})
|
||||
.filter((provider): provider is AcpProvider => provider !== null);
|
||||
}
|
||||
|
||||
/** Send a message to an ACP agent. Response streams via Tauri events. */
|
||||
@@ -79,13 +105,13 @@ export async function acpPrepareSession(
|
||||
providerId: string,
|
||||
workingDir: string,
|
||||
options: AcpPrepareSessionOptions = {},
|
||||
): Promise<void> {
|
||||
): Promise<string> {
|
||||
const sid = sessionId.slice(0, 8);
|
||||
const t0 = performance.now();
|
||||
perfLog(
|
||||
`[perf:prepare] ${sid} acpPrepareSession start (provider=${providerId})`,
|
||||
);
|
||||
await sessionTracker.prepareSession(
|
||||
const gooseSessionId = await sessionTracker.prepareSession(
|
||||
sessionId,
|
||||
providerId,
|
||||
workingDir,
|
||||
@@ -94,6 +120,31 @@ export async function acpPrepareSession(
|
||||
perfLog(
|
||||
`[perf:prepare] ${sid} acpPrepareSession done in ${(performance.now() - t0).toFixed(1)}ms`,
|
||||
);
|
||||
return gooseSessionId;
|
||||
}
|
||||
|
||||
export async function acpCreateSession(
|
||||
providerId: string,
|
||||
workingDir: string,
|
||||
options: AcpCreateSessionOptions = {},
|
||||
): Promise<{ sessionId: string }> {
|
||||
const localSessionId = crypto.randomUUID();
|
||||
const gooseSessionId = await acpPrepareSession(
|
||||
localSessionId,
|
||||
providerId,
|
||||
workingDir,
|
||||
options,
|
||||
);
|
||||
sessionTracker.registerSession(
|
||||
gooseSessionId,
|
||||
gooseSessionId,
|
||||
providerId,
|
||||
workingDir,
|
||||
);
|
||||
if (options.modelId) {
|
||||
await directAcp.setModel(gooseSessionId, options.modelId);
|
||||
}
|
||||
return { sessionId: gooseSessionId };
|
||||
}
|
||||
|
||||
export async function acpSetModel(
|
||||
|
||||
@@ -455,7 +455,6 @@ function handleShared(sessionId: string, update: SessionUpdate): void {
|
||||
currentModelId;
|
||||
|
||||
const sessionStore = useChatSessionStore.getState();
|
||||
sessionStore.setSessionModels(sessionId, availableModels);
|
||||
sessionStore.updateSession(
|
||||
sessionId,
|
||||
{ modelId: currentModelId, modelName: currentModelName },
|
||||
|
||||
@@ -115,8 +115,10 @@ export async function prepareSession(
|
||||
`[perf:prepare] ${sid} tracker setProvider(${providerId}) in ${(performance.now() - tProv).toFixed(1)}ms (goose_sid=${gooseSid})`,
|
||||
);
|
||||
|
||||
prepared.set(key, { gooseSessionId, providerId, workingDir });
|
||||
prepared.set(sessionId, { gooseSessionId, providerId, workingDir });
|
||||
const entry = { gooseSessionId, providerId, workingDir };
|
||||
prepared.set(key, entry);
|
||||
prepared.set(sessionId, entry);
|
||||
prepared.set(gooseSessionId, entry);
|
||||
gooseToLocal.set(gooseSessionId, sessionId);
|
||||
notifySessionRegistered(sessionId, gooseSessionId);
|
||||
|
||||
@@ -161,6 +163,7 @@ export function registerSession(
|
||||
}
|
||||
|
||||
prepared.set(sessionId, entry);
|
||||
prepared.set(gooseSessionId, entry);
|
||||
gooseToLocal.set(gooseSessionId, sessionId);
|
||||
notifySessionRegistered(sessionId, gooseSessionId);
|
||||
|
||||
|
||||
@@ -163,7 +163,14 @@
|
||||
"createProject": "Create project",
|
||||
"generalChatWithoutProject": "General chat without project context",
|
||||
"loading": "Loading...",
|
||||
"loadingModels": "Loading models...",
|
||||
"model": "Model",
|
||||
"allModels": "All models",
|
||||
"searchModels": "Search models...",
|
||||
"recommended": "Recommended",
|
||||
"noModelsAvailable": "No models available",
|
||||
"noSearchResults": "No matching models",
|
||||
"showAllModels": "Browse all models",
|
||||
"noProject": "No project",
|
||||
"selectModel": "Select model",
|
||||
"selectProject": "Select project",
|
||||
|
||||
@@ -163,7 +163,14 @@
|
||||
"createProject": "Crear proyecto",
|
||||
"generalChatWithoutProject": "Chat general sin contexto de proyecto",
|
||||
"loading": "Cargando...",
|
||||
"loadingModels": "Cargando modelos...",
|
||||
"model": "Modelo",
|
||||
"allModels": "Todos los modelos",
|
||||
"searchModels": "Buscar modelos...",
|
||||
"recommended": "Recomendados",
|
||||
"noModelsAvailable": "No hay modelos disponibles",
|
||||
"noSearchResults": "Sin resultados",
|
||||
"showAllModels": "Ver todos los modelos",
|
||||
"noProject": "Sin proyecto",
|
||||
"selectModel": "Seleccionar modelo",
|
||||
"selectProject": "Seleccionar proyecto",
|
||||
|
||||
Reference in New Issue
Block a user