Repository navigation
Conversation
A new emitter renders the protocol model into sdks/dart/lib/src/generated: immutable final classes with fromJson/toJson, sealed classes for the unions, enums with wire names, typedefs for the aliases, and a shape table for the enforcement stage. Output is laid out the way dart format 3.13 would lay it out, since the generator cannot run the formatter; the Dart CI checks it.
…ated codec Optional literal fields are stored rather than computed so an absent one stays absent; the open RFC 6902 operations keep undefined members in an extras map; omitOptionalNulls walks the generated shapes to drop whole optional nulls from raw documents, the producer-side contract the shared null-omission fixture pins. Dart joins producedBy in both shared fixtures.
The agent holds the conversation and state, builds the request (declaring the protocol version unless the peer ceiling is pinned below it), and runs one pipeline at a time; the HTTP agent posts JSON and reads server-sent events through an injectable http.Client.
The boundary reads the tabled optional nulls as absent, translates the retired THINKING_* events and legacy binary parts, and warns once per field per run. Enforcement drops unknown event types, deep-strips unknown material against the generated shapes with a warning per path, and decodes; a malformed known field stays fatal. The 0.0.39, 0.0.45 and 0.0.57 downgrades are plain functions selected by the peer ceiling.
The remaining three stages of the TypeScript run pipeline, ported rule for rule with the error and warning text kept verbatim: chunk events expand into their triads, the lifecycle and attribution rules are verified, and every event is applied onto messages, state and pending interrupts, with a hand-written RFC 6902 over the generated operation types. The pipeline now runs all stages in the TypeScript order.
Every stream in spec/1.0/conformance/streams is replayed as SSE bytes through a mock http.Client into an HttpAgent and held to the fixture's expectation; the spec harness and the TypeScript fixture type know the dart lane. One override, for the decoder's spelling of a wrong-role rejection. Also the example, README, changelog and the AGENTS.md handoff with the ledger of what is not implemented.
A run now starts on listen, so a stream nobody listens to cannot lock the agent; the peer ceiling is validated at construction; HttpAgent.close() releases the client it created; a frame that is not JSON is a decode error; the SSE parser delivers an event still open at end of stream, as TypeScript does, and caps event size; agent.messages is a fresh read-only view per applied event; the reducer's copy helpers are pinned by a test that sets every field; the emitter resolves aliases on optional fields and refuses an optional literal that narrows an enum; the drift gate runs on hand edits to generated Dart; the Dart CI check has its own name; AGENTS.md and README corrected accordingly.
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - "sdks/dart/**" | ||
| - "spec/**" | ||
| - "sdks/fixtures/**" | ||
| - ".github/workflows/unit-dart.yml" | ||
| pull_request: | ||
| branches: [main] | ||
| paths: | ||
| - "sdks/dart/**" | ||
| - "spec/**" | ||
| - "sdks/fixtures/**" | ||
| - ".github/workflows/unit-dart.yml" |
Python Preview PackagesVersion
Install with uvAdd the TestPyPI index to your [[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
explicit = trueThen install the packages you need: # Core SDK
uv add 'ag-ui-protocol==0.0.0.dev1792062588' --index testpypi
# Integrations (each already depends on the matching ag-ui-protocol preview)
uv add 'ag-ui-langgraph==0.0.0.dev1792062588' --index testpypi
uv add 'ag-ui-crewai==0.0.0.dev1792062588' --index testpypi
# NOTE: ag-ui-agent-spec depends on pyagentspec (git-only, not on PyPI).
# You will need to install pyagentspec separately from its git repo.
uv add 'ag-ui-agent-spec==0.0.0.dev1792062588' --index testpypi
uv add 'ag_ui_adk==0.0.0.dev1792062588' --index testpypi
uv add 'ag_ui_strands==0.0.0.dev1792062588' --index testpypiInstall with pippip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
ag-ui-protocol==0.0.0.dev1792062588
Commit: b841707 |
@ag-ui/a2a-middleware
@ag-ui/a2ui-middleware
@ag-ui/event-throttle-middleware
@ag-ui/mcp-apps-middleware
@ag-ui/mcp-middleware
@ag-ui/a2a
@ag-ui/adk-js
@ag-ui/adk
@ag-ui/ag2
@ag-ui/agno
@ag-ui/antigravity
@ag-ui/aws-strands
@ag-ui/claude-agent-sdk
@ag-ui/claude-managed-agents
@ag-ui/crewai
@ag-ui/langchain
@ag-ui/langgraph
@ag-ui/llamaindex
@ag-ui/mastra
@ag-ui/pydantic-ai
@ag-ui/vercel-ai-sdk
@ag-ui/watsonx
@ag-ui/a2ui-toolkit
create-ag-ui-app
@ag-ui/client
@ag-ui/core
@ag-ui/encoder
@ag-ui/proto
commit: |
contextablemark
left a comment
There was a problem hiding this comment.
I’d fix these two before merging: stopping a run can leave the agent stuck, and the generated message constructor can send invalid content. Both reproduced locally despite the 645 tests passing.
| ..headers['content-type'] = 'application/json' | ||
| ..headers['accept'] = 'text/event-stream' | ||
| ..body = jsonEncode(input.toJson()); | ||
| final response = await client.send(request); |
There was a problem hiding this comment.
P1 — cancelling a run can leave it stuck.
I reproduced this while waiting for response headers and again after RUN_STARTED with an idle SSE stream: subscription.cancel() stayed pending and agent.isRunning stayed true until the transport progressed or closed. That also blocks the next run.
Could we make cancellation unwind the transport and pipeline without waiting for the server, and add tests for both cases? Cancelling the subscription is the documented way to stop a run, so it needs to work when the server goes quiet.
|
|
||
| /// What the person sent: either plain text, or an ordered list of parts for a | ||
| /// multimodal message. | ||
| final Object content; |
There was a problem hiding this comment.
P2 — this lets invalid content go out on the wire.
UserMessage(id: 'u', content: 42) compiles and serializes as {"role":"user","id":"u","content":42}, but UserMessage.fromJson() rejects that same output. The constructor accepts anything because this field is Object.
Could we generate a typed text-or-parts API, or typed constructors with validation, so unsupported values cannot be sent? Please fix this in the emitter and cover valid text/multimodal round-trips plus invalid outbound content.
|
Can I use the following registerCopilotKit({
path: "/ag-ui/app",
resourceId: "copilotkit",
a2ui: {
enabled: true,
injectA2UITool: true,
},
});How can I connect AG-UI to Flutter GenUI? Why is there no documentation explaining how to integrate them? I haven't implemented the Flutter side yet. For now, I just want to research how to connect AG-UI with GenUI and determine the correct integration approach. |
What
A first-party Dart client for AG-UI 1.0, package
aguiatsdks/dart, generated fromspec/1.0/schema.json. It is a V0: a working skeleton for the Dart team to complete, with an explicit ledger of what is not implemented insdks/dart/AGENTS.md. The community package atsdks/community/dartis untouched.How
spec/generator/dart.tsrenders the protocol model intosdks/dart/lib/src/generated/(models.dart,shapes.dart,version.dart): immutable classes withfromJson/toJson, sealed unions, enums with wire names, and a shape table for enforcement. Wired intogenerate.tsand the byte-for-byte drift gate. The emitter lays the code out the waydart format3.13 does, since the generator cannot run the formatter; the Dart CI checks it with a pinned SDK.AbstractAgentandHttpAgentover server-sent events, pure Dart,package:httpas the only dependency.messages,stateandpendingInterrupts.spec/1.0/fixtures; the sharednull-omissionandagent-capabilitiesfixtures now listdartinproducedBy; and the conformance corpus inspec/1.0/conformance/streamsruns as a third lane (oneexpectOverrides.dart, for the decoder's spelling of a wrong-role rejection).spec/harness/conformance.test.tsandfixture.tsknow the lane..github/workflows/unit-dart.yml(analyze, format check, test; Dart pinned to 3.13.5). The TypeScript workflow's path filter includes the generated Dart so the drift gate runs on hand edits there.Not in this PR (by design, see the ledger)
Subscriber API, middleware abstraction, resume validation, protobuf transport, legacy event conversion/compaction/activity history,
copyWith/equality on generated types, docs pages, pub.dev publishing, a Flutter companion.Verification
cd sdks/dart && dart analyze --fatal-infos && dart format --set-exit-if-changed . && dart test— 645 tests, all 72 conformance streams includedcd spec && pnpm test && pnpm lint && pnpm typecheck— 2577 testspnpm --filter @ag-ui/client typecheckand its conformance lane (69) after the fixture-type change