diff --git a/ui/goose2/src/features/chat/hooks/__tests__/useChat.attachments.test.ts b/ui/goose2/src/features/chat/hooks/__tests__/useChat.attachments.test.ts index 573bf4ae1c..564591c1c6 100644 --- a/ui/goose2/src/features/chat/hooks/__tests__/useChat.attachments.test.ts +++ b/ui/goose2/src/features/chat/hooks/__tests__/useChat.attachments.test.ts @@ -141,11 +141,8 @@ describe("useChat attachments", () => { { type: "text", text: "" }, { type: "image", - source: { - type: "base64", - mediaType: "image/png", - data: "abc123", - }, + data: "abc123", + mimeType: "image/png", }, ]); expect(mockAcpSendMessage).toHaveBeenCalledWith("session-1", " ", { diff --git a/ui/goose2/src/features/chat/hooks/useChat.ts b/ui/goose2/src/features/chat/hooks/useChat.ts index ca16fa3402..f62d6963d0 100644 --- a/ui/goose2/src/features/chat/hooks/useChat.ts +++ b/ui/goose2/src/features/chat/hooks/useChat.ts @@ -94,7 +94,7 @@ function markMessageStopped(sessionId: string, messageId: string) { completionStatus: "stopped", }, content: message.content.map((block) => - block.type === "toolRequest" && block.status === "executing" + block.type === "toolRequest" && block.status === "in_progress" ? { ...block, status: "stopped" } : block, ), @@ -215,11 +215,8 @@ export function useChat( for (const img of images) { userMessage.content.push({ type: "image", - source: { - type: "base64", - mediaType: img.mimeType, - data: img.base64, - }, + data: img.base64, + mimeType: img.mimeType, }); } } diff --git a/ui/goose2/src/features/chat/lib/__tests__/toolChainGrouping.test.ts b/ui/goose2/src/features/chat/lib/__tests__/toolChainGrouping.test.ts index 426daefb0b..f41afe24f3 100644 --- a/ui/goose2/src/features/chat/lib/__tests__/toolChainGrouping.test.ts +++ b/ui/goose2/src/features/chat/lib/__tests__/toolChainGrouping.test.ts @@ -74,13 +74,13 @@ describe("getToolItemStatus", () => { it("treats response.isError as error", () => { expect(getToolItemStatus(pair("a", { name: "x" }, { isError: true }))).toBe( - "error", + "failed", ); }); it("uses request status when no response yet", () => { - expect(getToolItemStatus(pair("a", { status: "executing" }))).toBe( - "executing", + expect(getToolItemStatus(pair("a", { status: "in_progress" }))).toBe( + "in_progress", ); }); }); @@ -89,17 +89,17 @@ describe("getChainAggregateStatus", () => { it("prefers error over pending and executing", () => { expect( getChainAggregateStatus([ - pair("a", { status: "executing" }), + pair("a", { status: "in_progress" }), pair("b", { name: "x" }, { isError: true }), pair("c", { status: "pending" }), ]), - ).toBe("error"); + ).toBe("failed"); }); it("prefers stopped over executing/pending when there is no error", () => { expect( getChainAggregateStatus([ - pair("a", { status: "executing" }), + pair("a", { status: "in_progress" }), pair("b", { status: "stopped" }), ]), ).toBe("stopped"); @@ -109,9 +109,9 @@ describe("getChainAggregateStatus", () => { expect( getChainAggregateStatus([ pair("a", { name: "x" }, {}), - pair("b", { status: "executing" }), + pair("b", { status: "in_progress" }), ]), - ).toBe("executing"); + ).toBe("in_progress"); }); it("returns pending when only pending is present", () => { diff --git a/ui/goose2/src/features/chat/lib/toolChainGrouping.ts b/ui/goose2/src/features/chat/lib/toolChainGrouping.ts index 8c975e805d..5963457d1c 100644 --- a/ui/goose2/src/features/chat/lib/toolChainGrouping.ts +++ b/ui/goose2/src/features/chat/lib/toolChainGrouping.ts @@ -23,7 +23,7 @@ export function getToolItemName(item: ToolChainItem): string { export function getToolItemStatus(item: ToolChainItem): ToolCallStatus { if (item.response) { - return item.response.isError ? "error" : "completed"; + return item.response.isError ? "failed" : "completed"; } return item.request?.status ?? "completed"; } @@ -35,10 +35,10 @@ export function getToolItemStatus(item: ToolChainItem): ToolCallStatus { export function getChainAggregateStatus( items: ToolChainItem[], ): ToolCallStatus { - if (items.some((i) => getToolItemStatus(i) === "error")) return "error"; + if (items.some((i) => getToolItemStatus(i) === "failed")) return "failed"; if (items.some((i) => getToolItemStatus(i) === "stopped")) return "stopped"; - if (items.some((i) => getToolItemStatus(i) === "executing")) - return "executing"; + if (items.some((i) => getToolItemStatus(i) === "in_progress")) + return "in_progress"; if (items.some((i) => getToolItemStatus(i) === "pending")) return "pending"; return "completed"; } diff --git a/ui/goose2/src/features/chat/lib/toolStatusMap.ts b/ui/goose2/src/features/chat/lib/toolStatusMap.ts index c8d6741ace..252090cb4f 100644 --- a/ui/goose2/src/features/chat/lib/toolStatusMap.ts +++ b/ui/goose2/src/features/chat/lib/toolStatusMap.ts @@ -3,8 +3,8 @@ import type { ToolPart } from "@/shared/ui/ai-elements/tool"; export const toolStatusMap: Record = { pending: "input-streaming", - executing: "input-available", + in_progress: "input-available", completed: "output-available", - error: "output-error", + failed: "output-error", stopped: "output-denied", }; diff --git a/ui/goose2/src/features/chat/ui/MessageBubble.tsx b/ui/goose2/src/features/chat/ui/MessageBubble.tsx index 19b5575ed4..3dee123a15 100644 --- a/ui/goose2/src/features/chat/ui/MessageBubble.tsx +++ b/ui/goose2/src/features/chat/ui/MessageBubble.tsx @@ -219,10 +219,7 @@ function renderContentBlock( } case "image": { const ic = content as ImageContent; - const src = - ic.source.type === "base64" - ? `data:${ic.source.mediaType};base64,${ic.source.data}` - : ic.source.url; + const src = ic.uri ?? `data:${ic.mimeType};base64,${ic.data}`; return ( { - if (status === "executing") { + if (status === "in_progress") { const origin = startedAt ?? Date.now(); setElapsed(Math.floor((Date.now() - origin) / 1000)); const interval = setInterval(() => { @@ -282,7 +282,7 @@ export function ToolCallAdapter({ [args, name], ); const elapsedSeconds = - status === "executing" && elapsed >= 3 ? elapsed : undefined; + status === "in_progress" && elapsed >= 3 ? elapsed : undefined; const { resolveMarkdownHref, openResolvedPath } = useArtifactPolicyContext(); diff --git a/ui/goose2/src/features/chat/ui/ToolChainCards.tsx b/ui/goose2/src/features/chat/ui/ToolChainCards.tsx index fa3df78350..595a8e9dbd 100644 --- a/ui/goose2/src/features/chat/ui/ToolChainCards.tsx +++ b/ui/goose2/src/features/chat/ui/ToolChainCards.tsx @@ -17,25 +17,25 @@ import type { ToolCallStatus } from "@/shared/types/messages"; export type { ToolChainItem }; const STEP_BULLET_ICON: Record< - Exclude, + Exclude, LucideIcon > = { pending: CircleIcon, - executing: ClockIcon, + in_progress: ClockIcon, completed: Check, }; const STEP_BULLET_CLASS: Record< - Exclude, + Exclude, string > = { pending: "text-muted-foreground/70", - executing: "text-muted-foreground animate-pulse", + in_progress: "text-muted-foreground animate-pulse", completed: "text-muted-foreground", }; function ChainStepBullet({ status }: { status: ToolCallStatus }) { - if (status === "error") { + if (status === "failed") { return ( ); @@ -172,7 +172,7 @@ export function ToolChainCards({ toolItems }: { toolItems: ToolChainItem[] }) { const aggregateStatus = getChainAggregateStatus(toolItems); const summary = summarizeToolChainSteps(primaryItems); const isActiveChain = - aggregateStatus === "executing" || aggregateStatus === "pending"; + aggregateStatus === "in_progress" || aggregateStatus === "pending"; // Chains that mount as already-complete (history replay) start collapsed; // live chains mount mid-execution, stay open while running, and auto-collapse // once they finish so the chat keeps moving forward. diff --git a/ui/goose2/src/features/chat/ui/__tests__/MessageBubble.test.tsx b/ui/goose2/src/features/chat/ui/__tests__/MessageBubble.test.tsx index 90c0a6c93f..3e9cca9137 100644 --- a/ui/goose2/src/features/chat/ui/__tests__/MessageBubble.test.tsx +++ b/ui/goose2/src/features/chat/ui/__tests__/MessageBubble.test.tsx @@ -349,7 +349,7 @@ describe("MessageBubble", () => { id: "tool-1", name: "readFile", arguments: { path: "/tmp/demo.txt" }, - status: "executing", + status: "in_progress", }, { type: "toolResponse", @@ -374,7 +374,7 @@ describe("MessageBubble", () => { id: "tool-1", name: "readFile", arguments: {}, - status: "executing", + status: "in_progress", }, { type: "toolResponse", @@ -410,7 +410,7 @@ describe("MessageBubble", () => { id: "tool-1", name: "readFile", arguments: {}, - status: "executing", + status: "in_progress", }, { type: "toolResponse", diff --git a/ui/goose2/src/features/chat/ui/__tests__/ToolChainCards.test.tsx b/ui/goose2/src/features/chat/ui/__tests__/ToolChainCards.test.tsx index fc69abcdf0..7be6ea0198 100644 --- a/ui/goose2/src/features/chat/ui/__tests__/ToolChainCards.test.tsx +++ b/ui/goose2/src/features/chat/ui/__tests__/ToolChainCards.test.tsx @@ -79,7 +79,7 @@ describe("ToolChainCards", () => { toolItems={[ pair("Shell · npm test", { completed: true }), pair("Shell · npm build", { - status: "executing", + status: "in_progress", completed: false, }), ]} @@ -97,7 +97,7 @@ describe("ToolChainCards", () => { toolItems={[ pair("Edit · src/a.ts"), pair("Edit · src/b.ts", { - status: "executing", + status: "in_progress", completed: false, }), ]} @@ -129,7 +129,7 @@ describe("ToolChainCards", () => { it("auto-collapses a live chain once every step has completed", () => { const a = pair("Edit · src/a.ts"); const bRequest = pair("Edit · src/b.ts", { - status: "executing", + status: "in_progress", completed: false, }); const { rerender } = render(); @@ -171,7 +171,7 @@ describe("ToolChainCards", () => { />, ); const wrapper = container.querySelector('[data-role="tool-chain-card"]'); - expect(wrapper?.getAttribute("data-status")).toBe("error"); + expect(wrapper?.getAttribute("data-status")).toBe("failed"); }); it("renders a step rail row for each child inside a chain", () => { @@ -181,7 +181,7 @@ describe("ToolChainCards", () => { pair("Edit · src/a.ts"), pair("Edit · src/b.ts"), pair("Edit · src/c.ts", { - status: "executing", + status: "in_progress", completed: false, }), ]} @@ -317,7 +317,7 @@ describe("ToolChainCards", () => { it("does not surface the chain summary while the chain is still active", () => { const a = pair("Edit · src/a.ts"); const b = pair("Edit · src/b.ts", { - status: "executing", + status: "in_progress", completed: false, }); if (a.request) { diff --git a/ui/goose2/src/features/providers/api/credentials.ts b/ui/goose2/src/features/providers/api/credentials.ts index 27e8db7100..94514f98ec 100644 --- a/ui/goose2/src/features/providers/api/credentials.ts +++ b/ui/goose2/src/features/providers/api/credentials.ts @@ -14,10 +14,7 @@ export async function getProviderConfig( ): Promise { const client = await getClient(); const response = await client.goose.GooseProvidersConfigRead({ providerId }); - return response.fields.map((field) => ({ - ...field, - value: field.value ?? null, - })); + return response.fields; } export async function saveProviderConfig( diff --git a/ui/goose2/src/shared/api/__tests__/acpNotificationHandler.test.ts b/ui/goose2/src/shared/api/__tests__/acpNotificationHandler.test.ts index 8c43c44ad1..4f32e894dc 100644 --- a/ui/goose2/src/shared/api/__tests__/acpNotificationHandler.test.ts +++ b/ui/goose2/src/shared/api/__tests__/acpNotificationHandler.test.ts @@ -239,7 +239,7 @@ describe("acpNotificationHandler", () => { type: "toolRequest", id: "tool-b", name: "grep", - status: "executing", + status: "in_progress", }); expect(message.content[2]).toMatchObject({ type: "toolResponse", diff --git a/ui/goose2/src/shared/api/__tests__/acpToolCallStatus.test.ts b/ui/goose2/src/shared/api/__tests__/acpToolCallStatus.test.ts index d2cb678423..024c78e115 100644 --- a/ui/goose2/src/shared/api/__tests__/acpToolCallStatus.test.ts +++ b/ui/goose2/src/shared/api/__tests__/acpToolCallStatus.test.ts @@ -65,7 +65,7 @@ describe("ACP tool call status handling", () => { expect(assistant?.content[0]).toMatchObject({ type: "toolRequest", id: "tool-1", - status: "error", + status: "failed", }); expect(assistant?.content[1]).toMatchObject({ type: "toolResponse", @@ -114,7 +114,7 @@ describe("ACP tool call status handling", () => { expect(message.content[0]).toMatchObject({ type: "toolRequest", id: "tool-1", - status: "error", + status: "failed", }); expect(message.content[1]).toMatchObject({ type: "toolResponse", diff --git a/ui/goose2/src/shared/api/acpNotificationHandler.ts b/ui/goose2/src/shared/api/acpNotificationHandler.ts index 5ca3bc589e..8ba97f9866 100644 --- a/ui/goose2/src/shared/api/acpNotificationHandler.ts +++ b/ui/goose2/src/shared/api/acpNotificationHandler.ts @@ -7,7 +7,6 @@ import { useChatSessionStore } from "@/features/chat/stores/chatSessionStore"; import { getBufferedMessage } from "@/features/chat/hooks/replayBuffer"; import type { ToolCallLocation, - ToolCallStatus, ToolKind, ToolRequestContent, ToolResponseContent, @@ -51,9 +50,6 @@ interface LivePerf { } const livePerf = new Map(); -const toolCallStatusFromUpdate = (status: string): ToolCallStatus => - status === "failed" ? "error" : "completed"; - function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } @@ -90,7 +86,7 @@ function locationsFromUpdate( function toolCallUpdatePatch( update: SessionUpdate, -): Partial { +): Pick, "toolKind" | "locations"> { const toolKind = toolKindFromUpdate(update); const locations = locationsFromUpdate(update); @@ -226,7 +222,7 @@ function handleReplay(sessionId: string, update: SessionUpdate): void { name: update.title, ...identity, arguments: rawInputToArguments(update.rawInput), - status: "executing", + status: "in_progress", ...toolCallUpdatePatch(update), startedAt: created ?? Date.now(), ...(chainSummary ? { chainSummary } : {}), @@ -276,7 +272,6 @@ function handleReplay(sessionId: string, update: SessionUpdate): void { } } if (update.status === "completed" || update.status === "failed") { - const toolCallStatus = toolCallStatusFromUpdate(update.status); const tc = msg.content.find( (c) => c.type === "toolRequest" && c.id === update.toolCallId, ); @@ -287,7 +282,7 @@ function handleReplay(sessionId: string, update: SessionUpdate): void { ...tc, ...identity, ...toolCallUpdatePatch(update), - status: toolCallStatus, + status: update.status, } as ToolRequestContent; } } @@ -356,7 +351,7 @@ function handleLive(sessionId: string, update: SessionUpdate): void { name: update.title, ...identity, arguments: rawInputToArguments(update.rawInput), - status: "executing", + status: "in_progress", ...toolCallUpdatePatch(update), startedAt: Date.now(), ...(chainSummary ? { chainSummary } : {}), @@ -403,7 +398,7 @@ function handleLive(sessionId: string, update: SessionUpdate): void { } if (update.status === "completed" || update.status === "failed") { - const toolCallStatus = toolCallStatusFromUpdate(update.status); + const { status: resolvedStatus } = update; const ownerMessage = store.messagesBySession[sessionId]?.find( (m) => m.id === messageId, ); @@ -425,7 +420,7 @@ function handleLive(sessionId: string, update: SessionUpdate): void { ...block, ...identity, ...toolCallUpdatePatch(update), - status: toolCallStatus, + status: resolvedStatus, } : block, ), diff --git a/ui/goose2/src/shared/api/dictation.ts b/ui/goose2/src/shared/api/dictation.ts index 883fb4d6af..60ba7eb827 100644 --- a/ui/goose2/src/shared/api/dictation.ts +++ b/ui/goose2/src/shared/api/dictation.ts @@ -59,7 +59,7 @@ export async function listDictationLocalModels(): Promise< > { const client = await getClient(); const response = await client.goose.GooseDictationModelsList({}); - return response.models as unknown as WhisperModelStatus[]; + return response.models; } export async function downloadDictationLocalModel( @@ -76,7 +76,7 @@ export async function getDictationLocalModelDownloadProgress( const response = await client.goose.GooseDictationModelsDownloadProgress({ modelId, }); - return (response.progress ?? null) as DictationDownloadProgress | null; + return response.progress ?? null; } export async function cancelDictationLocalModelDownload( diff --git a/ui/goose2/src/shared/types/__tests__/messages.test.ts b/ui/goose2/src/shared/types/__tests__/messages.test.ts index 7af17b86fc..64b3255276 100644 --- a/ui/goose2/src/shared/types/__tests__/messages.test.ts +++ b/ui/goose2/src/shared/types/__tests__/messages.test.ts @@ -26,7 +26,9 @@ import type { const textBlock: TextContent = { type: "text", text: "hello" }; const imageBlock: ImageContent = { type: "image", - source: { type: "url", url: "https://img.png" }, + data: "", + mimeType: "image/png", + uri: "https://img.png", }; const toolRequestBlock: ToolRequestContent = { type: "toolRequest", diff --git a/ui/goose2/src/shared/types/agents.ts b/ui/goose2/src/shared/types/agents.ts index df4380085b..bbcdba5058 100644 --- a/ui/goose2/src/shared/types/agents.ts +++ b/ui/goose2/src/shared/types/agents.ts @@ -3,24 +3,6 @@ // a narrow union. export type ProviderType = string; -export interface ProviderConfig { - type: ProviderType; - name: string; - description?: string; - models: ModelInfo[]; - requiresApiKey: boolean; - apiKeyEnvVar?: string; -} - -export interface ModelInfo { - id: string; - name: string; - contextWindow: number; - supportsTools: boolean; - supportsVision: boolean; - supportsThinking: boolean; -} - // Avatar type — either a remote URL or a local file in ~/.goose/avatars/ export type Avatar = | { type: "url"; value: string } @@ -86,4 +68,4 @@ export interface CreateAgentRequest { acpEndpoint?: string; } -// Session, TokenState, ChatState, and MessageEventType are defined in ./chat.ts +// Session, TokenState, and ChatState are defined in ./chat.ts diff --git a/ui/goose2/src/shared/types/chat.ts b/ui/goose2/src/shared/types/chat.ts index 76326a912b..6205977d29 100644 --- a/ui/goose2/src/shared/types/chat.ts +++ b/ui/goose2/src/shared/types/chat.ts @@ -1,6 +1,3 @@ -import type { Message } from "./messages"; -import type { Agent } from "./agents"; - // Chat state machine export type ChatState = | "idle" @@ -67,61 +64,3 @@ export interface Session { messageCount: number; userSetName?: boolean; } - -// SSE event types (from goosed server) -export type MessageEventType = - | "message" - | "error" - | "finish" - | "modelChange" - | "notification" - | "updateConversation" - | "ping"; - -export interface MessageEvent { - type: "message"; - message: Message; - tokenState: TokenState; -} - -export interface ErrorEvent { - type: "error"; - error: string; -} - -export interface FinishEvent { - type: "finish"; - reason: string; - tokenState: TokenState; -} - -export interface ModelChangeEvent { - type: "modelChange"; - model: string; - mode: string; -} - -export type StreamEvent = - | MessageEvent - | ErrorEvent - | FinishEvent - | ModelChangeEvent; - -// Chat request -export interface ChatRequest { - userMessage: Message; - sessionId: string; - recipeName?: string; - overrideConversation?: Message[]; -} - -// Active chat context -export interface ChatContext { - sessionId: string; - agent: Agent; - messages: Message[]; - chatState: SessionChatRuntime["chatState"]; - tokenState: SessionChatRuntime["tokenState"]; - streamingMessageId: SessionChatRuntime["streamingMessageId"]; - error: SessionChatRuntime["error"]; -} diff --git a/ui/goose2/src/shared/types/dictation.ts b/ui/goose2/src/shared/types/dictation.ts index f275935067..e2878b1248 100644 --- a/ui/goose2/src/shared/types/dictation.ts +++ b/ui/goose2/src/shared/types/dictation.ts @@ -1,47 +1,16 @@ +export type { + DictationModelOption, + DictationProviderStatusEntry as DictationProviderStatus, + DictationTranscribeResponse, + DictationLocalModelStatus as WhisperModelStatus, + DictationDownloadProgress, +} from "@aaif/goose-sdk"; + export type DictationProvider = "openai" | "groq" | "elevenlabs" | "local"; -export interface DictationModelOption { - id: string; - label: string; - description: string; -} - -export interface DictationProviderStatus { - configured: boolean; - host?: string | null; - description: string; - usesProviderConfig: boolean; - settingsPath?: string | null; - configKey?: string | null; - modelConfigKey?: string | null; - defaultModel?: string | null; - selectedModel?: string | null; - availableModels: DictationModelOption[]; -} - -export interface DictationTranscribeResponse { - text: string; -} - export type MicrophonePermissionStatus = | "not_determined" | "authorized" | "denied" | "restricted" | "unsupported"; - -export interface WhisperModelStatus { - id: string; - sizeMb: number; - description: string; - downloaded: boolean; - downloadInProgress: boolean; -} - -export interface DictationDownloadProgress { - bytesDownloaded: number; - totalBytes: number; - progressPercent: number; - status: string; - error?: string | null; -} diff --git a/ui/goose2/src/shared/types/messages.ts b/ui/goose2/src/shared/types/messages.ts index 973aaefa03..c792038d88 100644 --- a/ui/goose2/src/shared/types/messages.ts +++ b/ui/goose2/src/shared/types/messages.ts @@ -2,6 +2,48 @@ import type { GooseReadResourceResult, GooseToolMetadata, } from "@aaif/goose-sdk"; +import type { + Annotations, + ImageContent as AcpImageContent, + Role, + TextContent as AcpTextContent, + ToolCallLocation as AcpToolCallLocation, + ToolCallStatus as AcpToolCallStatus, + ToolKind, +} from "@agentclientprotocol/sdk"; + +// ── Wire types (re-exported from ACP SDK) ───────────────────────────── +// +// These are the exact types that come off the ACP WebSocket. We re-export +// them so feature code imports everything from this module. Aliases exist +// only for readability — no reshaping, no field-dropping. + +export type { Annotations, Role, ToolKind }; +export type ToolCallLocation = AcpToolCallLocation; + +/** ACP TextContent with discriminator. */ +export type TextContent = AcpTextContent & { type: "text" }; + +/** ACP ImageContent with discriminator. */ +export type ImageContent = AcpImageContent & { type: "image" }; + +/** + * Tool call execution status. + * + * The four ACP wire values plus `"stopped"`, a renderer-only extension + * for user-cancelled tool calls. + */ +export type ToolCallStatus = AcpToolCallStatus | "stopped"; + +// ── Message role ────────────────────────────────────────────────────── + +/** + * ACP defines `Role = "user" | "assistant"`. The renderer adds `"system"` + * for locally-synthesized notification messages. + */ +export type MessageRole = Role | "system"; + +// ── Composer attachment drafts ──────────────────────────────────────── export type ChatAttachmentKind = "image" | "file" | "directory"; @@ -35,55 +77,11 @@ export type ChatAttachmentDraft = | ChatFileAttachmentDraft | ChatDirectoryAttachmentDraft; -// Message roles -export type MessageRole = "user" | "assistant" | "system"; - -/** ACP audience restriction — which roles may see a content block. */ -export type Audience = ("user" | "assistant")[]; - -/** ACP content-block annotations (mirrors the SDK's Annotations shape). */ -export interface ContentAnnotations { - audience?: Audience; -} - -// Content block types -export interface TextContent { - type: "text"; - text: string; - annotations?: ContentAnnotations; -} - -export interface ImageContent { - type: "image"; - source: - | { type: "base64"; mediaType: string; data: string } - | { type: "url"; url: string }; - annotations?: ContentAnnotations; -} - -export type ToolCallStatus = - | "pending" - | "executing" - | "completed" - | "error" - | "stopped"; - -export type ToolKind = - | "read" - | "edit" - | "delete" - | "move" - | "search" - | "execute" - | "think" - | "fetch" - | "switch_mode" - | "other"; - -export interface ToolCallLocation { - path: string; - line?: number | null; -} +// ── Renderer-only content block types ───────────────────────────────── +// +// These types have no ACP equivalent. They are synthesized by the +// notification handler from _meta payloads, tool call reductions, or +// local UI events. export type MessageCompletionStatus = | "inProgress" @@ -92,9 +90,7 @@ export type MessageCompletionStatus = | "stopped"; export interface ToolChainSummary { - /** Lowercase phrase covering the chain's tool calls (e.g. "applied dark mode polish"). */ summary: string; - /** Number of tool calls the summary covers. */ count: number; } @@ -107,15 +103,9 @@ export interface ToolRequestContent { arguments: Record; status: ToolCallStatus; toolKind?: ToolKind; - locations?: ToolCallLocation[]; - /** Epoch ms when the tool call started executing (set on event receipt). */ + locations?: AcpToolCallLocation[]; startedAt?: number; - annotations?: ContentAnnotations; - /** - * Server-generated summary of a multi-tool chain that starts at this tool - * call. Only set on the FIRST tool call of a chain (>= 2 tools); the rest of - * the chain has this field undefined. - */ + annotations?: Annotations; chainSummary?: ToolChainSummary; } @@ -126,7 +116,7 @@ export interface ToolResponseContent { result: string; structuredContent?: unknown; isError: boolean; - annotations?: ContentAnnotations; + annotations?: Annotations; } export interface McpAppPayload { @@ -155,18 +145,18 @@ export interface McpAppContent { export interface ThinkingContent { type: "thinking"; text: string; - annotations?: ContentAnnotations; + annotations?: Annotations; } export interface RedactedThinkingContent { type: "redactedThinking"; - annotations?: ContentAnnotations; + annotations?: Annotations; } export interface ReasoningContent { type: "reasoning"; text: string; - annotations?: ContentAnnotations; + annotations?: Annotations; } export interface ActionRequiredContent { @@ -177,16 +167,18 @@ export interface ActionRequiredContent { toolName?: string; arguments?: Record; schema?: Record; - annotations?: ContentAnnotations; + annotations?: Annotations; } export interface SystemNotificationContent { type: "systemNotification"; notificationType: "compaction" | "info" | "warning" | "error"; text: string; - annotations?: ContentAnnotations; + annotations?: Annotations; } +// ── Message ─────────────────────────────────────────────────────────── + export type MessageContent = | TextContent | ImageContent @@ -217,11 +209,9 @@ export interface MessageMetadata { agentVisible?: boolean; attachments?: MessageAttachment[]; chips?: MessageChip[]; - /** Persona that generated this assistant message (set on send). */ personaId?: string; personaName?: string; providerId?: string; - /** Which persona this user message is addressed to. */ targetPersonaId?: string; targetPersonaName?: string; completionStatus?: MessageCompletionStatus; @@ -235,7 +225,8 @@ export interface Message { metadata?: MessageMetadata; } -// Type guards for content blocks +// ── Type guards ─────────────────────────────────────────────────────── + export function isTextContent(c: MessageContent): c is TextContent { return c.type === "text"; } @@ -265,7 +256,8 @@ export function isSystemNotification( return c.type === "systemNotification"; } -// Helpers +// ── Helpers ─────────────────────────────────────────────────────────── + export function getTextContent(message: Message): string { return message.content .filter(isTextContent) diff --git a/ui/goose2/src/shared/types/providers.ts b/ui/goose2/src/shared/types/providers.ts index 8330cd1e24..3fdd56f2e5 100644 --- a/ui/goose2/src/shared/types/providers.ts +++ b/ui/goose2/src/shared/types/providers.ts @@ -11,13 +11,7 @@ export type ProviderSetupMethod = ProviderSetupMethodDto; export type ProviderGroup = ProviderSetupGroupDto; export type ProviderField = ProviderSetupFieldDto; -export interface ProviderFieldValue { - key: string; - value: string | null; - isSet: boolean; - isSecret: boolean; - required: boolean; -} +export type { ProviderConfigFieldValueDto as ProviderFieldValue } from "@aaif/goose-sdk"; export type ProviderCatalogEntry = Omit< ProviderSetupCatalogEntryDto,