Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/studio/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
type StandingRouteState,
type StandingRouteUsage,
} from "@/data/standing-routes";
import { executionProfileRowIdentity } from "@/lib/execution-profile-row-identity";
import { cn } from "@/lib/utils";
import {
parseWorkspaceRoute,
Expand Down Expand Up @@ -5790,6 +5791,7 @@ function AgentOperationsView() {
<div className="agent-runtime-row" key={`capability:${profile.executionProfileId}`}>
<div>
<strong>{runtime?.kind ?? "runtime"} · {model?.model ?? "model"}</strong>
<span>{executionProfileRowIdentity(profile)}</span>
<span>{capability?.serviceCapability ?? "UNVERIFIED"} · {capability?.diagnostic ?? "not checked"}</span>
</div>
<Button
Expand Down Expand Up @@ -5845,7 +5847,7 @@ function AgentOperationsView() {
<label><span>Execution profile</span><Select value={profileId} onValueChange={(value) => { setProfileId(value); setManualPreview(null); }}><SelectTrigger><SelectValue placeholder="Select profile" /></SelectTrigger><SelectContent>{profiles.map((profile) => {
const runtime = runtimes.get(profile.runtimeDefinitionId);
const model = models.get(profile.modelProfileId);
return <SelectItem key={profile.executionProfileId} value={profile.executionProfileId}>{runtime?.kind ?? "runtime"} · {model?.model ?? "model"} · r{profile.revision}</SelectItem>;
return <SelectItem key={profile.executionProfileId} value={profile.executionProfileId}>{runtime?.kind ?? "runtime"} · {model?.model ?? "model"} · {executionProfileRowIdentity(profile)}</SelectItem>;
})}</SelectContent></Select></label>
</div>
<div className="agent-control-actions">
Expand Down Expand Up @@ -6889,7 +6891,7 @@ function RealCandidatePreflightView() {
<CardContent className="preflight-stage-list">
{currentStages.map((stage, index) => (
<div className="preflight-stage" key={stage.stage}>
<span className={stage.status === "PASS" ? "" : "is-blocked"}>
<span className={stage.status === "PASS" ? "preflight-stage-index" : "preflight-stage-index is-blocked"}>
{stage.status === "PASS" ? index + 1 : <CircleOff size={11} />}
</span>
<div>
Expand Down
12 changes: 7 additions & 5 deletions apps/studio/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -5506,22 +5506,24 @@ footer span:first-child {
.preflight-disposition-facts span,
.preflight-disposition-facts strong {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.preflight-disposition-facts span {
color: #685c51;
font-size: 12px;
text-transform: uppercase;
overflow: visible;
white-space: normal;
}

.preflight-disposition-facts strong {
margin-top: 5px;
overflow: hidden;
color: #c28f62;
font-family: inherit;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}

.preflight-disposition > code {
Expand Down Expand Up @@ -6006,7 +6008,7 @@ footer span:first-child {
padding-bottom: 0;
}

.preflight-stage > span {
.preflight-stage-index {
display: grid;
width: 22px;
height: 22px;
Expand All @@ -6018,7 +6020,7 @@ footer span:first-child {
font-size: 12px;
}

.preflight-stage > span.is-blocked {
.preflight-stage-index.is-blocked {
border-color: rgba(213, 161, 110, 0.18);
color: #d5a16e;
}
Expand Down
51 changes: 51 additions & 0 deletions apps/studio/src/lib/execution-profile-row-identity.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, expect, it } from "vitest";

import { executionProfileRowIdentity } from "./execution-profile-row-identity.js";

const terraCodex = {
executionProfileId: `sha256:${"a".repeat(64)}`,
profileKey: "rule-evidence-codex-app-server",
revision: 1006,
} as const;

const terraOntology = {
executionProfileId: `sha256:${"b".repeat(64)}`,
profileKey: "ontology-codex-app-server",
revision: 1002,
} as const;

describe("execution profile row identity", () => {
it("shows the picker rN plus profileKey and a short id", () => {
expect(executionProfileRowIdentity(terraCodex)).toBe(
"r1006 · rule-evidence-codex-app-server · aaaaaaaaaa",
);
});

it("distinguishes same-runtime same-model rows the picker would otherwise collapse", () => {
const left = executionProfileRowIdentity(terraCodex);
const right = executionProfileRowIdentity(terraOntology);
expect(left).not.toBe(right);
expect(left).toContain("r1006");
expect(right).toContain("r1002");
expect(left).toContain("rule-evidence-codex-app-server");
expect(right).toContain("ontology-codex-app-server");
expect(left).toContain("aaaaaaaaaa");
expect(right).toContain("bbbbbbbbbb");
});

it("keeps later revisions of the same profileKey distinct", () => {
expect(executionProfileRowIdentity({
...terraCodex,
executionProfileId: `sha256:${"c".repeat(64)}`,
revision: 2006,
})).toBe("r2006 · rule-evidence-codex-app-server · cccccccccc");
});

it("does not turn the capability list into a run or campaign control", () => {
const label = executionProfileRowIdentity(terraCodex).toLowerCase();
expect(label).not.toContain("preflight");
expect(label).not.toContain("run");
expect(label).not.toContain("campaign");
expect(label).not.toContain("spend");
});
});
20 changes: 20 additions & 0 deletions apps/studio/src/lib/execution-profile-row-identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const HASH_PREFIX = "sha256:";
const SHORT_ID_LENGTH = 10;

export type ExecutionProfileRowIdentityInput = Readonly<{
executionProfileId: string;
profileKey: string;
revision: number;
}>;

function shortExecutionProfileId(executionProfileId: string): string {
return executionProfileId.startsWith(HASH_PREFIX)
? executionProfileId.slice(HASH_PREFIX.length, HASH_PREFIX.length + SHORT_ID_LENGTH)
: executionProfileId.slice(0, SHORT_ID_LENGTH);
}

export function executionProfileRowIdentity(
profile: ExecutionProfileRowIdentityInput,
): string {
return `r${profile.revision} · ${profile.profileKey} · ${shortExecutionProfileId(profile.executionProfileId)}`;
}
24 changes: 24 additions & 0 deletions apps/studio/src/lib/preflight-disposition-facts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";

const studioRoot = join(dirname(fileURLToPath(import.meta.url)), "..");

describe("preflight disposition fact labels", () => {
it("does not ellipsize POST-FEE UPPER BOUND", () => {
const css = readFileSync(join(studioRoot, "index.css"), "utf8");
const start = css.indexOf(".preflight-disposition-facts span {");
expect(start).toBeGreaterThan(-1);
const block = css.slice(start, css.indexOf("}", start) + 1);
expect(block).toContain("white-space: normal");
expect(block).not.toContain("ellipsis");
expect(block).not.toContain("nowrap");
});

it("keeps the Post-fee upper bound copy on the current-snapshot row", () => {
const app = readFileSync(join(studioRoot, "App.tsx"), "utf8");
expect(app).toContain("<span>Post-fee upper bound</span>");
expect(app).toContain("className=\"preflight-disposition-facts\"");
});
});
21 changes: 21 additions & 0 deletions apps/studio/src/lib/preflight-stage-index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";

const studioRoot = join(dirname(fileURLToPath(import.meta.url)), "..");

describe("preflight stage index circle", () => {
it("scopes the 22px circle to the step index, not every child span", () => {
const css = readFileSync(join(studioRoot, "index.css"), "utf8");
expect(css).toContain(".preflight-stage-index {");
expect(css).toContain("width: 22px;");
expect(css).not.toMatch(/\.preflight-stage\s*>\s*span\s*\{/);
});

it("marks the step index with preflight-stage-index so Badge stays a pill", () => {
const app = readFileSync(join(studioRoot, "App.tsx"), "utf8");
expect(app).toContain('className={stage.status === "PASS" ? "preflight-stage-index" : "preflight-stage-index is-blocked"}');
expect(app).toContain("<Badge variant={stage.status === \"PASS\" ? \"verified\" : \"shadow\"}>");
});
});