feat(agui): AG-UI protocol adapter + generative UI (L1, default-off) — supersedes #387#436
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #436 +/- ##
=======================================
Coverage ? 89.35%
=======================================
Files ? 156
Lines ? 18510
Branches ? 0
=======================================
Hits ? 16539
Misses ? 1971
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
cafaad9 to
9ed8cd5
Compare
a4e93d4 to
94b63a4
Compare
… body awslabs#436 leaked operator triage into the public Approve body — the supervisor wrote the needs_human rationale ('needs_human: true … a human should skim the strip-list and decide …') inline in the ## Verdict, which the frontmatter/notes strips don't catch. This body is posted verbatim for approve/request/comment alike. - supervisor: HARD rule — the public body (Verdict incl.) is about the code only; needs_human reasoning + operator/tooling/'a human should…' language goes ONLY in frontmatter needs_human_reason and/or the (stripped) Notes section. - publish_reviews.sh: scrub_operator backstop drops lines referencing needs_human, --ack, publish guard, publish_reviews.sh, or 'a human should skim/decide/…' from the posted body (belt-and-suspenders for legacy reports).
4c634d4 to
24d3287
Compare
fanhongy
left a comment
There was a problem hiding this comment.
PR #436 Code Review
PR: #436
Reviewed commit: 94b63a48832bc19b3d0a392ca12439a82da43b77
Must Fix
1. CAO_AGUI_ENABLED exposes a stream that never receives lifecycle events
Location: src/cli_agent_orchestrator/plugins/builtin/event_log_publisher.py:84
api.main._agui_enabled() accepts either CAO_AGUI_ENABLED or
CAO_MCP_APPS_ENABLED, but EventLogPublisher._emit() only checks
apps.enabled. The documented quick start uses only CAO_AGUI_ENABLED=true,
so session, terminal, and handoff events are discarded before reaching the
AG-UI bus.
Reproduced on the PR:
agui_route_enabled=True
lifecycle_publisher_enabled=False
Fix: use one shared surface-enablement helper for both the API and publisher,
or make the publisher gate true when either flag is enabled. Add an integration
test that enables only CAO_AGUI_ENABLED, emits a real lifecycle hook, and
observes the corresponding AG-UI frame.
2. The PWA discards the authoritative state channel
Location: cao_pwa/src/components/InstanceTab.tsx:73
The server emits STATE_SNAPSHOT on every connection and STATE_DELTA
after changes, but the reducer has no branch for either event and returns the
existing state. Consequently, sessions and terminals that predate the browser
connection never appear. Switching tabs also remounts the component and loses
all locally reduced state.
Fix: retain a typed dashboard snapshot in reducer state, hydrate it from
data.snapshot, and apply RFC 6902 patches from data.delta with a proven JSON
Patch library. Derive the visible session/terminal maps from that state. Add a
component test that starts from a non-empty snapshot and then applies a delta.
3. Replay has an event-loss window before live subscription
Location: src/cli_agent_orchestrator/api/main.py:919
The generator reads history, builds/yields a fleet snapshot, and only subscribes
to the live bus at line 936. Any event published after history() returns but
before subscribe() registers is absent from both sources and is permanently
lost. This contradicts the documented "resumes without a gap" contract.
Queue overflow has the same silent-gap problem because the connection remains
open and the client has no sequence-gap signal.
Fix: register a live subscription before taking the replay snapshot, then
replay history and drain queued events with event-id deduplication. Add a
monotonic cursor or SSE id: field; on queue overflow, signal/close the stream
so the client is forced through replay. Add a concurrency test that publishes
during the history/live handoff.
4. OpenTelemetry is initialized but no production operation is instrumented
Locations: src/cli_agent_orchestrator/api/main.py:456,
src/cli_agent_orchestrator/telemetry/otel.py:88,
docs/otel-deployment.md:120
The PR installs exporters and defines span helpers, but searches under src/
find only helper definitions. No handoff, assign, send-message, provider, or
workflow path calls invoke_agent_span, execute_tool_span, or chat_span.
No metric instrument is created either. Enabling telemetry therefore exports no
application spans or metrics, despite the changelog and deployment guide saying
those dispatches emit GenAI telemetry.
Fix: instrument the actual orchestration boundaries and propagate
traceparent when constructing plugin events. Create and update the promised
metrics, or narrow the feature/docs to traces only. Add an integration test that
executes one dispatch through a real service seam and asserts an exported span,
instead of testing helper functions in isolation.
5. A clean default development install cannot collect the new tests
Locations: pyproject.toml:58, test/telemetry/conftest.py:12
The OTel SDK is correctly optional, but test/telemetry/conftest.py
unconditionally imports it while the dev dependency group does not install the
otel extra. In a fresh PR worktree, uv run pytest ... failed during
collection with:
ModuleNotFoundError: No module named 'opentelemetry.sdk'
The same tests pass only after uv sync --extra otel.
Fix: include the OTel SDK/exporter in the dev dependency group, or make the
SDK-specific suite skip cleanly when the extra is absent and add a separate
extra-enabled CI job. Keep the existing subprocess test for the base-install
fallback.
Suggested Fixes
6. Token redaction depends on using the cao-server wrapper
Location: src/cli_agent_orchestrator/api/main.py:2943
The access-log filter is installed only in main(). Running the valid ASGI form
uvicorn cli_agent_orchestrator.api.main:app bypasses it and logs the
access_token query parameter. Install the filter during app setup/lifespan,
before requests are accepted, and test the imported-app deployment path.
7. The new devcontainer commands target a nonexistent root JS project
Locations: .devcontainer/devcontainer.json:19,
.devcontainer/test-ci.sh:17
The repository root has no package.json or Bun lockfile, yet both files run
bun install and root-level bun run lint/typecheck/build/test. The optional
E2E path also references nonexistent packages/cao-playwright-utils.
Fix: run the Python commands at the root and run npm commands explicitly in
web/, cao_mcp_apps/, and cao_pwa/, matching the actual workflows.
8. The documented IndexedDB fallback does not exist
Locations: cao_pwa/src/instances.ts:14, cao_pwa/src/App.tsx:13,
docs/pwa.md:199
IndexedDB errors reject directly; App has no rejection handler and remains on
Loading... forever. The troubleshooting guide claims an in-memory fallback.
Fix: implement a process-local storage adapter fallback and catch initial
load failures, or remove the claim and render an actionable storage error.
9. The offline-instance confirmation is not a confirmation
Location: cao_pwa/src/components/InstancePicker.tsx:38
On a failed health probe the UI sets "add anyway?" and immediately persists the
instance and closes the dialog, so the operator cannot answer.
Fix: return after showing the warning and require a second explicit submit,
or provide separate Cancel and Add anyway actions.
Good To Fix
npm auditreports four dev-only advisories, including critical Vitest and
high-severity Vite advisories. Production dependencies are clean
(npm audit --omit=dev). Refresh the lockfile to patched versions.git diff --check origin/main...HEADfails on seven Antigravity fixture files
because of added blank lines at EOF.cao_pwais described as a PWA but has no web app manifest or service worker.
Either add the installability/offline plumbing or call it a standalone web app.- The PR combines AG-UI, telemetry, a provider, broad test-fixture replacement,
devcontainer work, and unrelated terminology edits. Splitting independent
changes would materially reduce regression risk and review cost.
Verification
- GitHub checks: all reported checks pass.
- Targeted backend suite with
[otel]:85 passed. - PWA unit/component suite:
24 passed. - Fresh default backend environment: test collection fails without
[otel]. - PWA production dependency audit: no vulnerabilities.
24d3287 to
8d10149
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces an additive, default-off AG-UI surface (including generative UI production), along with supporting infrastructure for safety, testing, observability (optional OpenTelemetry), and a standalone dashboard PWA that consumes the AG-UI stream.
Changes:
- Add AG-UI-related safety/ops hardening (log redaction for query-string bearer tokens, default-off regression tests, emit-ui coverage).
- Add optional OpenTelemetry “GenAI semconv” instrumentation with a strict opt-in gate and “no-extra” no-op fallback.
- Add a standalone
cao_pwa/dashboard plus examples and a credentials-freemock_cliprovider to enable deterministic CI paths.
Reviewed changes
Copilot reviewed 126 out of 135 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| test/utils/test_log_redaction.py | Adds tests asserting query-token redaction for access logs. |
| test/test_constants.py | Updates CORS origin defaults test for the PWA dev port. |
| test/telemetry/test_spans.py | Verifies GenAI span helper naming/attributes. |
| test/telemetry/test_otel_init.py | Pins telemetry init/shutdown opt-in behavior and degrade paths. |
| test/telemetry/test_optional_extra.py | Ensures telemetry degrades cleanly when OTel isn’t installed. |
| test/telemetry/test_context_propagation.py | Tests W3C trace-context inject/extract helpers. |
| test/telemetry/conftest.py | Provides shared in-memory exporter and tracer provider fixture. |
| test/telemetry/init.py | Declares telemetry test package. |
| test/services/test_workflow_spec_service.py | Updates workflow version terminology in docstring. |
| test/services/test_workflow_service.py | Updates workflow version terminology in docstring. |
| test/services/test_step_output_store.py | Updates workflow version terminology in docstring. |
| test/services/test_sse_bus.py | Adds edge-case coverage and reset-bus singleton test. |
| test/services/test_settings_service.py | Resets settings-service module caches for deterministic tests. |
| test/services/test_event_log_service.py | Adds edge-case coverage and reset-event-log singleton test. |
| test/scripts/init.py | Declares scripts test package (empty marker). |
| test/providers/test_native_status_shared.py | Trims outdated provider-scope text in docstring. |
| test/providers/test_mock_cli_unit.py | Adds unit tests for the new mock_cli provider and fixture binary. |
| test/providers/test_mock_cli_coverage.py | Covers async initialize branches + cleanup for mock_cli. |
| test/providers/fixtures/bin/mock_cli | Adds the deterministic bash “agent” used by mock_cli provider tests. |
| test/providers/fixtures/antigravity_cli_tool_call.txt | Adds fixture capture for Antigravity tool-call output. |
| test/providers/fixtures/antigravity_cli_response.txt | Adds fixture capture for Antigravity completed response output. |
| test/providers/fixtures/antigravity_cli_processing.txt | Adds fixture capture for Antigravity processing output. |
| test/providers/fixtures/antigravity_cli_print_mode.txt | Adds fixture capture for Antigravity print-mode output. |
| test/providers/fixtures/antigravity_cli_permission.txt | Adds fixture capture for Antigravity permission prompt state. |
| test/providers/fixtures/antigravity_cli_interactive_clean.txt | Adds fixture capture for Antigravity interactive-mode states. |
| test/providers/fixtures/antigravity_cli_idle.txt | Adds fixture capture for Antigravity idle/prompt output. |
| test/providers/fixtures/antigravity_cli_error.txt | Adds fixture capture for Antigravity error/interrupt output. |
| test/models/test_workflow.py | Updates workflow terminology and clarifies docstrings. |
| test/mcp_server/test_workflow_tools.py | Updates workflow version terminology in docstring. |
| test/mcp_server/test_workflow_return.py | Updates workflow version terminology in docstring. |
| test/mcp_server/test_handoff_equivalence.py | Updates workflow version terminology in docstring. |
| test/mcp_server/test_emit_ui_coverage.py | Adds MCP tool coverage for emit_ui behavior (200/400/404). |
| test/fixtures/init.py | Declares managed-subprocess fixture package and intent. |
| test/examples/test_example_profiles.py | Validates example profiles reference valid ProviderType values. |
| test/examples/init.py | Declares examples test package (empty marker). |
| test/e2e/test_headless_ci.py | Adds an e2e test for the headless CI runner example script. |
| test/e2e/conftest.py | Switches e2e server requirement to managed subprocess fixture + adds Gemini skip fixture. |
| test/conftest.py | Adds PATH wiring for mock_cli fixture + exposes shared auth fixtures/plugins. |
| test/clients/test_workflow_index_migration.py | Updates workflow version terminology in docstring. |
| test/cli/commands/test_workflow.py | Updates workflow version terminology in docstring. |
| test/api/test_workflow_runs.py | Updates workflow version terminology in docstring. |
| test/api/test_workflow_endpoints.py | Updates workflow version terminology in docstring + clarifies regression note. |
| test/api/test_default_off_listeners.py | Adds default-off regression tests for disabled surfaces. |
| test/api/test_agui_enablement.py | Pins AG-UI enablement contract across env flags. |
| test/api/test_agui_emit_ui.py | Adds end-to-end producer endpoint tests for allow-list + size bounds + 404 when off. |
| test/api/test_agui_auth_hardening.py | Ensures token-parse failures map to 401, not 500. |
| src/cli_agent_orchestrator/utils/logging.py | Adds access-log query-token redaction + stderr WARNING handler. |
| src/cli_agent_orchestrator/telemetry/spans.py | Adds GenAI semantic-convention span helper context managers. |
| src/cli_agent_orchestrator/telemetry/semconv.py | Defines frozen GenAI semconv keys + CAO extensions. |
| src/cli_agent_orchestrator/telemetry/otel.py | Adds opt-in OTel SDK init/shutdown with OTLP exporters and missing-SDK degrade behavior. |
| src/cli_agent_orchestrator/telemetry/context.py | Adds W3C trace-context inject/extract helpers. |
| src/cli_agent_orchestrator/telemetry/init.py | Adds optional-extra import strategy and no-op fallback API surface. |
| src/cli_agent_orchestrator/skills/workflow-author/SKILL.md | Updates “Bolt” phrasing to “version” in skill text. |
| src/cli_agent_orchestrator/skills/agui-author/SKILL.md | Adds a skill documenting safe generative UI authoring via emit_ui. |
| src/cli_agent_orchestrator/services/workflow_spec_service.py | Updates workflow version terminology and clarifies reserved/execution references. |
| src/cli_agent_orchestrator/services/workflow_service.py | Updates workflow version terminology in docstring. |
| src/cli_agent_orchestrator/services/step_output_store.py | Updates workflow version terminology in docstring. |
| src/cli_agent_orchestrator/services/status_monitor.py | Tightens typing for pyte screen tracking and casts provider status returns. |
| src/cli_agent_orchestrator/services/sse_bus.py | Adds SSEBus alias + reset helper for tests. |
| src/cli_agent_orchestrator/services/event_log_service.py | Adds reset helper for tests. |
| src/cli_agent_orchestrator/providers/mock_cli.py | Adds deterministic provider wrapping the fixture mock_cli binary. |
| src/cli_agent_orchestrator/providers/manager.py | Registers mock_cli provider in provider factory. |
| src/cli_agent_orchestrator/plugins/events.py | Extends event DTOs with optional traceparent for telemetry propagation. |
| src/cli_agent_orchestrator/plugins/builtin/event_log_publisher.py | Adds backwards-compatible alias for plugin class name. |
| src/cli_agent_orchestrator/models/workflow.py | Updates workflow version terminology and clarifies “grammar vs engine” boundary. |
| src/cli_agent_orchestrator/models/workflow_runtime.py | Updates workflow version terminology across runtime DTOs. |
| src/cli_agent_orchestrator/models/provider.py | Adds ProviderType for mock_cli. |
| src/cli_agent_orchestrator/mcp_server/server.py | Adds emit_ui MCP tool that POSTs to /agui/v1/emit_ui. |
| src/cli_agent_orchestrator/ext_apps/static/topology.js | Simplifies comments; keeps topology widget minimal. |
| src/cli_agent_orchestrator/ext_apps/init.py | Updates comments around topology widget export list. |
| src/cli_agent_orchestrator/constants.py | Adds OTEL service name constant and extends CORS defaults for PWA port. |
| src/cli_agent_orchestrator/cli/commands/workflow.py | Updates workflow version terminology in docstring. |
| skills/workflow-author/SKILL.md | Syncs “Bolt” phrasing to “version” in repo-root skill copy. |
| skills/plugin.json | Adds skills plugin manifest for shipped skills. |
| skills/agui-author/SKILL.md | Adds repo-root copy of the agui-author skill content. |
| scripts/sync_skills.py | Adds agui-author to shipped skills allowlist. |
| pyproject.toml | Adds [otel] optional extra deps and adds authlib to dev deps for JWT fixtures. |
| examples/headless-ci/run.sh | Adds headless CI runner script that maps terminal states to exit codes. |
| examples/headless-ci/README.md | Documents the headless CI example and usage in CI environments. |
| examples/headless-ci/ci_developer.md | Adds a CI-focused agent profile for non-interactive runs. |
| examples/cross-provider/README.md | Updates cross-provider README to include Antigravity profile entry. |
| examples/agui-dashboard/showcase.sh | Adds live-path AG-UI generative UI showcase script (curl-driven). |
| examples/agui-dashboard/run.sh | Adds demo runner to start server + optionally launch demo fleet + run showcase. |
| examples/agui-dashboard/README.md | Documents the AG-UI dashboard demo and safety/refusal behaviors. |
| examples/agui-dashboard/fleet_worker.md | Adds demo agent profile for optional mock fleet. |
| docs/otel-deployment.md | Adds OTel collector deployment guidance and backend recipes. |
| docs/mock-cli-provider.md | Documents motivation/design/CI strategy for the mock_cli provider. |
| CHANGELOG.md | Adds changelog entries for AG-UI stream, generative UI, PWA, telemetry, and mock provider. |
| cao_pwa/vite.config.ts | Adds Vite config for standalone PWA (dev port 5174) with vitest config. |
| cao_pwa/tsconfig.json | Adds strict TS config for PWA package. |
| cao_pwa/src/types.ts | Defines shared PWA types (instances, events, summaries). |
| cao_pwa/src/test/setup.ts | Sets up vitest environment with fake-indexeddb and dialog stubs. |
| cao_pwa/src/test/instances.test.ts | Adds IndexedDB CRUD tests for instance storage. |
| cao_pwa/src/test/InstancePicker.test.tsx | Pins accessible instance picker structure and interactions. |
| cao_pwa/src/test/GenerativeUI.test.tsx | Tests allow-listed rendering + refusal placeholder behavior. |
| cao_pwa/src/test/api.test.ts | Tests connectAGUI URL construction, dispatch, reconnection behavior, and health ping. |
| cao_pwa/src/main.tsx | Adds PWA entry point mounting the React app. |
| cao_pwa/src/instances.ts | Implements IndexedDB persistence for CAO instance list. |
| cao_pwa/src/components/InstanceTab.tsx | Implements per-instance stream view + summary panels + generative UI feed. |
| cao_pwa/src/components/InstancePicker.tsx | Implements instance selection/add/remove UI with basic reachability check. |
| cao_pwa/src/components/GenerativeUI.tsx | Adds safe client-side renderer with explicit allow-list and inert fallback. |
| cao_pwa/src/App.tsx | Composes instance picker + active tab and performs initial instance load. |
| cao_pwa/src/api.ts | Implements EventSource connection and reconnect logic for AG-UI stream. |
| cao_pwa/playwright.live.config.ts | Adds live-path Playwright config for real-server e2e runs. |
| cao_pwa/playwright.config.ts | Adds deterministic replay Playwright config for recording artifacts. |
| cao_pwa/package.json | Adds PWA package manifest, scripts, and dev deps (vitest/playwright/vite). |
| cao_pwa/index.html | Adds PWA HTML entrypoint. |
| cao_pwa/e2e/generative-ui.spec.ts | Adds deterministic replay e2e spec validating rendering + refusal. |
| cao_pwa/.gitignore | Adds PWA-specific ignores for node/build/test artifacts. |
| .github/workflows/cao-pwa-generative-ui.yml | Adds CI workflow to build/test/record PWA proof artifacts (replay + live). |
| .devcontainer/test-ci.sh | Adds a devcontainer script to run CI-equivalent steps locally. |
| .devcontainer/Dockerfile | Adds devcontainer image aligned with Playwright + installs tmux/uv/bun. |
| .devcontainer/devcontainer.json | Adds devcontainer configuration and post-create commands/port forwards. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
8d10149 to
0fda48f
Compare
|
Thanks @fanhongy and @Copilot — all findings addressed. Phase-A was force-pushed and all checks are green. Summary: Scope (Good-To-Fix #4, "split the PR"): narrowed this PR to the L1 adapter. The standalone dashboard PWA ( Must-Fix
Suggested
Good-To-Fix
Copilot inline
|
0fda48f to
63caf72
Compare
Add targeted unit tests for the 16 lines codecov reported as missing: - api/main.py (13): the /agui/v1/stream failure-isolation branches — token HTTPException re-raise + generic->401, _fleet_snapshot terminal-listing error, ?since= history-replay error, connect STATE_SNAPSHOT and per-event STATE_DELTA error handlers, the replay/live dedup continue, and emit_ui's oversized + non-JSON-serializable props guards. - providers/manager.py (1): the credentials-free mock_cli provider branch. - services/status_monitor.py (1): both _detect_screen cast paths (rendered-screen success + no-provider fallback). - telemetry/__init__.py (1): a non-opentelemetry ImportError is re-raised (a real bug surfaces loudly) rather than masked as a no-op. All fakes drain finite sequences so the SSE generator always terminates (no hanging tests).
d25a105 to
e93ebf9
Compare
|
thanks for the commits. Clean fix, few gaps remaining: 1. The replacement viewer does not replay events missed during reconnectNew regression introduced by the remediation. Locations: examples/agui-eventsource-viewer/index.html:407-426 , src/cli_agent_orchestrator/api/main.py:830-847 , The viewer always opens the fixed URL /agui/v1/stream and relies on native EventSource automatic reconnect. Native reconnect sends the most A focused endpoint reproduction sent Last-Event-ID: missed and observed: This contradicts the demo's advertised "SSE reconnect ... with no gap" behavior and the resilience guidance in docs/agui.md:80-87 . Fix: Prefer an ID-based server cursor. Accept Last-Event-ID , add an event-log lookup that returns records after that ID, and replay them before 2. Queue overflow still creates the silent gap from the original findingUnresolved portion of previous must-fix finding 3. Locations: src/cli_agent_orchestrator/services/sse_bus.py:52-56 , src/cli_agent_orchestrator/services/sse_bus.py:103-113 , Registering the queue before history replay correctly closes the handoff race. However, when that bounded queue fills, _deliver still drops the A focused overflow reproduction observed: This still violates the documented no-gap contract in docs/agui.md:82-87 and docs/agui.md:148-149 . Fix: Mark the subscriber overflowed and terminate its stream, or deliver a gap sentinel that makes the endpoint close. The client's reconnect must Suggested Fix3. The new viewer cannot connect to an auth-enabled server as shippedLocation: examples/agui-eventsource-viewer/index.html:407-414 , examples/agui-eventsource-viewer/README.md:64-72 The server requires ?access_token= in auth-enabled mode, but the viewer only accepts a base URL and appends /agui/v1/stream to it. The Fix: Add an optional token input, build the stream URL with URL and searchParams , and keep the token in memory only. Cover URL construction Previous other findings:All addressed. Verification• Current GitHub checks: passing. |
|
@fanhongy acknowledged and thanks for the multi-turn reviews - working on those fixes now |
e93ebf9 to
786447c
Compare
|
Thanks for the review, @fanhongy. Pushed a follow-up (force-with-lease onto the same single Verified commit, finding → fix → proving test
Docs ( Local verification: targeted AG-UI + services suites GREEN (112 tests), |
b99786e to
79241de
Compare
|
CI note: the red Unit Tests / CAO MCP Apps jobs on this PR are inherited from a pre-existing breakage on I've opened a dedicated fix: #452 (test-only; isolates the settle-check in those tests). Once #452 lands on |
79241de to
5b9eeb5
Compare
5b9eeb5 to
6e8bb6d
Compare
|
✅ Resolved (re: this note). The Full CI is green on the rebased head: Unit Tests (3.10/3.11/3.12), Code Quality, CAO MCP Apps + E2E, AG-UI demo (shift-left recording), Web UI Build, and Security Scan all pass. This PR is back to purely the AG-UI L1 feature + the F1/F2/F3 review remediations. |
✅ Done — rebased onto latest
|
6e8bb6d to
eaf1ef8
Compare
|
Thanks for addressing the reconnect behavior. The stream now closes correctly on overflow, which fixes the original silent-open-gap problem. With branch with result: I can see this is covered with unit test, but might worth looking at: which you have: This test means: Let's say if you a queue with capacity 3, publishing e0, e1, e2, e3 produces: After e0: [e0] When e3 arrives, the queue is full, and the first item e0 will be removed then inserts the sentinel. Leave the queue like: [e1, e2, OVERFLOW_SENTINEL] e0 is now missing. The assertion only asks whether at least one event arrived. It does not ask whether all expected events arrived. This assertion also passes:
and it only verifies that What Is Missing The test needs to verify both properties:
Long-in-short: the existing test correctly proves that overflow triggers closure, but it does not prove the no-event-loss recovery. It would also be helpful to strengthen Thank you! |
…hase-A (reconciled) Closes out Phase-A of awslabs#387 as a single, net-new commit rebased onto the latest upstream `main`. This squashes the reconciled AG-UI core work (the "best of both implementations" adjudicated in #19) into one authored change so it can be reviewed cleanly before it goes upstream. Additive and opt-in: every new surface is default-off (gated by env/config) or a new module that is not imported unless enabled, so the existing localhost dashboard, MCP servers, and API stay byte-identical when the flags are unset. Protocols & UI - AG-UI streaming: GET /agui/v1/stream maps CAO's normalized event vocabulary to AG-UI typed events, with a STATE_SNAPSHOT on connect, an RFC-6902 STATE_DELTA shared-state channel, and ?since= replay, behind CAO_AGUI_ENABLED + scope auth. Metadata-only by construction (message bodies never carried). - Generative UI: agents author UI via a frozen, server-validated allow-list of named components (approval/choice/diff/progress/metrics/agent cards) with JSON props — no HTML/script/eval; off-list components are refused at the adapter, the renderer, and the replay artifact. - Standalone dashboard PWA (cao_pwa/) that consumes the stream from any browser and resumes via ?since=; a browser-openable deterministic replay artifact. - Opt-in OpenTelemetry GenAI instrumentation ([otel] extra) and a credentials-free mock_cli provider for CI. Reconciliation (best-of-both) - Renderer-true demo vocabulary (diff_summary title, progress.value on the 0.0-1.0 scale) pinned by live-spec assertions so drift fails the spec instead of hiding behind HTTP 200. - OTel packaging under [otel] with an actionable degrade hint; find_spec-based subprocess guard. - agui-author skill registered in SHIPPED_SKILLS and guarded by the packaging-parity suite. Shift-left testing - Backend unit/integration: AG-UI stream mapping, emit_ui validation/refusal, enablement gating, and auth hardening (test/api/test_agui_*, test/services/test_agui_stream_mapping.py, test/ext_apps/*). - Frontend: cao_pwa vitest incl. generative-UI + safety-refusal cases; tsc clean; vite build within the bundle-size budget. - Live path: Playwright live spec (cao_pwa/playwright.live.config.ts) exercises the six components with renderer-true assertions, iframe refusal, the server-restart ?since= replay, and reload persistence; showcase.sh gates on the six GENERATIVE_UI frames arriving on the live stream. Video verification proof - Shift-left demo recording: examples/agui-eventsource-viewer/tools/record-demo.mjs drives the live viewer, asserts the six generative-UI components render and the off-list component is refused, and exports docs/media/agui-eventsource-viewer-demo.gif. It runs in CI as the "AG-UI demo (shift-left recording)" job; the GIF is rendered in the PR description, the examples READMEs, and docs/agui.md. Dependency-free viewer + full patch coverage - examples/agui-eventsource-viewer/: a single zero-dependency HTML file (no npm, no framework, no build) that consumes /agui/v1/stream, hydrates a fleet projection from STATE_SNAPSHOT + RFC-6902 STATE_DELTA, and renders the six allow-listed generative-UI components from JSON props with DOM APIs only (off-list components become inert placeholders). Replaces the removed PWA as the "stock browser client renders the stream" proof. - Patch coverage brought to 100%: tests for the AG-UI stream/emit_ui edge branches (auth re-raise, failure-isolation handlers, replay dedup, oversized/ non-serializable props), the mock_cli provider branch, status_monitor screen-detection, the telemetry non-otel-ImportError re-raise, and the OTel lifespan init/shutdown failure handlers. Review remediation (fanhongy 2026-07-16) — each fix proven RED-first by a new test - F2 queue-overflow silent gap (must-fix): a full bounded SSE queue no longer drops events on an open connection. services/sse_bus.py marks the subscriber overflowed and enqueues an OVERFLOW_SENTINEL; the AG-UI stream registers with overflow_close=True and its drain closes the stream so the client reconnects and backfills exactly once. The /events MCP-Apps path keeps legacy drop-on-slow. Proven by test/services/test_sse_bus_overflow.py and test/api/test_agui_stream_overflow.py. - F1 reconnect event loss (must-fix, coupled to F2): GET /agui/v1/stream now accepts the native EventSource Last-Event-ID header and replays event-log records after that id (EventLog.after_id) before the live drain; ?since= keeps precedence. Proven by test/api/test_agui_stream_reconnect.py and the EventLog.after_id unit tests; end-to-end no-gap reconnect added to the demo recorder (proveReconnectNoGap). - F3 viewer token (suggested): examples/agui-eventsource-viewer/index.html gains an Access-token field and builds the stream URL via URL/searchParams (in-memory only, redacted, seeded from the page URL then scrubbed); the README "edit the source" note is dropped. Proven by the recorder's URL-construction assertion. - Docs (docs/agui.md + example READMEs) reconciled to the Last-Event-ID reconnect and overflow→reconnect→backfill contract. Implements the AG-UI L1 adapter proposed in awslabs#386. Co-authored-by: Kiro Agent <244629292+kiro-agent@users.noreply.github.com>
eaf1ef8 to
769dce4
Compare
|
@fanhongy — great catch, and thank you for the precise repro. You're right: closing the stream on overflow fixed the silent-open-gap, but the recovery still lost an event, and your reproduction pinned exactly why. Root cause. The overflow branch made room for the sentinel by evicting the oldest buffered event: sub.queue.get_nowait() # drops e0 (front)
sub.queue.put_nowait(OVERFLOW_SENTINEL)With a cap-3 queue fed Fix ( buffered = []
while not sub.queue.empty():
buffered.append(sub.queue.get_nowait())
for item in buffered[:-1]: # keep the contiguous prefix; drop newest
sub.queue.put_nowait(item)
sub.queue.put_nowait(OVERFLOW_SENTINEL)Now the client delivers Your exact repro now prints: Strengthened
All checks are green on the latest push (Unit Tests 3.10/3.11/3.12, Code Quality, AG-UI demo, MCP Apps + E2E, Web UI Build, Trivy/Security). Thanks again for the thorough review! |
There was a problem hiding this comment.
This isn't good - figuring out how these leaked in here and removing
fanhongy
left a comment
There was a problem hiding this comment.
wow. This is a very qquick fix. Thanks for responding this fast! LGTM.
… guard (#456) Provider status-detection fixtures are captured from live CLI TUIs whose login banners print the authenticated account email. Two such addresses were committed: - Delete 9 orphaned `test/providers/fixtures/antigravity_cli_*.txt` fixtures (shipped via #436) that captured a maintainer's Google login banner. They are referenced by NO test — the antigravity suite uses the separate `agy_*.txt` fixtures — so deleting them removes the PII with zero test impact. - Redact a contributor's account email in `test/providers/fixtures/claude_code_new_tui_completed_raw.txt` (used by `test_claude_code_unit.py`) to `user@example.com`. The email sits in the header banner; the test asserts only COMPLETED status and the bottom-box pattern, so detection is unaffected. - Add `test/test_fixtures_no_personal_pii.py`: a fail-closed guard that scans every `test/**/fixtures/**` file for personal-provider email addresses (gmail, icloud, …) and fails CI, so a live-capture PII leak cannot recur. Co-authored-by: Kiro Agent <244629292+kiro-agent@users.noreply.github.com>
AG-UI protocol adapter + generative UI (Phase-A)
Implements the AG-UI L1 adapter proposed in #386: a thin, default-off surface that maps CAO's normalized fleet events onto AG-UI typed SSE events, plus a generative-UI producer path. Supersedes #387.
Every new surface is additive and default-off — with the flags unset, the existing localhost dashboard, MCP servers, and HTTP API are byte-identical.
What ships here vs. follow-ups (issue #386)
/agui/v1/stream, typed events,STATE_SNAPSHOT/STATE_DELTA,?since=replayemit_ui, server-validated frozen allow-listexecute_toolspan +cao.orchestration.dispatchescounter +traceparent(opt-in)mock_clicredentials-free provider (deterministic CI)mock_cliproviderDemo recordings
What is shipped now — dependency-free EventSource viewer (Path A). A stock
browser
EventSourceclient — one HTML file, no npm/framework/build — rendersthis PR's
/agui/v1/stream: the fleet projection (STATE_SNAPSHOT+RFC-6902
STATE_DELTA) and all six allow-listed generative-UI components,driven live by
examples/agui-dashboard/showcase.sh. Off-list components renderan inert placeholder (never executed). Source:
examples/agui-eventsource-viewer/.This GIF is generated by the build, not hand-recorded — the
AG-UI demo (shift-left recording)CI job runsexamples/agui-eventsource-viewer/tools/record-demo.mjs, which drives the live viewer, asserts each component renders and the off-list component is refused (CI fails on drift), and exports the GIF.Coming in a future phase — stock AG-UI client interop (Path B). A minimal
React +
@ag-ui/client(CopilotKit-style) app renders the same stream through athin run-endpoint shim that bridges AG-UI's per-run
RunAgentInputPOST toCAO's one-way ambient fleet stream (and rewrites CAO's named SSE frames into
the stock AG-UI wire format). This is the in-repo seed of the
integrations/cli-agent-orchestratorpackage proposed in #386 and ships in afollow-up PR.
Preview only — the Path B app (React +
@ag-ui/client+ run-endpoint shim) ships in theintegrations/cli-agent-orchestratorfollow-up (#386); this GIF is a walkthrough of that work-in-progress.Scope
GET /agui/v1/streammaps CAO's normalized events to AG-UI typed events (STATE_SNAPSHOTon connect, RFC-6902STATE_DELTA,?since=replay), behindCAO_AGUI_ENABLED+ scope auth. The generator registers its live subscription before replaying history and dedupes the overlap by event id (with an SSEid:cursor), so a?since=reconnect resumes with neither a gap nor a duplicate. Metadata-only: message bodies never travel on the wire.emit_ui/POST /agui/v1/emit_ui); off-list components and oversized/non-serializable props are refused server-side (no HTML/script/eval).[otel]extra) — the inter-agent dispatch seam emits a GenAIexecute_toolspan and acao.orchestration.dispatchescounter, and propagates W3Ctraceparentinto plugin events; base install degrades to no-ops.mock_cliprovider for deterministic CI.Testing
STATE_DELTA),emit_uivalidation/refusal, enablement gating (route and publisher share one helper), auth hardening, and telemetry instrumentation (test/api/test_agui_*,test/services/test_agui_stream_mapping.py,test/telemetry/*). Full non-e2e suite green;black/isort/mypyclean.examples/agui-dashboard/showcase.shgates on the sixGENERATIVE_UIframes arriving on the live SSE stream (doubles as a deployment smoke test; non-zero exit on any miss).Live evidence (Option 1 — the L1 wire, credentials-free)
examples/agui-dashboard/run.sh+showcase.shagainst a livecao-server(CAO_AGUI_ENABLED=1) — no tokens, no tmux:live showcase transcript
Reproduce:
Implements the AG-UI L1 adapter proposed in #386.