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}
))}
);
}