Files
tutti/packages/agent/gui/workbench/AgentGuiWorkbenchReactiveHeader.tsx
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

86 lines
2.4 KiB
TypeScript

import { useMemo, type ReactNode } from "react";
import type { AgentSessionEngine } from "@tutti-os/agent-activity-core";
import type {
AgentGUIAgentDirectoryPort,
AgentGUIAgentDirectorySnapshot
} from "../types.ts";
import { useEngineSelector } from "../shared/engine/useEngineSelector.ts";
import {
agentGuiWorkbenchConversationIdentitiesEqual,
resolveAgentGuiWorkbenchConversationIdentity
} from "./conversationIdentity.ts";
import {
AgentGuiWorkbenchHeader,
type AgentGuiWorkbenchHeaderProps
} from "./header.ts";
import type {
AgentGuiWorkbenchProvider,
AgentGuiWorkbenchState
} from "./types.ts";
interface AgentGuiWorkbenchReactiveHeaderProps extends Omit<
AgentGuiWorkbenchHeaderProps,
| "agentTitle"
| "conversationIconUrl"
| "conversationTitle"
| "conversationTitleDisplayPrompt"
| "hasConversation"
> {
agentDirectory: AgentGUIAgentDirectoryPort;
dockIconUrls?: Partial<Record<AgentGuiWorkbenchProvider, string>>;
sessionEngine: AgentSessionEngine;
workbenchState: AgentGuiWorkbenchState | null;
}
export function AgentGuiWorkbenchReactiveHeader({
agentDirectory,
dockIconUrls,
sessionEngine,
workbenchState,
...headerProps
}: AgentGuiWorkbenchReactiveHeaderProps): ReactNode {
const directoryStore = useMemo(
() => ({
getSnapshot: () => agentDirectory.getSnapshot(),
subscribe: (
listener: (snapshot: AgentGUIAgentDirectorySnapshot) => void
) =>
agentDirectory.subscribe(() => {
listener(agentDirectory.getSnapshot());
})
}),
[agentDirectory]
);
const agents = useEngineSelector(
directoryStore,
(snapshot) => snapshot.agents,
Object.is
);
const conversationIdentity = useEngineSelector(
sessionEngine,
(engineState) =>
resolveAgentGuiWorkbenchConversationIdentity({
agents,
dockIconUrls,
engineState,
workbenchState
}),
agentGuiWorkbenchConversationIdentitiesEqual
);
return (
<AgentGuiWorkbenchHeader
{...headerProps}
agentTitle={conversationIdentity?.agentTitle}
conversationIconUrl={
conversationIdentity?.iconUrl ?? headerProps.conversationIconFallbackUrl
}
conversationTitle={conversationIdentity?.title}
conversationTitleDisplayPrompt={conversationIdentity?.titleDisplayPrompt}
hasConversation={Boolean(
workbenchState?.lastActiveAgentSessionId?.trim()
)}
/>
);
}