diff --git a/frontend/packages/swarm-ui/src/agent/state/StateBadges.tsx b/frontend/packages/swarm-ui/src/agent/state/StateBadges.tsx
index 365a3f348..1560b1858 100644
--- a/frontend/packages/swarm-ui/src/agent/state/StateBadges.tsx
+++ b/frontend/packages/swarm-ui/src/agent/state/StateBadges.tsx
@@ -1,6 +1,7 @@
import { Badge, type BadgeTone } from "@hive/shared/badge.js";
import { BadgePopover } from "../../ui/badge-popover/BadgePopover.js";
import { AgentInference } from "../detail/AgentInference.js";
+import { effortTitle, modelTitle } from "./badge-titles.js";
import { RelativeTime } from "../../ui/relative-time/RelativeTime.js";
import {
useSwarmAgentStateStream,
@@ -59,9 +60,6 @@ export function StateBadges({
// when clicked. Omitted: the badges only display.
agent?: string;
}) {
- const modelTitle = header.resolved_model
- ? `resolved to ${header.resolved_model}`
- : undefined;
return (
<>
+
) : (
@@ -102,13 +104,13 @@ export function StateBadges({
) : (
diff --git a/frontend/packages/swarm-ui/src/agent/state/badge-titles.ts b/frontend/packages/swarm-ui/src/agent/state/badge-titles.ts
new file mode 100644
index 000000000..0652a13f5
--- /dev/null
+++ b/frontend/packages/swarm-ui/src/agent/state/badge-titles.ts
@@ -0,0 +1,22 @@
+// The tooltips of the model and effort badges in an agent's terminal header.
+// Clickable ones, which open the agent's inference settings, say so; the plain
+// ones, on a subagent's terminal and in the details table, only say where the
+// value comes from.
+
+const OPENS = "Click for the inference settings";
+
+/** The model badge's tooltip: what the alias resolved to, when known. */
+export function modelTitle(
+ resolvedModel: string | null | undefined,
+ clickable: boolean,
+): string | undefined {
+ const resolved = resolvedModel ? `resolved to ${resolvedModel}` : undefined;
+ if (!clickable) return resolved;
+ return resolved ? `${resolved}. ${OPENS}` : OPENS;
+}
+
+/** The effort badge's tooltip: where the effort comes from. */
+export function effortTitle(source: string, clickable: boolean): string {
+ const from = `set by: ${source}`;
+ return clickable ? `${from}. ${OPENS}` : from;
+}
diff --git a/frontend/packages/swarm-ui/test/badge-titles.test.mjs b/frontend/packages/swarm-ui/test/badge-titles.test.mjs
new file mode 100644
index 000000000..6a5323470
--- /dev/null
+++ b/frontend/packages/swarm-ui/test/badge-titles.test.mjs
@@ -0,0 +1,27 @@
+// The model and effort badge tooltips. Run by `npm test`, which Node runs with
+// its built-in test runner and type stripping.
+import assert from "node:assert/strict";
+import { test } from "node:test";
+import { effortTitle, modelTitle } from "../src/agent/state/badge-titles.ts";
+
+test("a plain model badge says what the alias resolved to, or nothing", () => {
+ assert.equal(modelTitle("claude-x-1", false), "resolved to claude-x-1");
+ assert.equal(modelTitle(undefined, false), undefined);
+ assert.equal(modelTitle("", false), undefined);
+});
+
+test("a clickable model badge says it opens the settings", () => {
+ assert.equal(
+ modelTitle("claude-x-1", true),
+ "resolved to claude-x-1. Click for the inference settings",
+ );
+ assert.equal(modelTitle(undefined, true), "Click for the inference settings");
+});
+
+test("the effort badge names its source and, when clickable, the click", () => {
+ assert.equal(effortTitle("swarm", false), "set by: swarm");
+ assert.equal(
+ effortTitle("swarm", true),
+ "set by: swarm. Click for the inference settings",
+ );
+});