+
{agent.name}
@@ -1411,18 +1363,15 @@ export function AgentDetail() {
/>
)}
- {!urlRunId && (
-
+ {!streamlinedUiEnabled && !urlRunId ? (
+
- )}
+ ) : null}
{actionError && {actionError}
}
{isPendingApproval && (
@@ -1490,13 +1439,15 @@ export function AgentDetail() {
)}
{/* View content */}
- {activeView === "dashboard" && (
+ {activeView === "overview" && (streamlinedUiEnabled || !legacyAuditSection) && (
)}
@@ -1512,18 +1463,22 @@ export function AgentDetail() {
/>
)}
- {activeView === "configuration" && (
-
+ {activeView === "runtime" && (
+
+
+
)}
{activeView === "secrets" && (
@@ -1552,7 +1507,32 @@ export function AgentDetail() {
)}
- {activeView === "runs" && (
+ {activeView === "permissions" && (
+
+
+
+ )}
+
+ {activeView === "api-keys" && (
+
+
+
+ )}
+
+ {activeView === "revisions" && (
+
+ )}
+
+ {activeView === "run-detail" && (
)}
- {activeView === "audit" && resolvedCompanyId ? (
-
+ {!streamlinedUiEnabled && legacyAuditSection === "runs" && (
+
+ )}
+
+ {!streamlinedUiEnabled && legacyAuditSection === "activity" && resolvedCompanyId ? (
+
) : null}
- {activeView === "budget" && resolvedCompanyId ? (
-
-
budgetMutation.mutate(amount)}
- variant="plain"
- />
+ {!streamlinedUiEnabled && (legacyAuditSection === "costs" || legacyAuditSection === "budgets") ? (
+
+
Agent budget
+
+ Review this agent's budget policy and spend in the organization costs view.
+
+
) : null}
@@ -1772,21 +1765,25 @@ function LatestRunCard({
);
}
-/* ---- Agent Overview (main single-page view) ---- */
+/* ---- Agent Overview ---- */
-function AgentOverview({
+export function AgentOverview({
agent,
runs,
assignedIssues,
runtimeState,
- agentId,
+ reportsToAgent,
+ directReportCount,
+ skillNames,
agentRouteId,
}: {
agent: AgentDetailRecord;
runs: HeartbeatRun[];
- assignedIssues: { id: string; title: string; status: string; priority: string; identifier?: string | null; createdAt: Date }[];
+ assignedIssues: Issue[];
runtimeState?: AgentRuntimeState;
- agentId: string;
+ reportsToAgent?: Agent;
+ directReportCount: number;
+ skillNames: string[];
agentRouteId: string;
}) {
const issuesById = useMemo(() => {
@@ -1794,37 +1791,81 @@ function AgentOverview({
for (const issue of assignedIssues) map.set(issue.id, issue);
return map;
}, [assignedIssues]);
+ const configuredModel = asNonEmptyString(agent.adapterConfig?.model)
+ ?? asNonEmptyString(agent.adapterConfig?.modelName)
+ ?? asNonEmptyString(agent.runtimeConfig?.model)
+ ?? "Adapter default";
+ const lastRun = runs[0] ?? null;
return (
-
- {/* Latest Run */}
+
- {/* Charts */}
-
-
-
-
- {/* PAP-411: "Tasks by Priority" chart hidden behind SHOW_TASK_PRIORITY_UI. */}
- {SHOW_TASK_PRIORITY_UI && (
-
-
-
- )}
-
-
-
-
-
-
+
+
+
+
Identity
+
+
+
+ {roleLabels[agent.role] ?? agent.role}
+ {agent.title ?? "Not set"}
+
+ {reportsToAgent ? (
+
+ {reportsToAgent.name}
+
+ ) : Board}
+
+ {directReportCount}
+
+
+
+
+
+
Harness / Runtime
+ Configure
+
+
+ {adapterLabels[agent.adapterType] ?? agent.adapterType}
+ {configuredModel}
+ {runtimeState?.sessionDisplayId ?? runtimeState?.sessionId ?? "No session"}
+
+ {lastRun ? `${lastRun.status} · ${relativeTime(lastRun.createdAt)}` : "No runs"}
+
+
+
+
+
+ Capabilities
+ {agent.capabilities?.trim() ? (
+ {agent.capabilities}
+ ) : (
+ No capability summary has been added.
+ )}
+
+
+
+
+
Skills
+ Manage
+
+ {skillNames.length > 0 ? (
+
+ {skillNames.slice(0, 8).map((skill) => {skill})}
+ {skillNames.length > 8 ? +{skillNames.length - 8} more : null}
+
+ ) : (
+ No skills enabled.
+ )}
+
- {/* Recent Issues */}
-
+
-
Recent Tasks
+
Recent Tasks
See All →
@@ -1833,108 +1874,39 @@ function AgentOverview({
{assignedIssues.length === 0 ? (
No recent tasks.
) : (
-
- {assignedIssues.slice(0, 10).map((issue) => (
-
+ {assignedIssues.slice(0, 6).map((issue) => (
+ }
+ issue={issue}
+ presentation="task"
+ metadata={{relativeTime(issue.updatedAt)}}
+ showDivider
/>
))}
- {assignedIssues.length > 10 && (
-
- +{assignedIssues.length - 10} more tasks
+ {assignedIssues.length > 6 && (
+
+ +{assignedIssues.length - 6} more tasks
)}
)}
-
+
- {/* Costs */}
-
-
Costs
-
-
-
- );
-}
-
-/* ---- Costs Section (inline) ---- */
-
-function CostsSection({
- runtimeState,
- runs,
-}: {
- runtimeState?: AgentRuntimeState;
- runs: HeartbeatRun[];
-}) {
- const runsWithCost = runs
- .filter((r) => {
- const metrics = runMetrics(r);
- return metrics.cost > 0 || metrics.input > 0 || metrics.output > 0 || metrics.cached > 0;
- })
- .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
-
- return (
-
- {runtimeState && (
-
-
-
- Input tokens
- {formatTokens(runtimeState.totalInputTokens)}
-
-
- Output tokens
- {formatTokens(runtimeState.totalOutputTokens)}
-
-
- Cached tokens
- {formatTokens(runtimeState.totalCachedInputTokens)}
-
-
- Total cost
- {formatCents(runtimeState.totalCostCents)}
-
-
+
+ Audit
+
+ {(["activity", "runs", "costs", "budgets"] as const).map((section) => (
+
+ {section}
+
+ ))}
- )}
- {runsWithCost.length > 0 && (
-
-
-
-
- | Date |
- Run |
- Input |
- Output |
- Cost |
-
-
-
- {runsWithCost.slice(0, 10).map((run) => {
- const metrics = runMetrics(run);
- return (
-
- | {formatDate(run.createdAt)} |
- {run.id.slice(0, 8)} |
- {formatTokens(metrics.input)} |
- {formatTokens(metrics.output)} |
-
- {metrics.cost > 0
- ? `$${metrics.cost.toFixed(4)}`
- : "-"
- }
- |
-
- );
- })}
-
-
-
- )}
+
);
}
@@ -1964,31 +1936,15 @@ export function syncAgentRouteAfterRename(
return true;
}
-function AgentConfigurePage({
+function AgentRevisionsTab({
agent,
- agentId,
companyId,
- onDirtyChange,
- onSaveActionChange,
- onCancelActionChange,
- onSavingChange,
- updatePermissions,
- canConfigureProviderTrace,
}: {
agent: AgentDetailRecord;
- agentId: string;
companyId?: string;
- onDirtyChange: (dirty: boolean) => void;
- onSaveActionChange: (save: (() => void) | null) => void;
- onCancelActionChange: (cancel: (() => void) | null) => void;
- onSavingChange: (saving: boolean) => void;
- updatePermissions: { mutate: (permissions: AgentPermissionUpdate) => void; isPending: boolean };
- canConfigureProviderTrace: boolean;
}) {
const queryClient = useQueryClient();
const navigate = useNavigate();
- const { tab: urlTab } = useParams<{ tab?: string }>();
- const [revisionsOpen, setRevisionsOpen] = useState(false);
const { data: configRevisions } = useQuery({
queryKey: queryKeys.agents.configRevisions(agent.id),
@@ -2000,81 +1956,48 @@ function AgentConfigurePage({
onSuccess: (updated) => {
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.id) });
queryClient.invalidateQueries({ queryKey: queryKeys.agents.configRevisions(agent.id) });
- if (!syncAgentRouteAfterRename(queryClient, navigate, agent, updated, urlTab ?? "configuration")) {
+ if (!syncAgentRouteAfterRename(queryClient, navigate, agent, updated, "revisions")) {
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.urlKey) });
}
},
});
return (
-
-
-
-
API Keys
-
+
+
+
Configuration Revisions
+ {configRevisions?.length ?? 0} total
-
- {/* Configuration Revisions — collapsible at the bottom */}
-
-
- {revisionsOpen && (
-
- {(configRevisions ?? []).length === 0 ? (
-
No configuration revisions yet.
- ) : (
-
- {(configRevisions ?? []).slice(0, 10).map((revision) => (
-
-
-
- {revision.id.slice(0, 8)}
- ·
- {formatDate(revision.createdAt)}
- ·
- {revision.source}
-
-
-
-
- Changed:{" "}
- {revision.changedKeys.length > 0 ? revision.changedKeys.join(", ") : "no tracked changes"}
-
-
- ))}
+ {(configRevisions ?? []).length === 0 ? (
+
No configuration revisions yet.
+ ) : (
+
+ {(configRevisions ?? []).map((revision) => (
+
+
+
+ {revision.id.slice(0, 8)}
+ ·
+ {formatDate(revision.createdAt)}
+ ·
+ {revision.source}
+
+
- )}
-
- )}
-
+
+ Changed: {revision.changedKeys.length > 0 ? revision.changedKeys.join(", ") : "no tracked changes"}
+
+
+ ))}
+
+ )}
);
}
@@ -2091,7 +2014,7 @@ function ConfigurationTab({
updatePermissions,
hidePromptTemplate,
hideInstructionsFile,
- content = "configuration",
+ content = "runtime",
canConfigureProviderTrace = false,
}: {
agent: AgentDetailRecord;
@@ -2103,7 +2026,7 @@ function ConfigurationTab({
updatePermissions: { mutate: (permissions: AgentPermissionUpdate) => void; isPending: boolean };
hidePromptTemplate?: boolean;
hideInstructionsFile?: boolean;
- content?: "configuration" | "secrets";
+ content?: "runtime" | "permissions" | "secrets";
canConfigureProviderTrace?: boolean;
}) {
const queryClient = useQueryClient();
@@ -2119,7 +2042,7 @@ function ConfigurationTab({
? queryKeys.agents.adapterModels(companyId, agent.adapterType)
: ["agents", "none", "adapter-models", agent.adapterType],
queryFn: () => agentsApi.adapterModels(companyId!, agent.adapterType),
- enabled: Boolean(companyId) && content === "configuration",
+ enabled: Boolean(companyId) && content === "runtime",
});
const lowTrustSelected = getTrustPreset(agent.permissions) === "low_trust_review";
@@ -2127,7 +2050,7 @@ function ConfigurationTab({
const { data: boundaryProjects, isLoading: boundaryProjectsLoading } = useQuery({
queryKey: companyId ? queryKeys.projects.list(companyId) : ["projects", "__low-trust-disabled"],
queryFn: () => projectsApi.list(companyId!),
- enabled: Boolean(companyId && lowTrustSelected) && content === "configuration",
+ enabled: Boolean(companyId && lowTrustSelected) && content === "permissions",
});
const { data: boundaryIssues, isLoading: boundaryIssuesLoading } = useQuery({
@@ -2135,7 +2058,7 @@ function ConfigurationTab({
? [...queryKeys.issues.list(companyId), "low-trust-boundary-candidates"]
: ["issues", "__low-trust-disabled"],
queryFn: () => issuesApi.list(companyId!, { limit: 100, sortField: "updated", sortDir: "desc" }),
- enabled: Boolean(companyId && lowTrustSelected) && content === "configuration",
+ enabled: Boolean(companyId && lowTrustSelected) && content === "permissions",
});
const updateAgent = useMutation({
@@ -2170,12 +2093,19 @@ function ConfigurationTab({
}
lastAgentRef.current = agent;
}, [agent, awaitingRefreshAfterSave]);
- const isConfigSaving = updateAgent.isPending || awaitingRefreshAfterSave;
+ const isConfigSaving = content !== "permissions" && (updateAgent.isPending || awaitingRefreshAfterSave);
useEffect(() => {
onSavingChange(isConfigSaving);
}, [onSavingChange, isConfigSaving]);
+ useEffect(() => {
+ if (content !== "permissions") return;
+ onDirtyChange(false);
+ onSaveActionChange(null);
+ onCancelActionChange(null);
+ }, [content, onCancelActionChange, onDirtyChange, onSaveActionChange]);
+
const canCreateAgents = Boolean(agent.permissions?.canCreateAgents);
const canCreateSkills = agent.permissions?.canCreateSkills !== false;
const canAssignTasks = Boolean(agent.access?.canAssignTasks);
@@ -2194,7 +2124,7 @@ function ConfigurationTab({
return (
-
updateAgent.mutateAsync(patch)}
@@ -2206,17 +2136,17 @@ function ConfigurationTab({
hideInlineSave
hidePromptTemplate={hidePromptTemplate}
hideInstructionsFile={hideInstructionsFile}
- content={content}
+ content={content === "runtime" ? "configuration" : "secrets"}
sectionLayout="cards"
canConfigureProviderTrace={canConfigureProviderTrace}
- />
- {content === "configuration" ? (
+ /> : null}
+ {content === "runtime" ? (
Saved adapter config affects the next run. Active runs keep the config they started with, and config changes may start a fresh adapter session.
) : null}
- {content === "configuration" ? : null}
- {content === "configuration" ?
+ {content === "permissions" ?
Permissions
@@ -2326,6 +2256,7 @@ export function PromptsTab({
const { selectedCompanyId } = useCompany();
const { isMobile } = useSidebar();
const [selectedFile, setSelectedFileState] = useState("AGENTS.md");
+ const [instructionMode, setInstructionMode] = useState<"read" | "edit" | "raw">("read");
const [showFilePanel, setShowFilePanel] = useState(false);
const [draft, setDraft] = useState(null);
const [bundleDraft, setBundleDraft] = useState<{
@@ -2362,6 +2293,7 @@ export function PromptsTab({
useEffect(() => {
editorInteractedRef.current = false;
setSelectedFile("AGENTS.md");
+ setInstructionMode("read");
setShowFilePanel(false);
setDraft(null);
setBundleDraft(null);
@@ -2952,6 +2884,7 @@ export function PromptsTab({
})}
onSelectFile={(filePath) => {
setSelectedFile(filePath);
+ setInstructionMode("read");
if (!fileOptions.includes(filePath)) setDraft("");
if (isMobile) setShowFilePanel(false);
}}
@@ -3018,6 +2951,21 @@ export function PromptsTab({
+
+ {(["read", "edit", "raw"] as const).map((mode) => (
+
+ ))}
+
{!fileLoading && (
+ ) : instructionMode === "read" ? (
+
+ {displayValue.trim() ? (
+ useMarkdownEditor ? (
+
+ {displayValue}
+
+ ) : (
+
{displayValue}
+ )
+ ) : (
+
This instruction file is empty.
+ )}
+
+ ) : instructionMode === "raw" ? (
+
+ {displayValue}
+
) : useMarkdownEditor ? (