mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
feat: add hermes_local session management and show provider/model in run details
This commit is contained in:
parent
388650afc7
commit
acfd7c260a
2 changed files with 37 additions and 3 deletions
|
|
@ -41,6 +41,7 @@ export const LEGACY_SESSIONED_ADAPTER_TYPES = new Set([
|
|||
"codex_local",
|
||||
"cursor",
|
||||
"gemini_local",
|
||||
"hermes_local",
|
||||
"opencode_local",
|
||||
"pi_local",
|
||||
]);
|
||||
|
|
@ -76,6 +77,11 @@ export const ADAPTER_SESSION_MANAGEMENT: Record<string, AdapterSessionManagement
|
|||
nativeContextManagement: "unknown",
|
||||
defaultSessionCompaction: DEFAULT_SESSION_COMPACTION_POLICY,
|
||||
},
|
||||
hermes_local: {
|
||||
supportsSessionResume: true,
|
||||
nativeContextManagement: "confirmed",
|
||||
defaultSessionCompaction: ADAPTER_MANAGED_SESSION_POLICY,
|
||||
},
|
||||
};
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
|
|
|
|||
|
|
@ -263,12 +263,16 @@ function runMetrics(run: HeartbeatRun) {
|
|||
);
|
||||
const cost =
|
||||
visibleRunCostUsd(usage, result);
|
||||
const provider = asNonEmptyString(usage?.provider) ?? null;
|
||||
const model = asNonEmptyString(usage?.model) ?? null;
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
cached,
|
||||
cost,
|
||||
totalTokens: input + output,
|
||||
provider,
|
||||
model,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1127,6 +1131,7 @@ export function AgentDetail() {
|
|||
agentRouteId={canonicalAgentRef}
|
||||
selectedRunId={urlRunId ?? null}
|
||||
adapterType={agent.adapterType}
|
||||
adapterConfig={agent.adapterConfig}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
@ -2905,6 +2910,7 @@ function RunsTab({
|
|||
agentRouteId,
|
||||
selectedRunId,
|
||||
adapterType,
|
||||
adapterConfig,
|
||||
}: {
|
||||
runs: HeartbeatRun[];
|
||||
companyId: string;
|
||||
|
|
@ -2912,6 +2918,7 @@ function RunsTab({
|
|||
agentRouteId: string;
|
||||
selectedRunId: string | null;
|
||||
adapterType: string;
|
||||
adapterConfig: Record<string, unknown>;
|
||||
}) {
|
||||
const { isMobile } = useSidebar();
|
||||
|
||||
|
|
@ -2940,7 +2947,7 @@ function RunsTab({
|
|||
<ArrowLeft className="h-3.5 w-3.5" />
|
||||
Back to runs
|
||||
</Link>
|
||||
<RunDetail key={selectedRun.id} run={selectedRun} agentRouteId={agentRouteId} adapterType={adapterType} />
|
||||
<RunDetail key={selectedRun.id} run={selectedRun} agentRouteId={agentRouteId} adapterType={adapterType} adapterConfig={adapterConfig} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -2971,7 +2978,7 @@ function RunsTab({
|
|||
{/* Right: run detail — natural height, page scrolls */}
|
||||
{selectedRun && (
|
||||
<div className="flex-1 min-w-0 pl-4">
|
||||
<RunDetail key={selectedRun.id} run={selectedRun} agentRouteId={agentRouteId} adapterType={adapterType} />
|
||||
<RunDetail key={selectedRun.id} run={selectedRun} agentRouteId={agentRouteId} adapterType={adapterType} adapterConfig={adapterConfig} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -2980,7 +2987,7 @@ function RunsTab({
|
|||
|
||||
/* ---- Run Detail (expanded) ---- */
|
||||
|
||||
function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: HeartbeatRun; agentRouteId: string; adapterType: string }) {
|
||||
function RunDetail({ run: initialRun, agentRouteId, adapterType, adapterConfig }: { run: HeartbeatRun; agentRouteId: string; adapterType: string; adapterConfig: Record<string, unknown> }) {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
const { data: hydratedRun } = useQuery({
|
||||
|
|
@ -3174,6 +3181,27 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
|
|||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{/* Adapter type · provider · model */}
|
||||
{(() => {
|
||||
const displayProvider = metrics.provider
|
||||
?? asNonEmptyString(adapterConfig?.provider);
|
||||
const displayModel = metrics.model
|
||||
?? asNonEmptyString(adapterConfig?.model);
|
||||
if (!adapterType && !displayProvider && !displayModel) return null;
|
||||
return (
|
||||
<div className="text-[11px] text-muted-foreground font-mono flex items-center gap-1.5 flex-wrap">
|
||||
{adapterType && (
|
||||
<span className="bg-muted rounded px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide">{adapterType.replace(/_/g, " ")}</span>
|
||||
)}
|
||||
{displayProvider && displayModel && (
|
||||
<span>{displayProvider}/{displayModel}</span>
|
||||
)}
|
||||
{!displayProvider && displayModel && (
|
||||
<span>{displayModel}</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
{resumeRun.isError && (
|
||||
<div className="text-xs text-destructive">
|
||||
{resumeRun.error instanceof Error ? resumeRun.error.message : "Failed to resume run"}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue