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
130 lines
4.2 KiB
TypeScript
130 lines
4.2 KiB
TypeScript
import { useMemo } from "react";
|
|
import { cn } from "../../../app/renderer/lib/utils";
|
|
import styles from "../AgentGUINode.styles";
|
|
import type { AgentGUIAgentTarget } from "../../../types";
|
|
|
|
interface Input {
|
|
layoutMode: "dock" | "embedded" | "hero";
|
|
provider: string;
|
|
agentTargets: readonly AgentGUIAgentTarget[];
|
|
handoffAgentTargets?: readonly AgentGUIAgentTarget[];
|
|
selectedAgentTarget: AgentGUIAgentTarget | null;
|
|
providerSelectReadonly: boolean;
|
|
composerControlsHardDisabled: boolean;
|
|
isSelectedProjectMissing: boolean;
|
|
disabled: boolean;
|
|
onHandoffConversation?: (target: AgentGUIAgentTarget) => void;
|
|
handoffLabel?: string;
|
|
handoffMenuLabel?: string;
|
|
defaultHandoffLabel: string;
|
|
defaultHandoffMenuLabel: string;
|
|
}
|
|
|
|
export function useComposerProviderTargets(input: Input) {
|
|
const {
|
|
layoutMode,
|
|
provider,
|
|
agentTargets,
|
|
handoffAgentTargets,
|
|
selectedAgentTarget,
|
|
providerSelectReadonly,
|
|
composerControlsHardDisabled,
|
|
isSelectedProjectMissing,
|
|
disabled,
|
|
onHandoffConversation,
|
|
handoffLabel,
|
|
handoffMenuLabel
|
|
} = input;
|
|
const labels = {
|
|
handoffConversation: input.defaultHandoffLabel,
|
|
handoffConversationMenu: input.defaultHandoffMenuLabel
|
|
};
|
|
const isHeroLayout = layoutMode === "hero";
|
|
const composerClassName = isHeroLayout
|
|
? styles.composerHero
|
|
: styles.composer;
|
|
const providerSwitchTargets = useMemo(
|
|
() => agentTargets.filter(Boolean),
|
|
[agentTargets]
|
|
);
|
|
const selectedAgentTargetId =
|
|
selectedAgentTarget?.targetId ?? `local:${provider}`;
|
|
const selectedProviderSwitchTarget =
|
|
providerSwitchTargets.find(
|
|
(target) => target.targetId === selectedAgentTargetId
|
|
) ??
|
|
providerSwitchTargets.find((target) => target.provider === provider) ??
|
|
selectedAgentTarget;
|
|
const providerMenuTargets =
|
|
selectedProviderSwitchTarget &&
|
|
!providerSwitchTargets.some(
|
|
(target) => target.targetId === selectedProviderSwitchTarget.targetId
|
|
)
|
|
? [selectedProviderSwitchTarget, ...providerSwitchTargets]
|
|
: providerSwitchTargets;
|
|
const enabledHandoffProviderTargets = useMemo(
|
|
() =>
|
|
(handoffAgentTargets ?? providerMenuTargets).filter(
|
|
(target) => target.disabled !== true
|
|
),
|
|
[handoffAgentTargets, providerMenuTargets]
|
|
);
|
|
const handoffMenuTargets = selectedProviderSwitchTarget
|
|
? enabledHandoffProviderTargets.filter((target) => {
|
|
if (target.targetId === selectedProviderSwitchTarget.targetId) {
|
|
return false;
|
|
}
|
|
const selectedAgentTargetId =
|
|
selectedProviderSwitchTarget.agentTargetId ??
|
|
selectedProviderSwitchTarget.targetId;
|
|
const targetAgentTargetId = target.agentTargetId ?? target.targetId;
|
|
return targetAgentTargetId !== selectedAgentTargetId;
|
|
})
|
|
: enabledHandoffProviderTargets;
|
|
const selectedProviderLabel =
|
|
selectedProviderSwitchTarget?.label ??
|
|
selectedAgentTarget?.label ??
|
|
provider;
|
|
const effectiveHandoffLabel = handoffLabel || labels.handoffConversation;
|
|
const effectiveHandoffMenuLabel =
|
|
handoffMenuLabel || labels.handoffConversationMenu;
|
|
const inputShellClassName = cn(
|
|
styles.composerInputShell,
|
|
isHeroLayout && styles.composerInputShellHero
|
|
);
|
|
const inputDisabled = isSelectedProjectMissing || disabled;
|
|
const providerSelectDisabled =
|
|
providerSelectReadonly || composerControlsHardDisabled || inputDisabled;
|
|
const handoffDisabled = resolveComposerHandoffDisabled({
|
|
hasHandoffConversation: onHandoffConversation !== undefined
|
|
});
|
|
const showProviderSelect =
|
|
!isHeroLayout &&
|
|
selectedProviderSwitchTarget !== null &&
|
|
providerMenuTargets.length > 0;
|
|
const showHandoffSelect = showProviderSelect && providerSelectReadonly;
|
|
|
|
return {
|
|
composerClassName,
|
|
effectiveHandoffLabel,
|
|
effectiveHandoffMenuLabel,
|
|
handoffDisabled,
|
|
handoffMenuTargets,
|
|
inputDisabled,
|
|
inputShellClassName,
|
|
isHeroLayout,
|
|
providerMenuTargets,
|
|
providerSelectDisabled,
|
|
selectedProviderLabel,
|
|
selectedProviderSwitchTarget,
|
|
showHandoffSelect,
|
|
showProviderSelect
|
|
};
|
|
}
|
|
|
|
export function resolveComposerHandoffDisabled(input: {
|
|
hasHandoffConversation: boolean;
|
|
}): boolean {
|
|
return !input.hasHandoffConversation;
|
|
}
|