call goose serve from tauri frontend via goose-acp client (#8549)

Co-authored-by: Jack Amadeo <jackamadeo@squareup.com>
This commit is contained in:
Lifei Zhou
2026-04-16 17:34:19 +10:00
committed by GitHub
parent 625f2d75fe
commit 50ac3dc0b2
28 changed files with 4268 additions and 178 deletions
+94
View File
@@ -1,4 +1,12 @@
import { invoke } from "@tauri-apps/api/core";
import { USE_DIRECT_ACP } from "./acpFeatureFlag";
import * as directAcp from "./acpApi";
import * as sessionTracker from "./acpSessionTracker";
import {
setActiveMessageId,
clearActiveMessageId,
} from "./acpNotificationHandler";
import { searchSessionsViaExports } from "./sessionSearch";
export interface AcpProvider {
id: string;
@@ -21,6 +29,9 @@ export interface AcpPrepareSessionOptions {
/** Discover ACP providers installed on the system. */
export async function discoverAcpProviders(): Promise<AcpProvider[]> {
if (USE_DIRECT_ACP) {
return directAcp.listProviders();
}
return invoke("discover_acp_providers");
}
@@ -31,6 +42,39 @@ export async function acpSendMessage(
prompt: string,
options: AcpSendMessageOptions = {},
): Promise<void> {
if (USE_DIRECT_ACP) {
const { systemPrompt, personaId, images } = options;
const gooseSessionId = sessionTracker.getGooseSessionId(
sessionId,
personaId,
);
if (!gooseSessionId) {
throw new Error("Session not prepared. Call acpPrepareSession first.");
}
const hasSystem = systemPrompt && systemPrompt.trim().length > 0;
const effectivePrompt = hasSystem
? `<persona-instructions>\n${systemPrompt}\n</persona-instructions>\n\n<user-message>\n${prompt}\n</user-message>`
: prompt;
const content: import("@agentclientprotocol/sdk").ContentBlock[] = [
{ type: "text", text: effectivePrompt },
];
if (images) {
for (const [data, mimeType] of images) {
content.push({ type: "image", data, mimeType } as any);
}
}
const messageId = crypto.randomUUID();
setActiveMessageId(gooseSessionId, messageId);
await directAcp.prompt(gooseSessionId, content);
clearActiveMessageId(gooseSessionId);
return;
}
const { systemPrompt, workingDir, personaId, personaName, images } = options;
return invoke("acp_send_message", {
sessionId,
@@ -50,6 +94,16 @@ export async function acpPrepareSession(
providerId: string,
options: AcpPrepareSessionOptions = {},
): Promise<void> {
if (USE_DIRECT_ACP) {
const workingDir = options.workingDir ?? "~/.goose/artifacts";
await sessionTracker.prepareSession(
sessionId,
providerId,
workingDir,
options.personaId,
);
return;
}
const { workingDir, personaId } = options;
return invoke("acp_prepare_session", {
sessionId,
@@ -63,6 +117,10 @@ export async function acpSetModel(
sessionId: string,
modelId: string,
): Promise<void> {
if (USE_DIRECT_ACP) {
const gooseSessionId = sessionTracker.getGooseSessionId(sessionId);
return directAcp.setModel(gooseSessionId ?? sessionId, modelId);
}
return invoke("acp_set_model", {
sessionId,
modelId,
@@ -87,6 +145,9 @@ export interface AcpSessionSearchResult {
/** List all sessions known to the goose binary. */
export async function acpListSessions(): Promise<AcpSessionInfo[]> {
if (USE_DIRECT_ACP) {
return directAcp.listSessions();
}
return invoke("acp_list_sessions");
}
@@ -94,6 +155,9 @@ export async function acpSearchSessions(
query: string,
sessionIds: string[],
): Promise<AcpSessionSearchResult[]> {
if (USE_DIRECT_ACP) {
return searchSessionsViaExports(query, sessionIds);
}
return invoke("acp_search_sessions", { query, sessionIds });
}
@@ -108,6 +172,17 @@ export async function acpLoadSession(
gooseSessionId: string,
workingDir?: string,
): Promise<void> {
if (USE_DIRECT_ACP) {
const effectiveWorkingDir = workingDir ?? "~/.goose/artifacts";
await directAcp.loadSession(gooseSessionId, effectiveWorkingDir);
sessionTracker.registerSession(
sessionId,
gooseSessionId,
"goose",
effectiveWorkingDir,
);
return;
}
return invoke("acp_load_session", {
sessionId,
gooseSessionId,
@@ -117,11 +192,17 @@ export async function acpLoadSession(
/** Export a session as JSON via the goose binary. */
export async function acpExportSession(sessionId: string): Promise<string> {
if (USE_DIRECT_ACP) {
return directAcp.exportSession(sessionId);
}
return invoke("acp_export_session", { sessionId });
}
/** Import a session from JSON via the goose binary. Returns new session metadata. */
export async function acpImportSession(json: string): Promise<AcpSessionInfo> {
if (USE_DIRECT_ACP) {
return directAcp.importSession(json);
}
return invoke("acp_import_session", { json });
}
@@ -129,6 +210,11 @@ export async function acpImportSession(json: string): Promise<AcpSessionInfo> {
export async function acpDuplicateSession(
sessionId: string,
): Promise<AcpSessionInfo> {
if (USE_DIRECT_ACP) {
const gooseSessionId =
sessionTracker.getGooseSessionId(sessionId) ?? sessionId;
return directAcp.forkSession(gooseSessionId);
}
return invoke("acp_duplicate_session", { sessionId });
}
@@ -137,6 +223,14 @@ export async function acpCancelSession(
sessionId: string,
personaId?: string,
): Promise<boolean> {
if (USE_DIRECT_ACP) {
const gooseSessionId = sessionTracker.getGooseSessionId(
sessionId,
personaId,
);
await directAcp.cancelSession(gooseSessionId ?? sessionId);
return true;
}
return invoke("acp_cancel_session", {
sessionId,
personaId: personaId ?? null,