Skip to content
Draft
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
25 changes: 23 additions & 2 deletions packages/shared/src/agent-platform-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,34 @@ export interface AgentApplication {

// --- Revisions -------------------------------------------------------------

/** Normalized reasoning-effort knob; mirrors the backend spec schema. */
export type ReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh";

/** One model in a manual priority list; per-entry reasoning overrides the spec default. */
export interface ModelEntry {
model: string;
reasoning?: ReasoningEffort;
}

/** Quality/cost level for an `auto` policy, resolved to a maintained model list at runtime. */
export type ModelLevel = "low" | "medium" | "high";

/**
* Model selection. `auto` resolves a level to a platform-maintained,
* priority-ordered list at runtime; `manual` is the author's explicit
* priority list (first entry primary, rest fallbacks).
*/
export type ModelPolicy =
| { mode: "auto"; level: ModelLevel; reasoning?: ReasoningEffort }
| { mode: "manual"; models: ModelEntry[] };

/**
* The agent spec carried on a revision. Fully typed elaboration (triggers,
* tools, mcps, skills, limits) lands with the config editor milestone; for now
* the known top-level fields are surfaced and the rest passes through.
*/
export interface AgentSpec {
model: string;
model_policy?: ModelPolicy;
triggers?: unknown[];
tools?: unknown[];
mcps?: unknown[];
Expand All @@ -86,7 +107,7 @@ export interface AgentSpec {
max_wall_seconds?: number;
};
entrypoint?: string;
reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh";
reasoning?: ReasoningEffort;
[key: string]: unknown;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useAgentApplication } from "../hooks/useAgentApplication";
import { useAgentChat } from "../hooks/useAgentChat";
import { useAgentChatPendingApproval } from "../hooks/useAgentChatPendingApproval";
import { useAgentRevision } from "../hooks/useAgentRevision";
import { modelPolicySummary } from "../utils/format";
import { resolveIngressBaseUrl } from "../utils/ingress";
import { AgentChatPendingApprovalCard } from "./AgentChatPendingApprovalCard";
import { AgentChatSurface } from "./AgentChatSurface";
Expand Down Expand Up @@ -199,7 +200,7 @@ export function AgentChatPane({
<PreviewBanner
revisionId={targetRevisionId}
isDraft={isDraftPreview}
model={revision?.spec?.model}
model={modelPolicySummary(revision?.spec?.model_policy)}
region={cloudRegion}
/>
<AgentChatSurface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,36 @@ function byPath(files: BundleFile[], path: string): BundleFile | undefined {
// --- bodies -----------------------------------------------------------------

function ModelBody({ spec }: { spec: AgentSpec }) {
const policy = spec.model_policy;
return (
<Flex direction="column" gap="2">
<Row label="model" value={spec.model ?? "not set"} mono />
<Row label="reasoning" value={spec.reasoning ?? "default"} />
{policy ? (
<Row label="policy" value={policy.mode} />
) : (
<Row label="model" value="not set" mono />
)}
{policy?.mode === "auto" ? (
<>
<Row label="level" value={policy.level} />
<Row
label="reasoning"
value={policy.reasoning ?? spec.reasoning ?? "default"}
/>
</>
) : null}
{policy?.mode === "manual" ? (
<>
{policy.models.map((m, i) => (
<Row
key={`${m.model}:${m.reasoning ?? "_"}`}
label={i === 0 ? "model" : "fallback"}
Comment on lines +640 to +643

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Duplicate-key risk in manual model list. The composite key ${m.model}:${m.reasoning ?? "_"} is not guaranteed unique — if the same model appears twice in the priority list (e.g., two entries for "claude-3-5-sonnet" with no per-entry reasoning), React will emit a duplicate-key warning and reconciliation may misbehave. Array index is a safe alternative for a stable, ordered priority list where items are never reordered in-place.

Suggested change
{policy.models.map((m, i) => (
<Row
key={`${m.model}:${m.reasoning ?? "_"}`}
label={i === 0 ? "model" : "fallback"}
{policy.models.map((m, i) => (
<Row
key={i}
label={i === 0 ? "model" : "fallback"}
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/agent-applications/components/AgentConfigurationPane.tsx
Line: 640-643

Comment:
Duplicate-key risk in manual model list. The composite key `${m.model}:${m.reasoning ?? "_"}` is not guaranteed unique — if the same model appears twice in the priority list (e.g., two entries for `"claude-3-5-sonnet"` with no per-entry reasoning), React will emit a duplicate-key warning and reconciliation may misbehave. Array index is a safe alternative for a stable, ordered priority list where items are never reordered in-place.

```suggestion
          {policy.models.map((m, i) => (
            <Row
              key={i}
              label={i === 0 ? "model" : "fallback"}
```

How can I resolve this? If you propose a fix, please make it concise.

value={m.reasoning ? `${m.model} · ${m.reasoning}` : m.model}
mono
/>
))}
<Row label="reasoning" value={spec.reasoning ?? "default"} />
</>
) : null}
{spec.entrypoint ? (
<Row label="entrypoint" value={spec.entrypoint} mono />
) : null}
Expand Down
12 changes: 12 additions & 0 deletions packages/ui/src/features/agent-applications/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {
AgentApprovalRequestState,
AgentRevisionState,
AgentSessionState,
ModelPolicy,
} from "@posthog/shared/agent-platform-types";
/** Formats a USD spend value for the fleet / agent stat strips. */
export function formatSpendUsd(value: number | null | undefined): string {
Expand Down Expand Up @@ -111,3 +112,14 @@ export function revisionStateColor(
return "gray";
}
}

/** Short, glanceable model-policy label for banners (e.g. "auto · high", "claude-sonnet-4-6 +1"). */
export function modelPolicySummary(
policy: ModelPolicy | null | undefined,
): string | undefined {
if (!policy) return undefined;
if (policy.mode === "auto") return `auto · ${policy.level}`;
const [first, ...rest] = policy.models;
if (!first) return "manual";
return rest.length > 0 ? `${first.model} +${rest.length}` : first.model;
}
Loading