feat(agent): docked assistant sheet runs general.help on the single-call console (#1769)

RIP-4 stage 1. The app-wide docked "Fråga min assistent" sheet rendered
general.help through the streaming AgentChat runtime, so on a local/OpenAI-
compatible model it 503'd. It now renders AskConsole for general.help (both a
fresh ask and a resumed thread), the same single-call, provider-agnostic path
/chat already uses, with the read-only ledger tools + snapshot. Every other
intent (the write/staging flows, onboarding, etc.) still renders AgentChat
unchanged, so run-turn.ts stays until those migrate in later stages.

Resumed free-form threads convert their stored messages to text-only (the
console has no tool/staged rows). Fresh asks report the created conversation id
back to the sheet via onConversationCreated, same as onConversationIdChange did.

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-08-21 13:13:54 +02:00
committed by GitHub
co-authored by Jakob Wennberg Claude Opus 4.8
parent 05c3c6ebd9
commit 148ec0ce85
+31 -8
View File
@@ -18,6 +18,8 @@ import AgentChat, {
normalizeStoredMessages,
type ChatMessage,
} from './AgentChat'
import AskConsole, { type AskConsoleMessage } from './AskConsole'
import { CHAT_INTENT_ID } from '@/lib/agent/ask/persist'
import type { AgentPanelFloatRect, StoredStagedOperation } from '@/types'
import {
DOCK_GUTTER,
@@ -756,14 +758,35 @@ export default function AgentSheet({
</button>
</div>
) : loaded ? (
<AgentChat
key={loaded.id}
intentId={loaded.intentId}
contextRef={loaded.contextRef ?? undefined}
initialConversationId={loaded.id}
initialMessages={loaded.messages}
onConversationIdChange={(id) => setConversationId(id)}
onStatus={onStatus}
loaded.intentId === CHAT_INTENT_ID ? (
// Resumed free-form thread: the single-call console (runs on a local
// model). Its turns are text-only, so drop any empty/tool rows.
<AskConsole
key={loaded.id}
initialConversationId={loaded.id}
initialMessages={loaded.messages
.filter((m) => m.text.trim().length > 0)
.map((m): AskConsoleMessage => ({ role: m.role, text: m.text }))}
contextRef={loaded.contextRef}
/>
) : (
<AgentChat
key={loaded.id}
intentId={loaded.intentId}
contextRef={loaded.contextRef ?? undefined}
initialConversationId={loaded.id}
initialMessages={loaded.messages}
onConversationIdChange={(id) => setConversationId(id)}
onStatus={onStatus}
/>
)
) : intentId === CHAT_INTENT_ID ? (
// Fresh free-form ask (the FAB's "Fråga min assistent" catch-all).
<AskConsole
seedUserMessage={seedUserMessage}
initialConversationId={null}
contextRef={contextRef ?? null}
onConversationCreated={(id) => setConversationId(id)}
/>
) : (
<AgentChat