| author | |
| committer | |
| log | daa1d0ed947c276cb74b08025b5903e2ffe31278 |
| tree | 1009f4db3e413f9dfce82b90ae85d1c09fa6824a |
| parent | a92c43b80ba307f112e0ae03bf64d841475cf326 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>6 files changed, 34 insertions(+), 3 deletions(-)
apps/mobile/src/features/threads/SubagentRow.tsx+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | import { scopeProjectRef, scopeThreadRef } from "@t3tools/client-runtime/environment"; |
| 2 | import { resolveProviderInstanceDisplayName } from "@t3tools/client-runtime/state/provider-instance-display"; | |
| 2 | 3 | import { resolveSubagentMetadata } from "@t3tools/client-runtime/state/subagent-display"; |
| 3 | 4 | import type { EnvironmentId, OrchestrationV2Subagent } from "@t3tools/contracts"; |
| 4 | 5 | import type { ReactNode } from "react"; |
| ... | ... | @@ -125,7 +126,7 @@ function SubagentMetadata(props: { |
| 125 | 126 | size={12} |
| 126 | 127 | /> |
| 127 | 128 | <Text className="min-w-0 shrink text-xs text-foreground-muted" numberOfLines={1}> |
| 128 | {provider?.displayName ? `${provider.displayName} · ` : ""} | |
| 129 | {provider ? `${resolveProviderInstanceDisplayName(provider)} · ` : ""} | |
| 129 | 130 | {modelLabel} |
| 130 | 131 | </Text> |
| 131 | 132 | {workspace.map(({ label, value }) => ( |
apps/web/src/components/ChatView.tsx+8| ... | ... | @@ -315,6 +315,7 @@ import { |
| 315 | 315 | applyProviderInstanceSettings, |
| 316 | 316 | deriveProviderInstanceEntries, |
| 317 | 317 | NO_PROVIDER_MODEL_SELECTION, |
| 318 | shouldShowInstanceBadge, | |
| 318 | 319 | sortProviderInstanceEntries, |
| 319 | 320 | } from "../providerInstances"; |
| 320 | 321 | import { |
| ... | ... | @@ -11111,6 +11112,13 @@ export default function ChatView(props: ChatViewProps) { |
| 11111 | 11112 | {showProviderSubagentBar ? ( |
| 11112 | 11113 | <ProviderSubagentBar |
| 11113 | 11114 | provider={selectedProviderEntry ?? null} |
| 11115 | showInstanceBadge={ | |
| 11116 | selectedProviderEntry !== undefined && | |
| 11117 | shouldShowInstanceBadge( | |
| 11118 | selectedProviderEntry, | |
| 11119 | providerInstanceEntries, | |
| 11120 | ) | |
| 11121 | } | |
| 11114 | 11122 | modelLabel={providerSubagentModelLabel} |
| 11115 | 11123 | effortLabel={providerSubagentEffortLabel} |
| 11116 | 11124 | status={providerSubagentStatus} |
apps/web/src/components/chat/ProviderSubagentBar.tsx+4| ... | ... | @@ -18,6 +18,8 @@ import { ProviderInstanceIcon } from "./ProviderInstanceIcon"; |
| 18 | 18 | export function ProviderSubagentBar(props: { |
| 19 | 19 | /** The provider running the subagent; no icon while its catalog loads. */ |
| 20 | 20 | readonly provider: ProviderInstanceEntry | null; |
| 21 | /** Several accounts on this provider: badge the glyph, as the composer does. */ | |
| 22 | readonly showInstanceBadge: boolean; | |
| 21 | 23 | readonly modelLabel: string; |
| 22 | 24 | /** Reasoning effort as the composer names it, when the subagent has one. */ |
| 23 | 25 | readonly effortLabel: string | null; |
| ... | ... | @@ -60,8 +62,10 @@ export function ProviderSubagentBar(props: { |
| 60 | 62 | accentColor={props.provider.accentColor} |
| 61 | 63 | acpRegistryAgentId={props.provider.acpRegistryAgentId} |
| 62 | 64 | acpRegistryIconUrl={props.provider.acpRegistryIconUrl} |
| 65 | showBadge={props.showInstanceBadge} | |
| 63 | 66 | className="size-4 shrink-0" |
| 64 | 67 | iconClassName="size-4" |
| 68 | badgeClassName="right-[-0.125rem] bottom-[-0.125rem] h-3 min-w-3 px-0.5 text-5xs" | |
| 65 | 69 | /> |
| 66 | 70 | ) : null} |
| 67 | 71 | <span className="min-w-0 truncate font-medium text-foreground">{props.modelLabel}</span> |
apps/web/src/components/chat/SubagentTooltipContent.tsx+15-2| ... | ... | @@ -23,12 +23,15 @@ import { ThreadHoverCard } from "../ThreadHoverCard"; |
| 23 | 23 | import { MiddleTruncate } from "../ui/middle-truncate"; |
| 24 | 24 | import { ProviderInstanceIcon } from "./ProviderInstanceIcon"; |
| 25 | 25 | import { cn } from "~/lib/utils"; |
| 26 | import { deriveProviderInstanceEntries, shouldShowInstanceBadge } from "../../providerInstances"; | |
| 26 | 27 | |
| 27 | 28 | /** Geometry and preview limits stay identical in lineage and timeline tooltips. */ |
| 28 | 29 | export function SubagentTooltipContent(props: { |
| 29 | 30 | title: string; |
| 30 | 31 | model: string | null; |
| 31 | 32 | provider?: ServerProvider | undefined; |
| 33 | /** The environment's instances; with several accounts on one provider, the card names this one. */ | |
| 34 | providers?: ReadonlyArray<ServerProvider> | undefined; | |
| 32 | 35 | driver?: ProviderDriverKind | undefined; |
| 33 | 36 | elapsed?: ReactNode; |
| 34 | 37 | parentThread?: Pick<OrchestrationV2ThreadShell, "projectId" | "worktreePath"> | undefined; |
| ... | ... | @@ -42,6 +45,9 @@ export function SubagentTooltipContent(props: { |
| 42 | 45 | const { modelLabel, workspace: metadata } = resolveSubagentMetadata(props); |
| 43 | 46 | const preview = subagentDetailPreview(props); |
| 44 | 47 | const driver = props.provider?.driver ?? props.driver; |
| 48 | const entries = deriveProviderInstanceEntries(props.providers ?? []); | |
| 49 | const entry = entries.find((candidate) => candidate.instanceId === props.provider?.instanceId); | |
| 50 | const showInstanceBadge = entry !== undefined && shouldShowInstanceBadge(entry, entries); | |
| 45 | 51 | const working = ["running", "in_progress", "pending", "waiting"].includes(props.status); |
| 46 | 52 | const failed = ["failed", "error"].includes(props.status); |
| 47 | 53 | const StatusIcon = working |
| ... | ... | @@ -57,14 +63,21 @@ export function SubagentTooltipContent(props: { |
| 57 | 63 | {driver ? ( |
| 58 | 64 | <ProviderInstanceIcon |
| 59 | 65 | driverKind={driver} |
| 60 | displayName={props.provider?.displayName ?? driver} | |
| 66 | displayName={entry?.displayName ?? props.provider?.displayName ?? driver} | |
| 67 | accentColor={entry?.accentColor} | |
| 61 | 68 | acpRegistryIconUrl={props.provider?.iconUrl} |
| 69 | // Same treatment as the sidebar card: accent dot, account in the label. | |
| 70 | showBadge={showInstanceBadge && entry?.accentColor !== undefined} | |
| 71 | badgeContent="none" | |
| 72 | badgeClassName="h-2 min-w-2 px-0" | |
| 62 | 73 | iconClassName="size-3 shrink-0 grayscale opacity-60" |
| 63 | 74 | /> |
| 64 | 75 | ) : ( |
| 65 | 76 | <BotIcon className="size-3 shrink-0" /> |
| 66 | 77 | )} |
| 67 | <span className="min-w-0 truncate text-foreground/75">{modelLabel}</span> | |
| 78 | <span className="min-w-0 truncate text-foreground/75"> | |
| 79 | {showInstanceBadge ? `${modelLabel} · ${entry.displayName}` : modelLabel} | |
| 80 | </span> | |
| 68 | 81 | </div> |
| 69 | 82 | <div className="flex min-w-0 items-center justify-between gap-4"> |
| 70 | 83 | <span |
apps/web/src/components/chat/ThreadRelationshipsControl.tsx+1| ... | ... | @@ -384,6 +384,7 @@ export function ThreadRelationshipsPanel(props: { |
| 384 | 384 | title={threadTitle} |
| 385 | 385 | model={agent.model} |
| 386 | 386 | provider={provider} |
| 387 | providers={providers} | |
| 387 | 388 | driver={providerDriver} |
| 388 | 389 | elapsed={<AgentElapsed agent={agent} />} |
| 389 | 390 | status={agent.status} |
apps/web/src/components/chat/V2LifecycleRow.tsx+4| ... | ... | @@ -217,6 +217,7 @@ export function V2LifecycleRow(props: { |
| 217 | 217 | provider={props.providerStatuses.find( |
| 218 | 218 | (provider) => provider.instanceId === item.providerInstanceId, |
| 219 | 219 | )} |
| 220 | providers={props.providerStatuses} | |
| 220 | 221 | title={formatSubagentDisplayTitle(item.title ?? "Subagent")} |
| 221 | 222 | result={item.result} |
| 222 | 223 | progress={item.progress} |
| ... | ... | @@ -374,6 +375,7 @@ export function SubagentNotificationLink(props: { |
| 374 | 375 | provider={props.providerStatuses.find( |
| 375 | 376 | (provider) => provider.instanceId === agent.providerInstanceId, |
| 376 | 377 | )} |
| 378 | providers={props.providerStatuses} | |
| 377 | 379 | title={formatSubagentDisplayTitle(agent.title ?? "Subagent")} |
| 378 | 380 | result={agent.result} |
| 379 | 381 | progress={agent.progress} |
| ... | ... | @@ -395,6 +397,7 @@ function SubagentTimelineLink(props: { |
| 395 | 397 | readonly subagentId: NodeId; |
| 396 | 398 | readonly driver: ProviderDriverKind; |
| 397 | 399 | readonly provider: ServerProvider | undefined; |
| 400 | readonly providers: ReadonlyArray<ServerProvider>; | |
| 398 | 401 | readonly title: string; |
| 399 | 402 | readonly result: string | null; |
| 400 | 403 | readonly progress: string | undefined; |
| ... | ... | @@ -538,6 +541,7 @@ function SubagentTimelineTooltip( |
| 538 | 541 | title={formatSubagentDisplayTitle(child?.title ?? props.title)} |
| 539 | 542 | model={props.model} |
| 540 | 543 | provider={props.provider} |
| 544 | providers={props.providers} | |
| 541 | 545 | driver={props.driver} |
| 542 | 546 | elapsed={props.elapsed} |
| 543 | 547 | status={props.status} |