From 783f923d99e9cb85ae0d2430331d721ae0db8d4b Mon Sep 17 00:00:00 2001 From: wahidsaeed Date: Mon, 3 Aug 2026 22:48:28 +0200 Subject: [PATCH] fix(entity-ui): treat absent harness.kind as pi_core for Pi permissions visibility The runner defaults an omitted harness.kind to pi_core (agents/dtos.py's harness: str = "pi_core") and enforces Pi's allow/ask/deny permission rules accordingly. The Model & harness panel didn't apply the same default: harnessValue stayed null, so isPiHarness was false and the PiPermissionsControl was hidden even though the run enforces it. Extract the check into isPiHarnessValue() in connectionUtils.ts (an absent/null harness counts as Pi) and use it in useModelHarness's isPiHarness. Runtime behavior is unchanged; this is a visibility fix only. Fixes #5661 --- .../SchemaControls/agentTemplate/useModelHarness.tsx | 3 ++- .../src/DrillInView/SchemaControls/connectionUtils.ts | 10 ++++++++++ .../tests/unit/connectionUtils.test.ts | 9 +++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/useModelHarness.tsx b/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/useModelHarness.tsx index 2b0c32a775..c1f08c7df6 100644 --- a/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/useModelHarness.tsx +++ b/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/useModelHarness.tsx @@ -45,6 +45,7 @@ import { connectionFromConfig, harnessAllowsModel, harnessSupportsUserMcp, + isPiHarnessValue, modelIdFromConfig, modelLabel, providerForModel, @@ -172,7 +173,7 @@ export function useModelHarness({ // is harness-filtered: selecting a model sets BOTH the model id and its provider, fed by the // `/inspect` capability map below. const harnessValue = typeof harness.kind === "string" ? (harness.kind as string) : null - const isPiHarness = harnessValue === "pi_core" || harnessValue === "pi_agenta" + const isPiHarness = isPiHarnessValue(harnessValue) const llm = config.llm const modelId = useMemo(() => modelIdFromConfig(llm), [llm]) const connection = useMemo(() => connectionFromConfig(llm), [llm]) diff --git a/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/connectionUtils.ts b/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/connectionUtils.ts index 527e648a90..622e928747 100644 --- a/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/connectionUtils.ts +++ b/web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/connectionUtils.ts @@ -163,6 +163,16 @@ function capsFor( return capabilities[harness] ?? null } +/** + * Whether a harness value is one of the Pi harnesses. An absent `harness.kind` (`null`/`undefined`) + * runs as `pi_core` at runtime (see `agents/dtos.py`'s `harness: str = "pi_core"` default), so it + * counts as Pi here too — otherwise the Pi permissions controls stay hidden for a run that is + * actually enforcing them (#5661). + */ +export function isPiHarnessValue(harness: string | null | undefined): boolean { + return harness == null || harness === "pi_core" || harness === "pi_agenta" +} + /** External MCP authoring is available only when the selected harness publishes it. */ export function harnessSupportsUserMcp( capabilities: HarnessCapabilitiesMap | null | undefined, diff --git a/web/packages/agenta-entity-ui/tests/unit/connectionUtils.test.ts b/web/packages/agenta-entity-ui/tests/unit/connectionUtils.test.ts index 4c6b727406..13ec55cf48 100644 --- a/web/packages/agenta-entity-ui/tests/unit/connectionUtils.test.ts +++ b/web/packages/agenta-entity-ui/tests/unit/connectionUtils.test.ts @@ -20,6 +20,7 @@ import { harnessAllowsProvider, harnessSupportsUserMcp, isDeploymentProviderKind, + isPiHarnessValue, modelIdFromConfig, modelSelectionMode, providerForModel, @@ -195,6 +196,14 @@ describe("connectionUtils: capability gating (inspect-fed)", () => { expect(modelSelectionMode(CAPABILITIES, "claude")).toBe("alias") }) + it("treats an absent harness.kind as pi_core, matching the runner default (#5661)", () => { + expect(isPiHarnessValue(undefined)).toBe(true) + expect(isPiHarnessValue(null)).toBe(true) + expect(isPiHarnessValue("pi_core")).toBe(true) + expect(isPiHarnessValue("pi_agenta")).toBe(true) + expect(isPiHarnessValue("claude")).toBe(false) + }) + it("is permissive when the map or harness is missing", () => { expect(allowedProviders(null, "pi_core")).toEqual(["*"]) expect(allowedProviders(CAPABILITIES, "future-harness")).toEqual(["*"])