import { scopeProjectRef, scopeThreadRef } from "@t3tools/client-runtime/environment"; import { normalizeProviderAccentColor, resolveProviderInstanceDisplayName, shouldShowInstanceBadge, } from "@t3tools/client-runtime/state/provider-instance-display"; import { resolveSubagentMetadata } from "@t3tools/client-runtime/state/subagent-display"; import { formatSubagentEffort } from "@t3tools/client-runtime/state/thread-execution"; import type { EnvironmentId, OrchestrationV2Subagent } from "@t3tools/contracts"; import type { ReactNode } from "react"; import { View } from "react-native"; import { AppText as Text } from "../../components/ui/AppText"; import { SymbolView } from "../../components/ui/AppSymbol"; import { ProviderIcon, ProviderInstanceIcon } from "../../components/ProviderIcon"; import { cn } from "../../lib/cn"; import { useEnvironmentServerConfig, useProject, useThreadShell } from "../../state/entities"; import { subagentCardDetail } from "./subagent-card-presentation"; import { SUBAGENT_TONE_TEXT_CLASS, SubagentStatusDot } from "./SubagentStatusDot"; import { resolveSubagentRowPresentation } from "./threadAgentsPresentation"; type SubagentRowSubagent = Pick< OrchestrationV2Subagent, | "threadId" | "childThreadId" | "model" | "modelSelection" | "driver" | "providerInstanceId" | "title" | "prompt" | "status" | "progress" | "result" | "remoteChild" >; export function SubagentRow(props: { readonly environmentId: EnvironmentId; readonly subagent: SubagentRowSubagent; readonly elapsed: ReactNode; /** The task runs in a linked environment this app is connected to. */ readonly canOpenRemote?: boolean; }) { const presentation = resolveSubagentRowPresentation(props.subagent, props.canOpenRemote); const detail = subagentCardDetail(presentation.detail); return ( {presentation.title} · {presentation.statusLabel} {presentation.runsOn !== null ? ( on {presentation.runsOn} ) : null} {props.elapsed} {presentation.canOpenThread ? ( ) : null} {detail ? ( {detail} ) : null} ); } function SubagentMetadata(props: { readonly environmentId: EnvironmentId; readonly subagent: SubagentRowSubagent; }) { const { environmentId, subagent } = props; // A task in a linked environment runs a provider instance of that environment. const config = useEnvironmentServerConfig(subagent.remoteChild?.environmentId ?? environmentId); const providers = (config?.providers ?? []).map((candidate) => { const rawConfig = config?.settings.providerInstances[candidate.instanceId]?.config; const instanceConfig = rawConfig !== null && typeof rawConfig === "object" ? (rawConfig as Readonly>) : null; const agentId = instanceConfig?.source === "local" ? undefined : instanceConfig?.agentId; return { ...candidate, driverKind: candidate.driver, accentColor: normalizeProviderAccentColor(candidate.accentColor), acpRegistryAgentId: typeof agentId === "string" ? agentId.trim() || undefined : undefined, }; }); const provider = providers.find( (candidate) => candidate.instanceId === subagent.providerInstanceId, ); const showBadge = provider !== undefined && shouldShowInstanceBadge(provider, providers); const parent = useThreadShell(scopeThreadRef(environmentId, subagent.threadId))?.source; const child = useThreadShell( subagent.childThreadId === null ? null : scopeThreadRef(environmentId, subagent.childThreadId), )?.source; const parentProject = useProject( parent ? scopeProjectRef(environmentId, parent.projectId) : null, ); const childProject = useProject(child ? scopeProjectRef(environmentId, child.projectId) : null); const selection = subagent.modelSelection; const { modelLabel, modelSlug, workspace } = resolveSubagentMetadata({ model: subagent.model, modelSelection: selection, provider, parentThread: parent, childThread: child, parentProject, childProject, }); const effort = formatSubagentEffort({ modelSlug, modelSelection: selection, provider }); return ( {showBadge ? ( ) : ( )} {provider ? `${resolveProviderInstanceDisplayName(provider)} · ` : ""} {modelLabel} {effort ? ` · ${effort}` : ""} {workspace.map(({ label, value }) => ( // Preserve the label against flattening without making it a separate accessibility stop. · {value} ))} ); }