mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-19 04:00:38 +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",
|
"codex_local",
|
||||||
"cursor",
|
"cursor",
|
||||||
"gemini_local",
|
"gemini_local",
|
||||||
|
"hermes_local",
|
||||||
"opencode_local",
|
"opencode_local",
|
||||||
"pi_local",
|
"pi_local",
|
||||||
]);
|
]);
|
||||||
|
|
@ -76,6 +77,11 @@ export const ADAPTER_SESSION_MANAGEMENT: Record<string, AdapterSessionManagement
|
||||||
nativeContextManagement: "unknown",
|
nativeContextManagement: "unknown",
|
||||||
defaultSessionCompaction: DEFAULT_SESSION_COMPACTION_POLICY,
|
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> {
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
|
|
||||||
|
|
@ -263,12 +263,16 @@ function runMetrics(run: HeartbeatRun) {
|
||||||
);
|
);
|
||||||
const cost =
|
const cost =
|
||||||
visibleRunCostUsd(usage, result);
|
visibleRunCostUsd(usage, result);
|
||||||
|
const provider = asNonEmptyString(usage?.provider) ?? null;
|
||||||
|
const model = asNonEmptyString(usage?.model) ?? null;
|
||||||
return {
|
return {
|
||||||
input,
|
input,
|
||||||
output,
|
output,
|
||||||
cached,
|
cached,
|
||||||
cost,
|
cost,
|
||||||
totalTokens: input + output,
|
totalTokens: input + output,
|
||||||
|
provider,
|
||||||
|
model,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1127,6 +1131,7 @@ export function AgentDetail() {
|
||||||
agentRouteId={canonicalAgentRef}
|
agentRouteId={canonicalAgentRef}
|
||||||
selectedRunId={urlRunId ?? null}
|
selectedRunId={urlRunId ?? null}
|
||||||
adapterType={agent.adapterType}
|
adapterType={agent.adapterType}
|
||||||
|
adapterConfig={agent.adapterConfig}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -2905,6 +2910,7 @@ function RunsTab({
|
||||||
agentRouteId,
|
agentRouteId,
|
||||||
selectedRunId,
|
selectedRunId,
|
||||||
adapterType,
|
adapterType,
|
||||||
|
adapterConfig,
|
||||||
}: {
|
}: {
|
||||||
runs: HeartbeatRun[];
|
runs: HeartbeatRun[];
|
||||||
companyId: string;
|
companyId: string;
|
||||||
|
|
@ -2912,6 +2918,7 @@ function RunsTab({
|
||||||
agentRouteId: string;
|
agentRouteId: string;
|
||||||
selectedRunId: string | null;
|
selectedRunId: string | null;
|
||||||
adapterType: string;
|
adapterType: string;
|
||||||
|
adapterConfig: Record<string, unknown>;
|
||||||
}) {
|
}) {
|
||||||
const { isMobile } = useSidebar();
|
const { isMobile } = useSidebar();
|
||||||
|
|
||||||
|
|
@ -2940,7 +2947,7 @@ function RunsTab({
|
||||||
<ArrowLeft className="h-3.5 w-3.5" />
|
<ArrowLeft className="h-3.5 w-3.5" />
|
||||||
Back to runs
|
Back to runs
|
||||||
</Link>
|
</Link>
|
||||||
<RunDetail key={selectedRun.id} run={selectedRun} agentRouteId={agentRouteId} adapterType={adapterType} />
|
<RunDetail key={selectedRun.id} run={selectedRun} agentRouteId={agentRouteId} adapterType={adapterType} adapterConfig={adapterConfig} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -2971,7 +2978,7 @@ function RunsTab({
|
||||||
{/* Right: run detail — natural height, page scrolls */}
|
{/* Right: run detail — natural height, page scrolls */}
|
||||||
{selectedRun && (
|
{selectedRun && (
|
||||||
<div className="flex-1 min-w-0 pl-4">
|
<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>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -2980,7 +2987,7 @@ function RunsTab({
|
||||||
|
|
||||||
/* ---- Run Detail (expanded) ---- */
|
/* ---- 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 queryClient = useQueryClient();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { data: hydratedRun } = useQuery({
|
const { data: hydratedRun } = useQuery({
|
||||||
|
|
@ -3174,6 +3181,27 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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 && (
|
{resumeRun.isError && (
|
||||||
<div className="text-xs text-destructive">
|
<div className="text-xs text-destructive">
|
||||||
{resumeRun.error instanceof Error ? resumeRun.error.message : "Failed to resume run"}
|
{resumeRun.error instanceof Error ? resumeRun.error.message : "Failed to resume run"}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue