Skip to content

feat(dev): agent-proxy routes for the Agent Inspector - #2085

Merged
tejaskash merged 5 commits into
refactorfrom
feat/inspector-agent-proxies
Aug 26, 2026
Merged

feat(dev): agent-proxy routes for the Agent Inspector#2085
tejaskash merged 5 commits into
refactorfrom
feat/inspector-agent-proxies

Conversation

@tejaskash

@tejaskash tejaskash commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

What

Adds the Agent Inspector routes that talk to a running agent or read the project spec. This layer is still a pure request-to-response handler and is not reachable from the CLI yet. The project dev wiring lands in #2086.

Routes

  • POST /invocations — protocol-aware proxy. HTTP, A2A, and AGUI agents are each normalized into the SPA's data: <json> SSE contract. MCP returns a clear error pointing at /api/mcp rather than being proxied as HTTP.
  • POST /api/mcp — forwards a JSON-RPC body to the agent's /mcp endpoint, buffering the reply under a 10MB cap.
  • GET /api/a2a/agent-card — fetches the running agent's A2A card.
  • GET /api/resources — flattens project.spec into the resource graph the SPA renders.

Tests

Every route is unit tested behind fake deps: invocation routing and SSE normalization (including A2A dedup and the non-streaming fallback), the MCP forward and its size cap, the agent-card paths, the resource graph, and httpServer's streaming and abort handling.

bun test, typecheck, lint:check, format:check all green.

@github-actions github-actions Bot added the size/xl PR size: XL label Aug 24, 2026
@github-actions github-actions Bot added agentcore-harness-reviewing AgentCore Harness review in progress and removed agentcore-harness-reviewing AgentCore Harness review in progress labels Aug 24, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 24, 2026
@tejaskash
tejaskash force-pushed the feat/inspector-agent-proxies branch from fcff328 to 013ffe2 Compare August 25, 2026 17:35
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 25, 2026
@tejaskash tejaskash changed the title feat(dev): Agent Inspector agent-proxy routes (C2) feat(dev): Agent Inspector agent-proxy routes Aug 25, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 25, 2026
@tejaskash
tejaskash force-pushed the feat/inspector-agent-proxies branch from 013ffe2 to 5e98a35 Compare August 25, 2026 17:45
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 25, 2026
@codecov-commenter

codecov-commenter commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.09707% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.39%. Comparing base (097e1f0) to head (279c0da).
⚠️ Report is 2 commits behind head on refactor.

Files with missing lines Patch % Lines
src/core/dev/inspector/proxies.ts 94.28% 4 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #2085      +/-   ##
============================================
+ Coverage     97.38%   97.39%   +0.01%     
============================================
  Files           440      449       +9     
  Lines         26626    27474     +848     
============================================
+ Hits          25929    26759     +830     
- Misses          697      715      +18     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tejaskash tejaskash changed the title feat(dev): Agent Inspector agent-proxy routes feat(dev): agent-proxy routes for the Agent Inspector Aug 25, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 25, 2026
@tejaskash
tejaskash force-pushed the feat/inspector-agent-proxies branch from 5e98a35 to 5cfa15f Compare August 25, 2026 19:01
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 25, 2026
@tejaskash
tejaskash force-pushed the feat/inspector-agent-proxies branch from 5cfa15f to d6abf97 Compare August 25, 2026 19:39
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 26, 2026
Base automatically changed from feat/inspector-http-layer to refactor August 26, 2026 15:05
@tejaskash
tejaskash force-pushed the feat/inspector-agent-proxies branch 2 times, most recently from 6f5b3a3 to 0a6bec4 Compare August 26, 2026 15:09
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 26, 2026
Add the Inspector routes that talk to a running agent or read the
project spec, extending the C1 route table:

- POST /invocations proxies HTTP, A2A, and AGUI agents, normalizing each
  into the SPA's data:<json> SSE contract. MCP agents get a clear error
  directing them to /api/mcp rather than being mis-proxied as HTTP.
- POST /api/mcp forwards a JSON-RPC body to the agent's /mcp endpoint and
  buffers the reply under a 10MB cap.
- GET /api/a2a/agent-card fetches the running agent's A2A card.
- GET /api/resources flattens the project spec into the resource graph.

Every upstream fetch carries the client's abort signal, and io/httpServer
streams async-iterable bodies with backpressure so a disconnect tears the
upstream request down on Node. A single session id threads through the
request header, agent body, and echoed x-session-id.

