/**
* `ModelServerLaunchBadge` — presentational launch-state indicator for an agent
* whose OpenCode profile binds a local model server (F35.1). All state is folded
* in {@link useAgents} (`modelServerStatusByServer` + `launchFailureByAgent`);
* this component only renders it.
*
* It shows, in order of severity:
* - a launch **failure** with its actionable message (not a bare "agent failed")
* — the full logs are never shown by default; a "Détails" toggle reveals the
* stable code/cause only;
* - otherwise the model-server lifecycle: `probing`, `starting`, `ready`
* (distinguishing a reused server from a freshly-started one).
*
* Renders nothing when there is neither a status to show nor a failure, so a
* plain (non-local-model) agent row stays untouched.
*/
import { useState } from "react";
import { cn } from "@/shared";
import type { ModelServerStatus } from "@/domain";
import type { AgentLaunchFailure } from "./useAgents";
export interface ModelServerLaunchBadgeProps {
/** The bound server's lifecycle status, when one has been observed. */
status?: ModelServerStatus;
/** The agent's last launch failure, when one occurred. */
failure?: AgentLaunchFailure;
}
/** Human label + tone for a non-failed lifecycle state. */
function describeStatus(
status: ModelServerStatus,
): { label: string; tone: string; role?: "status" } | null {
switch (status.state) {
case "notConfigured":
return null; // Nothing to surface for an unmanaged endpoint.
case "probing":
return { label: "vérification du serveur…", tone: "bg-muted/20 text-muted", role: "status" };
case "starting":
return { label: "démarrage du serveur…", tone: "bg-warning/20 text-warning", role: "status" };
case "downloading":
return { label: "téléchargement du modèle…", tone: "bg-warning/20 text-warning", role: "status" };
case "ready":
return status.reused
? { label: "serveur prêt (réutilisé)", tone: "bg-success/20 text-success" }
: { label: "serveur prêt", tone: "bg-success/20 text-success" };
case "failed":
// Handled by the failure branch below (richer, actionable).
return null;
}
}
export function ModelServerLaunchBadge({
status,
failure,
}: ModelServerLaunchBadgeProps) {
const [showDetail, setShowDetail] = useState(false);
// A launch failure (from `agentLaunchFailed`) or a `failed` status both mean
// the launch could not complete — prefer the agent-scoped failure (it carries
// the actionable message); fall back to the server `failed` status.
const failed: { code: string; message: string; cause?: string } | null =
failure
? failure
: status?.state === "failed"
? { code: status.code, message: status.message }
: null;
if (failed) {
return (
Échec du lancement : {failed.message}
{showDetail && (
code {failed.code}
{failed.cause ? ` · cause ${failed.cause}` : ""}
)}
);
}
if (!status) return null;
const described = describeStatus(status);
if (!described) return null;
return (
{described.label}
);
}