Skip to content

Commit 6a62cd4

Browse files
committed
fix: include harnesses in /api/resources response for browser UI
The frontend Agent Inspector crashes with "Cannot read properties of undefined (reading 'find')" when switching to a harness because the /api/resources endpoint was missing the harnesses array entirely. Constraint: Frontend expects harnesses array with deploymentStatus and deployed fields Confidence: high Scope-risk: narrow
1 parent 022ce41 commit 6a62cd4

5 files changed

Lines changed: 47 additions & 6 deletions

File tree

src/cli/operations/dev/web-ui/api-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ export interface ResourceHarness {
456456
name: string;
457457
model: string;
458458
tools: string[];
459+
deploymentStatus?: ResourceDeploymentStatus;
460+
deployed?: DeployedHarnessState;
459461
}
460462

461463
export interface DeployedHarnessState {

src/cli/operations/dev/web-ui/handlers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ export { handleListCloudWatchTraces, handleGetCloudWatchTrace } from './cloudwat
88
export { handleListMemoryRecords, handleRetrieveMemoryRecords } from './memory';
99
export { handleMcpProxy } from './mcp-proxy';
1010
export { handleA2AAgentCard } from './a2a-proxy';
11+
export { handleHarnessInvocation } from './harness-invocation';
12+
export { handleHarnessToolResponse } from './harness-tool-response';

src/cli/operations/dev/web-ui/handlers/resources.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
ResourceDeploymentStatus,
99
ResourceEvaluator,
1010
ResourceGateway,
11+
ResourceHarness,
1112
ResourceMemory,
1213
ResourceOnlineEvalConfig,
1314
ResourcePolicyEngine,
@@ -106,6 +107,42 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or
106107
}
107108
}
108109

110+
// Build harnesses from local config
111+
const localHarnessNames = new Set((project.harnesses ?? []).map(h => h.name));
112+
const harnesses: ResourceHarness[] = [];
113+
for (const h of project.harnesses ?? []) {
114+
let model = '';
115+
let tools: string[] = [];
116+
try {
117+
const spec = await configIO.readHarnessSpec(h.name);
118+
model = `${spec.model.provider}/${spec.model.modelId}`;
119+
tools = spec.tools.map(t => t.name);
120+
} catch {
121+
// harness spec may be unreadable — show what we can
122+
}
123+
const deployed = targetResources?.harnesses?.[h.name];
124+
harnesses.push({
125+
name: h.name,
126+
model,
127+
tools,
128+
deploymentStatus: statusByTypeAndName.get(`harness:${h.name}`),
129+
deployed: deployed ? { harnessId: deployed.harnessId, harnessArn: deployed.harnessArn } : undefined,
130+
});
131+
}
132+
133+
// Add pending-removal harnesses
134+
for (const [name, deployed] of Object.entries(targetResources?.harnesses ?? {})) {
135+
if (!localHarnessNames.has(name)) {
136+
harnesses.push({
137+
name,
138+
model: '',
139+
tools: [],
140+
deploymentStatus: 'pending-removal' as ResourceDeploymentStatus,
141+
deployed: { harnessId: deployed.harnessId, harnessArn: deployed.harnessArn },
142+
});
143+
}
144+
}
145+
109146
// Build memories from local config
110147
const localMemoryNames = new Set(project.memories.map(m => m.name));
111148
const memories: ResourceMemory[] = project.memories.map(m => ({
@@ -274,6 +311,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or
274311
success: true,
275312
project: project.name,
276313
agents,
314+
harnesses,
277315
memories,
278316
credentials,
279317
gateways,

src/cli/operations/dev/web-ui/web-server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
handleA2AAgentCard,
77
handleGetCloudWatchTrace,
88
handleGetTrace,
9+
handleHarnessToolResponse,
910
handleInvocations,
1011
handleListCloudWatchTraces,
1112
handleListMemoryRecords,
@@ -344,6 +345,8 @@ export class WebUIServer {
344345
await handleListCloudWatchTraces(ctx, req, res, origin);
345346
} else if (req.method === 'POST' && req.url === '/api/start') {
346347
await handleStart(ctx, req, res, origin);
348+
} else if (req.method === 'POST' && req.url === '/api/harness/tool-response') {
349+
await handleHarnessToolResponse(ctx, req, res, origin);
347350
} else if (req.method === 'POST' && req.url === '/invocations') {
348351
await handleInvocations(ctx, req, res, origin);
349352
} else if (req.method === 'POST' && req.url === '/api/mcp') {

src/cli/tui/screens/dev/DevScreen.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,8 @@ export function DevScreen(props: DevScreenProps) {
416416
const harnessIdx = selectedAgentIndex - supportedAgents.length;
417417
const harnessName = availableHarnesses[harnessIdx];
418418
if (harnessName) {
419-
if (onLaunchBrowser) {
420-
onLaunchBrowser({ harnessName });
421-
} else {
422-
setSelectedHarness(harnessName);
423-
setMode('deploying');
424-
}
419+
setSelectedHarness(harnessName);
420+
setMode('deploying');
425421
}
426422
}
427423
}

0 commit comments

Comments
 (0)