S3.10: office card shows the person's pixel portrait; provider policy explanations move into column tooltips
CI / Typecheck, lint, tests, e2e (push) Failing after 6m37s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-09 14:03:19 -04:00
1 parent e5a4e87300
commit 05ad409624
4 files changed
+16 -14

No files matched your search

+2 -2
View File
@@ -12,7 +12,7 @@ import { dayPart, season } from "../shared/palette-clock";
import { pixelScale } from "../shared/pixel-scale";
import type { Camera, OfficeAgentInput } from "./office/office-types";
import { officeStatus } from "./office/agent-state";
import { officeRoster } from "./office/roster";
import { ceoIdOf, officeRoster } from "./office/roster";
import { t } from "../i18n/i18n";
const FPS_INTERVAL = 1000 / 24;
@@ -251,7 +251,7 @@ export function OfficePage({ snapshot }: PageProps) {
/>
{selectedAgent && (
<div ref={cardBoxRef} style={{ position: "absolute", left: 0, top: 0, willChange: "transform", visibility: "hidden" }}>
<AgentDetailCard agent={selectedAgent} onClose={() => setSelectedId(null)} />
<AgentDetailCard agent={selectedAgent} isCeo={selectedAgent.id === ceoIdOf(inputs)} onClose={() => setSelectedId(null)} />
</div>
)}
<div className="office-toolbar" role="toolbar" aria-label={t("Office tools")}>
@@ -1,8 +1,9 @@
import { Avatar, Icon, IconButton, Pill } from "../../shared/ui";
import { Icon, IconButton, Pill } from "../../shared/ui";
import { officeStateLabel, roleLevelLabel } from "../../i18n/labels";
import { t } from "../../i18n/i18n";
import { TaskHoldNotice } from "../work/TaskHoldNotice";
import type { OfficeAgentInput } from "./office-types";
import { PixelAvatar } from "./PixelAvatar";
import type { OfficeState } from "./agent-state";
const STATE_TONE: Record<OfficeState, "green" | "amber" | "red" | undefined> = {
@@ -17,7 +18,7 @@ const STATE_TONE: Record<OfficeState, "green" | "amber" | "red" | undefined> = {
* Floating profile card for the agent selected on the office floor. The page
* owns its placement (it follows the sprite); the card only sizes itself.
*/
export function AgentDetailCard({ agent, onClose }: { agent: OfficeAgentInput; onClose: () => void }) {
export function AgentDetailCard({ agent, isCeo, onClose }: { agent: OfficeAgentInput; isCeo: boolean; onClose: () => void }) {
return (
<div
role="dialog"
@@ -31,7 +32,7 @@ export function AgentDetailCard({ agent, onClose }: { agent: OfficeAgentInput; o
}}
>
<div className="row" style={{ gap: 10, alignItems: "flex-start" }}>
<Avatar name={agent.name} size="lg" bot />
<PixelAvatar id={agent.id} isCeo={isCeo} />
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: "var(--fs-body)", lineHeight: 1.3, wordBreak: "break-word" }}>{agent.name}</div>
<div style={{ fontSize: "var(--fs-body)", color: "var(--text-2)", marginTop: 1, wordBreak: "break-word" }}>{agent.title}</div>
@@ -23,20 +23,18 @@ export function ProviderPolicyTable({
return (
<>
<div className="section-label" style={{ marginBottom: 6 }}>{t("Runtime policy")}</div>
{/* What each column governs, so a change is made knowing what it reaches. */}
<ul style={{ fontSize: "var(--fs-body)", color: "var(--text-3)", lineHeight: 1.6, margin: "0 0 10px", paddingLeft: 18 }}>
<li>{t("Scope: “Workspace” refuses every call that is not made for a workspace, including agent sessions on tasks without one.")}</li>
<li>{t("Data policy: zero data retention refuses background requests, so it also switches background off.")}</li>
<li>{t("Background: lets requests from the request console run in the provider's background mode.")}</li>
<li>{t("Monthly limit: counts every model call this company makes through the provider in the calendar month (UTC); at the limit, calls are refused and agent work waits until the month resets.")}</li>
<li>{t("Context window: the size new sessions fit prompts, skills, history and tool results into; sessions already running keep theirs.")}</li>
</ul>
<div className="card" style={{ padding: 0, overflowX: "auto", marginBottom: 28 }}>
<div
className="table-row head"
style={{ gridTemplateColumns: POLICY_GRID, minWidth: 940 }}
>
<div>{t("Provider")}</div><div>{t("Scope")}</div><div>{t("Data policy")}</div><div>{t("Background")}</div><div>{t("Monthly limit")}</div><div>{t("Context window (tokens)")}</div><div>{t("Usage")}</div>
<div>{t("Provider")}</div>
<div title={t("Scope: “Workspace” refuses every call that is not made for a workspace, including agent sessions on tasks without one.")}>{t("Scope")}</div>
<div title={t("Data policy: zero data retention refuses background requests, so it also switches background off.")}>{t("Data policy")}</div>
<div title={t("Background: lets requests from the request console run in the provider's background mode.")}>{t("Background")}</div>
<div title={t("Monthly limit: counts every model call this company makes through the provider in the calendar month (UTC); at the limit, calls are refused and agent work waits until the month resets.")}>{t("Monthly limit")}</div>
<div title={t("Context window: the size new sessions fit prompts, skills, history and tool results into; sessions already running keep theirs.")}>{t("Context window (tokens)")}</div>
<div>{t("Usage")}</div>
</div>
{providers.map((provider, index) => (
<ProviderPolicyRow
+3
View File
@@ -128,6 +128,7 @@ test("the office floor opens agent details on click", async () => {
// Different people look different.
const looks = await avatars.evaluateAll((canvases) => canvases.map((canvas) => (canvas as HTMLCanvasElement).toDataURL()));
expect(new Set(looks).size).toBe(4);
const avaLook = await page.locator(".org-node-card", { hasText: "Ava Patel" }).locator("canvas.pixel-avatar").evaluate((canvas) => (canvas as HTMLCanvasElement).toDataURL());
await page.getByRole("button", { name: "Office", exact: true }).click();
await expect(canvas).toBeVisible();
await page.waitForTimeout(300);
@@ -139,6 +140,8 @@ test("the office floor opens agent details on click", async () => {
const avaCard = page.getByRole("dialog", { name: "Agent Ava Patel" });
await expect(avaCard).toBeVisible();
await expect(avaCard.getByText("Design", { exact: true })).toBeVisible();
// The card shows the same pixel face the org chart drew for Ava.
expect(await avaCard.locator("canvas.pixel-avatar").evaluate((canvas) => (canvas as HTMLCanvasElement).toDataURL())).toBe(avaLook);
const outDir = resolve("test-results/screenshots");
mkdirSync(outDir, { recursive: true });