[WIP] feat: add agent inspector into azd cli#8125
Conversation
|
Thank you for your contribution @XiaofuHuang! We will review the pull request and get back to you soon. |
Adds a `--inspector` flag to `azd ai agent invoke` that launches the Agent Inspector SPA in the browser and proxies localhost HTTP/SSE/RPC to the agent running via `azd ai agent run --local`. The SPA is the same one shipped by the VS Code extension built in `--mode azd`; its assets are checked in under `internal/inspector/assets/` and embedded via `go:embed`. Includes table-driven tests for `assertLocalhost` and a server smoke test that binds an ephemeral port and verifies SPA fallback. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
22ae049 to
e95eb9d
Compare
- Drop assertLocalhost and its test; remove dead compile-time check. - Extract validateInspectorFlags; add DefaultInspectorPort constant. - Server.Start signals readiness so browser launches after bind. - sendError uses err.Error() and JSON-RPC -32603; log unhandled methods. - SSE loop uses bufio.Reader.ReadString to avoid per-iteration alloc. - Tests use strconv.Itoa and the ready channel. - Simplify comments throughout. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
- rpc.go: handle the new "inspector/fixRequested" SPA notification by logging "there is an error and user want AI to fix (source=...): ..." to the inspector logger. The standalone host has no Copilot UI, so this turns the SPA's Fix buttons into a usable signal during preview. - Re-embed the rebuilt SPA bundle (azd flavor) carrying the matching frontend changes: Fix buttons now route through this notification, and Events/Tools/Output empty states say "Run the agent" instead of "Run the workflow" under VITE_HOST=azd.
handleFixRequested now writes the "user wants AI to fix" line directly to os.Stderr in addition to the regular logger. The root command redirects log.Default() to io.Discard (no --debug) or a daily file (with --debug), so the existing s.logger.Printf was invisible at the terminal. Other inspector logs stay on the existing path — only this specific user-facing signal is teed to stderr.
- rpc.go handleFixRequested: prefix output with "[inspector] [fix-with-ai] ", drop the "(source=...)" tag, and indent continuation lines so multi-line summaries align under the prefix. Empty summaries fall back to "(no error details provided)". - Re-embed the rebuilt SPA bundle (azd flavor) carrying the matching generateFixPrompt change: the "Fix this failed workflow step: <executorId>." prefix line is gone, leaving only the fields that actually carry data (Failed step / Error Code / Error Message / Traceback).
…Default) Drop the URL-based "/responses" gate in proxyInvoke and the hardcoded logRaw=false in proxyFetchSSE. Both now log unconditionally through s.logger; --debug controls visibility through the existing log.Default() routing (file with --debug, io.Discard without). - proxyInvoke: always log POST body and response (full body for /responses, byte count for others to keep diagnostics readable). - proxyInvoke streaming: pass logRaw=true so SSE chunks are logged for every streaming response, not just /responses. - proxyFetchSSE: pass logRaw=true so SPA-driven SSE channels (e.g. /agentdev/v1/diagnostics that powers the Events tab) are also captured. Previously these were silently dropped even with --debug.
proxyInvoke now logs the full buffered response body for every URL, not just /responses. Symmetry with the streaming SSE path which already logs every chunk regardless of endpoint. --debug still controls visibility through log.Default().
Add an SSESink callback on inspector.Config so the CLI receives the proxied SSE bytes; when the inspector webview chats, the terminal now echoes user input and streams the agent response (or error) using the same printAgentResponse formatter as `azd ai agent invoke --local`. Adapter layer (injectSSEEvents in invoke_inspector.go) synthesises event: lines from the local agentserver's typed data: chunks so the existing readSSEStream parser can be reused unchanged. Also collapse the fix-with-ai stderr line to a single line.
Resolves the per-agent session_id and conversation.id via the existing resolveStoredID helper and pipes them through inspector.Config and the navigateToStep boot payload so the SPA continues whatever conversation the CLI was using instead of minting a fresh UUID per browser mount. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Replace the proxyInvoke pump's split close paths (deferred resp.Body.Close plus a goroutine close-on-cancel) with a single cancel()-driven close, so Body is closed exactly once whether the stream ends normally or the session is torn down mid-read. Add a test that asserts upstream sees its request context cancelled within ~2s of the inspector WebSocket closing. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
|
Hi @@XiaofuHuang. Thank you for your interest in helping to improve the Azure Developer CLI experience and for your contribution. We've noticed that there hasn't been recent engagement on this pull request. If this is still an active work stream, please let us know by pushing some changes or leaving a comment. Otherwise, we'll close this out in 7 days. |
|
Hi @@XiaofuHuang. Thank you for your contribution. Since there hasn't been recent engagement, we're going to close this out. Feel free to respond with a comment containing "/reopen" if you'd like to continue working on these changes. Please be sure to use the command to reopen or remove the "no-recent-activity" label; otherwise, this is likely to be closed again with the next cleanup pass. |
Spec: https://github.com/coreai-microsoft/foundrysdk_specs/pull/169
This pull request introduces the Agent Inspector UI to the Azure AI Agents extension, allowing users to launch a browser-based inspector for local agents without any Python or Node.js runtime dependencies. The main changes add a new
--inspectormode to theazd ai agent invokecommand, which serves a standalone Single Page Application (SPA) built from the VS Code extension and hosts it with an embedded Go HTTP/WebSocket server. This enables local agent inspection and debugging in a user-friendly way.The most important changes are:
Agent Inspector UI integration:
--inspectorflag (with--inspector-port) to theazd ai agent invokecommand. When enabled (and combined with--local), this launches a browser-based inspector UI connected to the local agent, instead of streaming responses to the terminal. Input validation ensures this flag is only used in supported scenarios. (invoke.go,invoke_inspector.go) [1] [2] [3] [4] [5] [6]rpc_handler.pylogic, supporting the required WebSocket JSON-RPC protocol for the UI. (internal/inspector/assets.go,internal/inspector/proxy_fetch.go) [1] [2]internal/inspector/assets/assets/*,internal/inspector/assets/index.html,build-frontend.ps1) [1] [2] [3] [4]Dependency and build system updates:
go.modto add direct dependencies ongithub.com/cli/browser(for browser launching) andgithub.com/gorilla/websocket(for WebSocket support). (go.mod) [1] [2]build-frontend.ps1, comments in code) [1] [2]Testing and validation:
internal/inspector/localhost_test.go)Overall, these changes provide a seamless, cross-platform way to inspect and debug local agents via a modern browser UI, improving developer experience and removing the need for extra runtime dependencies.