diff --git a/src/gateway/server-methods/system-agent-reset-boundary.test.ts b/src/gateway/server-methods/system-agent-reset-boundary.test.ts index 715fca2a84fe..0e3267064fa3 100644 --- a/src/gateway/server-methods/system-agent-reset-boundary.test.ts +++ b/src/gateway/server-methods/system-agent-reset-boundary.test.ts @@ -270,11 +270,11 @@ describe("openclaw.chat reset boundary", () => { historyResponses.push({ ok, payload, error }), } as never); - expect(historyResponses[0]).toMatchObject({ ok: true, error: undefined }); - expect(historyResponses[0]).not.toHaveProperty("payload.activeWizard"); - const restoredTurns = ( - historyResponses[0]?.payload as { turns: SystemAgentChatHistoryTurn[] } - ).turns; + const historyResponse = expectDefined(historyResponses[0], "recovery history response"); + expect(historyResponse).toMatchObject({ ok: true, error: undefined }); + expect(historyResponse).not.toHaveProperty("payload.activeWizard"); + const restoredTurns = (historyResponse.payload as { turns: SystemAgentChatHistoryTurn[] }) + .turns; expect(restoredTurns.find((turn) => turn.text === "banana")).not.toHaveProperty( "wizardAction", ); diff --git a/ui/src/pages/custodian/custodian-session-store.ts b/ui/src/pages/custodian/custodian-session-store.ts index 5b8c2cdeeaf7..65b6e1ff0844 100644 --- a/ui/src/pages/custodian/custodian-session-store.ts +++ b/ui/src/pages/custodian/custodian-session-store.ts @@ -3,7 +3,6 @@ import { readSystemAgentInferenceUnavailableErrorDetails, type SystemAgentChatParams, type SystemAgentChatResult, - type SystemAgentWizardActionReceipt, } from "@openclaw/gateway-protocol"; import type { GatewayBrowserClient } from "../../api/gateway.ts"; import { selectApplicationSession } from "../../app/agent-selection.ts"; @@ -17,7 +16,12 @@ import { import { buildAgentMainSessionKey, normalizeAgentId } from "../../lib/sessions/session-key.ts"; import { pathForCustodianAgentHandoff } from "./custodian-navigation.ts"; import { readCustodianRecoveryForClient } from "./custodian-recovery.ts"; -import { createCustodianStructuredInteraction } from "./custodian-structured-interaction.ts"; +import { + createCustodianStructuredInteraction, + hasCustodianUserInput, + hasCustodianWizardAction, + type CustodianSendResult, +} from "./custodian-structured-interaction.ts"; import { CustodianTranscriptState, type CustodianTranscriptHistoryOutcome, @@ -41,25 +45,8 @@ import { const SYSTEM_AGENT_CHAT_TIMEOUT_MS = 190_000; const SILENT_REPLY_PATTERN = /^\s*NO_REPLY\s*$/; -function hasCustodianUserInput(params: SystemAgentChatParams): boolean { - return ( - params.message !== undefined || - params.wizardAnswer !== undefined || - params.wizardCancel !== undefined - ); -} - -function hasCustodianWizardAction(params: SystemAgentChatParams): boolean { - return params.wizardAnswer !== undefined || params.wizardCancel !== undefined; -} - -type StoreListener = () => void; type ConfiguredInferenceState = "unresolved" | "required" | "ready"; type CustodianSetupIssue = "missing" | "unavailable"; -type CustodianSendResult = { - outcome: eventNudgeState.CustodianSendOutcome; - wizardAction?: SystemAgentWizardActionReceipt; -}; /** One process-local conversation owner shared by the full page and dock surface. */ export class CustodianSessionStore extends CustodianTranscriptState { @@ -88,7 +75,7 @@ export class CustodianSessionStore extends CustodianTranscriptState { private gatewayCleanup: (() => void) | null = null; private agentCleanup: (() => void) | null = null; private eventCleanup: (() => void) | null = null; - private readonly listeners = new Set(); + private readonly listeners = new Set<() => void>(); private readonly structuredInteraction = createCustodianStructuredInteraction({ state: () => ({ activeClient: this.activeClient, @@ -107,7 +94,7 @@ export class CustodianSessionStore extends CustodianTranscriptState { this.sendUserTurn(client, params, display, true, appendUserMessage), }); - subscribe(listener: StoreListener): () => void { + subscribe(listener: () => void): () => void { this.listeners.add(listener); return () => this.listeners.delete(listener); } diff --git a/ui/src/pages/custodian/custodian-structured-interaction.ts b/ui/src/pages/custodian/custodian-structured-interaction.ts index 306bfdd6d943..b263bc845ec5 100644 --- a/ui/src/pages/custodian/custodian-structured-interaction.ts +++ b/ui/src/pages/custodian/custodian-structured-interaction.ts @@ -8,6 +8,23 @@ import { custodianWizardSubmission } from "./custodian-wizard-step.ts"; import type * as eventNudgeState from "./event-nudge.ts"; import type { CustodianMessage, CustodianStructuredResponse } from "./transcript.ts"; +export type CustodianSendResult = { + outcome: eventNudgeState.CustodianSendOutcome; + wizardAction?: SystemAgentWizardActionReceipt; +}; + +export function hasCustodianUserInput(params: SystemAgentChatParams): boolean { + return ( + params.message !== undefined || + params.wizardAnswer !== undefined || + params.wizardCancel !== undefined + ); +} + +export function hasCustodianWizardAction(params: SystemAgentChatParams): boolean { + return params.wizardAnswer !== undefined || params.wizardCancel !== undefined; +} + type StructuredInteractionState = { activeClient: GatewayBrowserClient | null; chatAvailable: boolean; @@ -29,10 +46,7 @@ type StructuredInteractionHost = { params: SystemAgentChatParams, display: string, userTurnProjection: "always" | "unless-accepted", - ) => Promise<{ - outcome: eventNudgeState.CustodianSendOutcome; - wizardAction?: SystemAgentWizardActionReceipt; - }>; + ) => Promise; }; function withResponse( diff --git a/ui/src/styles/custodian.css b/ui/src/styles/custodian.css index 82818442d171..68f9c9060986 100644 --- a/ui/src/styles/custodian.css +++ b/ui/src/styles/custodian.css @@ -303,8 +303,8 @@ openclaw-custodian-page { } .custodian__structured-response-icon--cancelled { - background: color-mix(in srgb, var(--text-muted) 18%, transparent); - color: var(--text-muted); + background: color-mix(in srgb, var(--muted) 18%, transparent); + color: var(--muted); } .custodian__structured-response-copy { @@ -328,7 +328,7 @@ openclaw-custodian-page { } .custodian__structured-response-status { - color: var(--text-muted); + color: var(--muted); font-size: 12px; }