SSE parsing follows the framing rules (optional leading space, multi-line
data fields, blank-line event boundary) instead of a hardcoded slice.
- collapse invokeHttpAgent/invokeAguiAgent into a shared forwardInvocation
- single-return parseAgentEvent normalizing empty payloads to null
- hoist the SSE TextEncoder to module scope
- readCapped iterates over the shared iterateBody helper
- drop the a2aId counter; A2A message ids use randomUUID
- add the AGUI missing-prompt test
Delete JSDoc and inline notes that narrate what the code already shows.
Keep only one-line notes for non-obvious reasoning (security guards,
cross-runtime disconnect behavior, wire-contract field names, SSE framing).
…atch

- Inline the single-caller invokeHttpAgent wrapper into handleInvocations.
- Make invokeAguiAgent async so its guard returns apiError directly.
- Return kind from extractSseEventText instead of re-deriving it in a
  separate isStatusUpdateEvent pass.
- Collapse the A2A part/artifact accumulator loops into filter/map/join.
@tejaskash
tejaskash force-pushed the feat/inspector-agent-proxies branch from d66062a to 0c0f90f Compare August 26, 2026 18:26
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 26, 2026
- Populate the resources fixture with one of every resource type so each
  wire-shaping map callback is exercised (was 55% covered).
- Add invocation unhappy paths: upstream 502s, parseAgentEvent null frames,
  A2A artifact/task extraction, non-streaming and non-JSON fallbacks.
- Cover httpServer backpressure drain and the post-headers stream error.
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 26, 2026

@Hweinstock Hweinstock left a comment

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.

LGTM! some small suggestions/questions but no blockers.

return json(200, status);
}

/** POST /api/start — start an agent on demand; concurrent starts share one attempt. */

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.

q: were these removed on purpose?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, on purpose. Those route JSDocs just restated the method/path already visible in the handler, so the comment-cleanup pass dropped them per the no-restating-the-code guideline. The security and wire-contract comments stayed.

body,
signal,
});
} catch (error) {

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.

would there be a benefit to wire the logger here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There's no logger in this layer today (the dev handler surfaces status via renderStatus and lets errors propagate). The upstream failure already reaches the user as the 502 body in the Inspector, so I left it. Happy to add structured logging if we introduce a logger dep for the dev command more broadly.

// Handles bedrock {text}, {error}, ConverseStream contentBlockDelta, bare JSON string, and non-JSON tokens.
export function parseAgentEvent(data: string): string | { error: string } | null {
try {
const parsed: unknown = JSON.parse(data);

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.

would it simplify this code to use a zod schema that we parse with?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I looked at it — zod does not buy much here. parseAgentEvent takes loosely-typed passthrough tokens from arbitrary agent runtimes, handles several shapes ({text}, {error}, ConverseStream delta, bare string) AND a non-JSON fallback that returns the raw token. A zod union would still need the try/catch + raw fallback + empty-to-null glue, so the imperative form stays clearer. Left as is.

}

// When streamedFromStatus is set, artifact-update text is skipped because status-update already streamed it.
function extractSseEventText(

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.

should this function signature / name mention that its A2A specific?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call — renamed to extractA2aEventText in #2086 (0791591). It only handles A2A artifact/status/task kinds, so the generic SSE name was misleading.

expect(await response.text()).toBe(`data: ${JSON.stringify({ error: "boom" })}\n\n`);
});

test("passes a non-SSE response body through untouched", async () => {

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.

i like how readable these tests are.

Comment thread src/io/httpServer.ts
): Promise<void> {
for await (const chunk of body) {
if (signal.aborted) break;
if (!response.write(chunk)) await drain(response, signal);

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.

nice and simple!

@tejaskash
tejaskash merged commit 9ab30d3 into refactor Aug 26, 2026
16 checks passed
@tejaskash
tejaskash deleted the feat/inspector-agent-proxies branch August 26, 2026 21:02
tejaskash added a commit that referenced this pull request Aug 26, 2026
Rename extractSseEventText to extractA2aEventText; it only handles A2A
artifact/status/task event kinds, so the generic SSE name misled.
Addresses review feedback on #2085.
tejaskash added a commit that referenced this pull request Aug 27, 2026
Rename extractSseEventText to extractA2aEventText; it only handles A2A
artifact/status/task event kinds, so the generic SSE name misled.
Addresses review feedback on #2085.
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Aug 27, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Aug 27, 2026
tejaskash added a commit that referenced this pull request Aug 27, 2026
Rename extractSseEventText to extractA2aEventText; it only handles A2A
artifact/status/task event kinds, so the generic SSE name misled.
Addresses review feedback on #2085.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants