Skip to content

feat(a2ui): unified in-band action handlers — ag-ui toolkit slice (OSS-165)#135

Closed
contextablemark wants to merge 681 commits into
mainfrom
mark/oss-165-a2ui-inband-v2
Closed

feat(a2ui): unified in-band action handlers — ag-ui toolkit slice (OSS-165)#135
contextablemark wants to merge 681 commits into
mainfrom
mark/oss-165-a2ui-inband-v2

Conversation

@contextablemark

Copy link
Copy Markdown
Member

What

Ag-ui–side slice of unified in-band A2UI action handlers (OSS-165 v2). Lets an agent ship a local, no-round-trip interaction by authoring a native action.functionCall referencing a small agui.* data-write vocabulary, delivered in-band in the component JSON (one path for static + dynamic; no side-channel).

Renderer-side registration of the agui.* functions is the CopilotKit handoff (separate repo) — this PR is the framework-agnostic ag-ui layer.

Commits

  • feat(a2ui-toolkit): setValue / toggleValue authoring builders (emit action.functionCall, centralise the agui.* name); validateA2UIComponents now accepts action.functionCall — doesn't mis-flag a write-target path as an unresolved binding, still validates nested {path} read-bindings in arg values, and fails loud (invalid_function_call) on an unknown agui.* fn / missing required arg; generation guidance teaches the local-swap shape.
  • test(a2ui-middleware): locks the forward (LLM-side) action inbound contract (a2uiAction.userAction → synthetic log_a2ui_event + human-readable result + render_a2ui available).

Verification

  • @ag-ui/a2ui-toolkit: 111 tests, typecheck + build clean.
  • @ag-ui/a2ui-middleware: 100 tests (incl. the new forward-contract test) — no downstream breakage.
  • Real @a2ui/web_core (headless): the prototyped agui.* functions execute against a real surface — setValue (literal + path-bound copy), toggleValue (boolean + List show/hide), reactive notify; and the shipped builder's output executes end-to-end.
  • Real LLMs: OpenAI (gpt-4o) and Gemini (2.5-flash) both author correct agui.* local swaps under the new guidance; validator accepts/rejects correctly; web_core executes them.

Scope / follow-ups

  • Design (supersedes prior): Notion — "A2UI Action Handlers — Unified In-Band Design (v2)".
  • Handoff (CopilotKit repo): register agui.setValue/agui.toggleValue in the renderer catalog (shared, framework-agnostic module → React first, Angular/Vue fast-follow), Python helpers, #4821 doc fix.
  • Forward-path formalization (naming alignment + v1.0 actionResponse/actionId) tracked separately as PNI-106.

Related: OSS-165 · PNI-106 · GitHub CopilotKit#4821

🤖 Generated with Claude Code

ranst91 and others added 30 commits June 23, 2026 15:51
…ands-ts-empty-tool-result

fix(aws-strands): send non-empty tool result to model for empty content
…sive-murdock-59e61e

fix(aws-strands): drain stranded tool calls before RUN_FINISHED on halt
…on-bump-0.3.0

fix(dart): sync agUiVersion constant to 0.3.0
…nds-a2ui-fixed-schema-demo

chore(strands): add a2ui_fixed_schema demo to Python + TS backends
… package

The published package only needs lib/, example/, and docs. Without a
.pubignore, `dart pub publish` ships the entire test/ tree — including a
committed 10 MB compiled-kernel artifact (test/client/config_test.dill) and a
disabled test (test/sse/sse_client_test.dart.skip).

Excluding test/, *.dill and *.skip shrinks the published archive from ~3 MB to
~111 KB with no effect on the library API or examples. (0.1.0 unintentionally
shipped test/ plus large committed artifacts; this keeps 0.3.0+ lean.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tional-run-agent-input-fields

docs: clarify client-provided run tools
New AG-UI features (state sync, multimodal, reasoning) require recent
Agno releases. v2.6.12 added STATE_SNAPSHOT/STATE_DELTA events, and
v2.6.19 includes fixes for multimodal inputs and reasoning event ordering.
…no-extended-features

feat(agno): add extended AG-UI features
…dojo-generated-files

chore(dojo): regenerate files manifest
…dojo-generated-files

fix: fixing issue with incorrect dependencies for agno integration
Integration tests: tool-call arguments are serialized to a string with
WriteIndented, which embeds Environment.NewLine *inside* the string value,
so the escaped newline was platform-dependent ("\r\n" on the Windows machine
the baselines were captured on, "\n" on Linux CI). Verify normalizes file
line endings but not newlines escaped inside string values. Add a global
Verify scrubber that normalizes embedded "\r\n" -> "\n" and rewrite the 11
affected baselines to LF so the snapshots are portable across OSes.

Cross-language: the vitest suites import the @ag-ui/* workspace packages by
their built entry points, but the job only ran `pnpm install`. Build
core/encoder/proto/client (and install protoc, needed by the proto build)
before running the tests.

Dojo e2e: AGUIDojoServer used <TargetFrameworks> (plural), which marks the
project as multi-targeting even with a single value, so `dotnet run` failed
with "specify which framework using --framework". Use singular
<TargetFramework>.

Also make unit-dotnet-sdk.yml zizmor-clean: reference the trusted
github.event_name / github.repository via the built-in $GITHUB_EVENT_NAME /
$GITHUB_REPOSITORY env vars instead of template expansion in a run block, and
add a workflow-level concurrency group.
_detect_edited_human_message is a @staticmethod but referenced
self._normalized_content, raising NameError at runtime and failing
the edited-message unit tests. Call the sibling staticmethod through
the class instead.
SpanCapture's ActivityListener is process-global and listens to the shared
AG-UI/MEAI activity sources, so a telemetry test running in parallel (xUnit
parallelizes across classes; RunTelemetryIntegrationTest emits agui.run on the
same server source) leaked its spans into the capture. Assert.Single(agui.run)
then saw 3. Every span of a scenario shares the in-process trace started by
Root(), so record only spans whose TraceId belongs to an owned root. Makes the
nesting/correlation assertions deterministic under parallel execution.
…ream-edited-message-detection

fix(langgraph): detect same-id content edits in prepare_stream
enginerd-kr and others added 25 commits July 15, 2026 19:24
…ate-error-messages

# Conflicts:
#	integrations/claude-agent-sdk/python/ag_ui_claude_sdk/adapter.py
…ithub-actions

chore(deps): update ruby/setup-ruby action to v1.318.0
…-activity-in-messages-snapshot

fix(client): let MESSAGES_SNAPSHOT replace activity messages it carries
…5-duplicate-error-messages

fix(claude-agent-sdk): dedup errored-turn assistant messages, surface RunErrorEvent (ag-ui-protocol#2145)
…bump-ag-ui-protocol-pin

chore(adk-middleware): bump ag-ui-protocol minimum to >=0.1.18
…oval and interrupt responses

Previously a caller-supplied Resume (via RawRepresentationFactory) dropped
approval responses (the approval block was gated on `input.Resume is null`)
but interrupt responses were still appended unconditionally. That asymmetry
was dormant until Resume forwarding was added in this PR, which is the only
path that populates input.Resume before the translation blocks run.

Gate both translations on a single callerSuppliedResume flag so a caller who
hand-builds Resume owns it entirely, keeping the two resume paths symmetric.
Since the dropped approval/interrupt responses were already stripped from the
outgoing messages, emit an ActivityEvent so the drop is observable instead of
silent. Adds a mirror test for the interrupt precedence path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…otnet-context

fix(dotnet): forward Context and ForwardedProperties from RawRepresentationFactory input (ag-ui-protocol#2151)
fix(dotnet): surface run errors as error content
… Vault

Replace the SignPath / Azure Trusted Signing provider seam with a single
Azure Key Vault path: sign the packed *.nupkg with the DigiCert code-signing
certificate (non-exportable, RSA-HSM) in cpk-signing-kv, using
NuGetKeyVaultSignTool + GitHub OIDC (no long-lived secret). Vault URL and
cert name are read from `nuget`-environment secrets; the seam stays inert
until SIGNING_PROVIDER=keyvault.

- publish-release.yml: preflight guard, azure/login (OIDC), install + run
  NuGetKeyVaultSignTool per-nupkg, verify gate; drop the now-unused
  actions: read permission
- signing.md: rewrite for the Key Vault approach + provisioning checklist
- .gitignore: ignore the stray actionlint dev binary

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…40-sign-net-nuget-packages

ci(dotnet): sign NuGet packages with DigiCert cert in Azure Key Vault (OSS-440)
Bumps the shared VersionPrefix 0.0.3 -> 0.0.4 so the AGUI.* packages
re-release as new (immutable) versions carrying the DigiCert author
signature — nuget.org versions are immutable, so the existing unsigned
0.0.3 cannot be re-signed in place. Merging to main triggers the stable
publish-dotnet release, which now author-signs via Azure Key Vault
(SIGNING_PROVIDER=keyvault).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-dotnet-sdk-0.0.4

chore(dotnet): bump AGUI.* to 0.0.4 for first signed release
…1862-mcp-http-headers

fix(mcp-apps-middleware): forward auth headers to HTTP and SSE transports (ag-ui-protocol#1862)
…ithub-actions

chore(deps): update github actions
…rlin/make-go-dojo-default-go-example

Replace Go example server with Dojo implementation
…oning-text-message-id-collision

fix(dotnet): don't reuse the provider message id for reasoning events
…ator support (OSS-165)

Ag-ui side of unified in-band A2UI action handlers (OSS-165 v2):
- setValue/toggleValue authoring builders emitting native `action.functionCall`
  with the `agui.*` data-write vocabulary (centralises the wire name).
- validateA2UIComponents: accept `action.functionCall` — do not mis-flag a
  write-target `path` as an unresolved binding, still validate nested `{path}`
  read-bindings in arg values, and fail loud (`invalid_function_call`) on an
  unknown `agui.*` fn or a missing required arg.
- generation guidance teaches the local-swap functionCall shape.

Renderer-side registration of the agui.* functions is the CopilotKit handoff.
Verified against real @a2ui/web_core and real LLMs (OpenAI + Gemini).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tract

Regression test for how a forwarded `a2uiAction.userAction` is lowered into
synthetic messages the agent reads (log_a2ui_event tool call + human-readable
result), and that render_a2ui is available on that turn. Deterministic half of
the forward round-trip verified during OSS-165 v2. See PNI-106 for formalizing
this consumption + the v1.0 actionResponse/actionId round-trip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# dispatch would otherwise canary-publish from the tagged commit).
if: github.ref == 'refs/heads/main' || !startsWith(github.ref, 'refs/heads/')
run: |
echo "::error::Canary publishes are for non-main branches only (got '${{ github.ref }}'). To release from main, use the 'release / publish' workflow with mode=stable."
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: "3877599"
private-key: ${{ secrets.DEVOPS_BOT_PRIVATE_KEY }}
contents: read

jobs:
canary:
- name: Verify nx.json and release.config.json are in sync
run: bash scripts/release/verify-nx-release-allowlist.sh

release-scope-dropdown-sync:
- name: Verify release scope dropdowns match release.config.json
run: bash scripts/release/verify-release-scope-dropdowns.sh

release-config-manifest-names:
timeout-minutes: 45
environment: nuget
permissions:
contents: write
# failing 2.x run is surfaced as a warning annotation and a job summary. Once
# the 2.x failures are burned down, drop the step's continue-on-error to make
# this a required, blocking check.
adk-middleware-python-adk-2x:
runs-on: ubuntu-latest

steps:
- name: Checkout code

steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Report google-adk 2.x result
if: always()
run: |
if [ "${{ steps.adk2x-tests.outcome }}" = "success" ]; then
@github-actions

Copy link
Copy Markdown

Python Preview Packages — Publish Failed

Preview publish failed for commit d30f94b.
See the workflow run for details.

@contextablemark

Copy link
Copy Markdown
Member Author

Retargeted to upstream: superseded by ag-ui-protocol#2239 (rebased onto current ag-ui-protocol/main). This fork PR was opened against the fork's stale main by mistake.

@contextablemark
contextablemark deleted the mark/oss-165-a2ui-inband-v2 branch July 24, 2026 00:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.