Visitar URL original
feat(showcase/ag2): migrate AG2 showcase integration to AG2 1.x by vvlrff · Pull Request #7767 · CopilotKit/CopilotKit · GitHub
Skip to content

feat(showcase/ag2): migrate AG2 showcase integration to AG2 1.x - #7767

Merged
BenTaylorDev merged 63 commits into
CopilotKit:mainfrom
vvlrff:feat/showcase-ag2-1.x-migration
Nov 3, 2026
Merged

BenTaylorDev merged 63 commits into
CopilotKit:mainfrom
vvlrff:feat/showcase-ag2-1.x-migration

Conversation

@vvlrff

@vvlrff vvlrff commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Migrates the AG2 showcase integration (showcase/integrations/ag2) to the AG2 1.x API and brings it to feature parity with the other showcase integrations. This follows the AG2 1.x docs update merged in #7109.

  • Agents and server: core server, request plumbing and all agents (generative UI, interrupt, shared state, sub-agent, agent-config, headless, reasoning, tool-rendering chain) moved to AG2 1.x.
  • Reasoning demos enabled for AG2 1.1.2, with refreshed unsupported-feature verdicts.
  • MCP Apps demo is now served by an in-process ag2.mcp server.
  • Declarative generative UI (json-render, hashbrown) gets dedicated runtimes.
  • HITL in chat and beautiful-chat book via frontend tools.
  • Dependencies: CopilotKit 1.78.0 and @ag-ui/client 1.0.2, with the ag2 pin allowed in showcase-canonical-pins.json.
  • CI: the ag2 slug is allowed in the on-demand aimock e2e workflow, and aimock now runs with AIMOCK_STRICT_TURN_INDEX=1. Without it aimock re-serves the turnIndex:0 tool-call fixture on the follow-up turn and agents keyed on toolCallId loop. The flag is global, so it applies to every integration (see below).
  • Docs: PARITY_NOTES.md rewritten in AG2 1.x terms.

Known gaps

  • multimodal is red on aimock: an image-only input_image is turned into content: "" (aimock bug). It works against a real model.
  • The declarative-gen-ui spec still expects the old suggestions.
  • The MCP server publishes an extra ask tool.
  • Pytest has not been run on Python 3.10.
  • Playwright specs written against fixtures (e.g. "United Airlines", "Booked…Alice") fail against a real model.
  • Existing tsc errors (auth, declarative-json-render, headless-complete, hitl-in-app, cvdiag-emitter) are identical on 1.68.2 and 1.78.0.

Related PRs and Issues

Checklist

  • I have read the Contribution Guide
  • If the PR changes or adds functionality, I have updated the relevant documentation
  • If the PR contains a breaking change, the title has ! (for example feat(react-core)!: ...) and the description has a BREAKING CHANGE: line with migration steps. See VERSIONING.md (not applicable: no breaking change)
  • "Allow edits by maintainers" is checked (lets us help iterate on your PR directly — faster turnaround for everyone)

Summary by CodeRabbit

  • New Features
    • Expanded the AG2 showcase with reasoning, multimodal input, shared-state updates, agent delegation, and interactive diagram demos.
    • Added an in-chat booking demo and todo management in Beautiful Chat.
  • Updates
    • Updated the AG2 integration to use its current agent APIs and newer CopilotKit components.
    • Improved local and on-demand demo configuration for consistent tool-call handling.
  • Documentation
    • Updated AG2 showcase notes to reflect supported demos and known limitations.

vvlrff and others added 30 commits September 12, 2026 22:40
AG2 1.0 reshaped the public API, but every AG2 code sample in the docs
still targets 0.x — 127 references across 10 pages to symbols that no
longer exist. Following the quickstart today produces ImportErrors.

Migrate all AG2 documentation to the 1.0 API:

- `autogen` -> `ag2`; `ConversableAgent(system_message=, llm_config=)` ->
  `Agent(prompt=, config=OpenAIConfig(...))`
- `register_for_llm` / `register_for_execution` -> the `@tool` decorator
- `ContextVariables` -> conversation variables (`Context.variables`) and
  the `Variable()` annotation for injecting them into tools
- readables now read from `RunAgentInput.context` (typed items with
  `.description` / `.value`)
- auth threads identity through a server-side dependency rather than
  context variables, so it is never streamed to the client as state

Also:

- quickstart gains a "Connect your own AG2 agent" section covering
  `pip install "ag2[ag-ui,openai]"`, the manual `AGUIStream.dispatch`
  pattern and the `AGUIStream.build_asgi()` shorthand
- new page documenting subagents
- pass `framework="ag2"` to the shared `PrebuiltComponents` and
  `Interactive` snippets — without it they fall back to `langgraph`, so
  the AG2 pages were embedding LangGraph examples
- point AG2 doc links at `docs.ag2.ai/docs/...`; the `/latest/` prefix is
  no longer the canonical path

Every snippet was checked against the AG2 1.0 user guide.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- readables: drop the second json.loads, get_readable already decodes
- tool-rendering, subagents: add the parameters schema that a named
  useRenderTool registration requires; only the wildcard overload may
  omit it
- auth: give both sample identities allowed_accounts, and validate the
  token in the self-hosted handler so Inject("auth_user") resolves
- frontend-tools-setup: port the last 0.x setup cell to Agent/OpenAIConfig
- a2ui: move the runtime block to createCopilotRuntimeHandler and list
  the page in the generative-ui sidebar
- shared-state: fix the v1 useAgent link and qualify when the
  start-of-run STATE_SNAPSHOT is actually emitted
- manifest.schema.json: describe auth_pattern as dependencies + Inject

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Second review round on the AG2 1.0 docs migration, plus three issues
found while verifying every snippet against the ag2 1.0 sources.

From review:

- readables: `prompt=` on `dispatch` replaces the agent's prompt rather
  than adding to it (`ask()` assigns `context.prompt`, and
  `_prepare_turn` only seeds `_system_prompt` when it is empty), so the
  agent ran on the readables alone with its instructions silently
  dropped. Send both.
- shared-state read/write: `agent.state.language` was read unguarded
  right after two `?? {}` guards, crashing in that same early window.
- auth (both pages): the prose told the reader to register the tool with
  `tools=[...]`, but no `Agent(...)` block on either page had it.
- generative-ui sidebar: `mcp-apps` and `your-components` were missing
  from `meta.json`, so both pages were unreachable. Adds the
  `your-components/meta.json` every other integration already has.
- manifest: rename `ag2-context-variables` to `ag2-dependencies` — the
  flag describes dependency injection now, not context variables.
- state-rendering: `type AgentState` was declared and never used; v2
  `useAgent` takes no generic, so it types `agent.state` the way the
  shared-state pages already do.

Found while verifying:

- readables: `useAgentContext` JSON-encodes objects and arrays but
  passes a plain string through untouched, so the unconditional
  `json.loads` in `get_readable` raised on any string readable.
- shared-state write: the advanced snippet read `agent.state` unguarded;
  llamaindex's equivalent uses `agent.state?.`.
- subagents: `run_task` hands a delegation a copy of the conversation
  variables and never merges the specialist's writes back, so state
  written in a subagent silently never reaches the UI.

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

One conflict, in `showcase/integrations/ag2/docs/setup/frontend-tools-setup.mdx`.
main bumped that snippet's model from `gpt-4o-mini` to `gpt-5-mini` (#PE-70,
which gates shipped code on models we still ship); this branch had rewritten
the same block from the 0.x `ConversableAgent` / `llm_config` form to AG2 1.0's
`Agent` / `config=OpenAIConfig(...)`.

Resolved to this branch's 1.0 form. Its `gpt-5.4-mini` is already in the
`ship` tier of `showcase/shell-docs/model-allowlist.json`, so it satisfies the
gate main added and is newer than the name main swept to;
`scripts/validate-doc-model-names.ts` passes on the merge result.

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

Resolves conflicts from the unified partner landing pages work:
- ag2/index.mdx: take the new FrameworkOverview data-record page from main;
  re-apply the AG2 1.0 module rename (autogen.ag_ui -> ag2.ag_ui) in its
  connect intro.
- framework-overviews/ag2/after-features.mdx: accept the upstream deletion;
  the AG-UI callout it held no longer has a place on the new landing page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Raise the dependency floor to ag2>=1.1.2, run the default agent on the 1.x
Agent/AGUIStream with the OpenAI Responses config, drop the thread-pool
ContextVar shim that only the legacy sync LLM path needed, and drop the
multimodal normalizer: AG2 1.x maps image/document parts natively and strips
the legacy binary mirror during run-input parsing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@vvlrff

vvlrff commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

@NathanTarbert could you please trigger the CI run for this PR? Thanks!

@vvlrff

vvlrff commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

Hi @tylerslaton @jpr5 @ranst91 @marthakelly @mme @NathanTarbert 👋

Friendly ping on this PR. All CI checks are green (50 passing, 2 skipped) and there are no merge conflicts. The last activity here was about a week ago.

Could one of you take a look and, if everything looks good, approve and queue it for merge? Happy to address any remaining feedback right away.

Thanks!

@NathanTarbert

Copy link
Copy Markdown
Contributor

Hey @vvlrff, Apologies for the delayed response. I went through this properly, both the ag2 side and the four files outside it. All 50 checks are green now.

The thing I'd like to settle before this goes in is the loop caps. The old code set max_consecutive_auto_reply in twenty places, and this PR removes all twenty without putting anything back. Those limits weren't arbitrary: the comments deleted alongside them describe what happened without them, which was a tool loop producing enough log volume to hit the platform's rate limit, the service going unresponsive to health probes, and the watchdog killing it. AG2 1.x genuinely has no drop-in replacement, and you were right to say so in PARITY_NOTES.md. But the PR body's Known gaps list doesn't mention it, and that list is where a reviewer looks. There is a partial option: OpenAIResponsesConfig.max_tool_calls exists in 1.1.2 and isn't used anywhere here. It caps tool calls per response rather than turns in a loop, so it isn't the same guarantee, but on the agents that previously had the tightest limits it's a lot better than unbounded. Worth setting on those few, or at minimum moving the gap into the PR body so it's a conscious call rather than a surprise later.

On the aimock flag, the good news is that this isn't actually a conflict between integrations. The one file that breaks under strict mode is showcase/aimock/d6/mastra/shared-state-read.json, and the reason is visible in the file itself: it carries "copiedFrom": "langgraph-python", and its second leg has a comment saying "turn 2" while the field says "turnIndex": 0. The file it was copied from has no turnIndex on that leg at all. So it's a one-line fix in the fixture, not a reason for the flag to stay per-integration. Strict is also the honest default here, since the proxy path runs that way regardless. If you fix that line, this stops being a tradeoff and the flag can just be on.

Two things about the ag2 pin. requirements.txt asks for ag2[openai,ag-ui,mcp]>=1.1.2 with no ceiling, and the code carries patches written against 1.1.x internals. One of them injects a reasoning option because the 1.1.2 config object has no such field. That field exists in 1.2.1, which is what a fresh install resolves to today, so the patch is already doing nothing and its docstring already describes a version nobody installs. The other reaches into a private attribute on the request object. Neither is wrong today, but an unbounded floor plus private-API reach is the combination that breaks on someone else's machine and not yours. A ceiling, or a comment naming the exact versions each patch targets, would make that survivable.

Related, and this one CI can't catch for you. _usage_compat.py installs two patch targets. Only the second does anything. If you delete the first line the whole suite still passes, because the test calls the replacement function directly and never checks that installing it rebound anything. If you delete the second, every aimock-backed run dies partway through, after the text has already streamed to the user. A test that asserts the patch actually landed on the client would catch both directions.

Smaller, but worth a look. manifest.yaml now advertises reasoning support for tool-rendering-reasoning-chain, and that agent never asks for a reasoning summary. Only reasoning_agent.py gets that hook. Against aimock it looks fine because the fixture supplies the content, but against a real model that slot comes back empty and the manifest claim is false. Separately, the MCP ask tool is registered unconditionally and ends up in the chat agent's tool list, so the model can call it. That spins up a second model the demo doesn't intend to use and has no fixture for. The old prompt had a line telling the model not to, and this PR drops it.

On the big deletion, I think you made the right call and then undersold it. Removing the 390-line multimodal normalizer isn't just less code, it's better behavior: AG2 1.x produces real typed document inputs where the old path encoded PDFs as base64 image URLs. That's a capability gain, not parity. One detail that might matter for the bug you filed: 1.x drops the legacy binary part rather than converting it, which could be the actual source of the image-only-becomes-empty case rather than anything on the mock side. Worth confirming which before that report goes further.

Last one is the dependency list. requirements.txt dropped ag-ui-protocol and openai, but src/agents/_state.py still does from ag_ui.core import StateSnapshotEvent, and both src/agents/agent.py and src/agents/beautiful_chat.py still import openai. Those resolve today because ag2[openai,ag-ui] drags them in, so nothing breaks until ag2 changes what it depends on. reasoning_agent.py has the same shape in reverse: it imports httpx2, which is the right call since that's what AG2 1.x builds its client on, but the file declares httpx>=0.27.0 and nothing declares httpx2. Going the other way, pypdf>=4.0.0 is still pinned and the normalizer that used it is gone. While you're in there, roll_dice and roll_d20 disagree in one spot, which I think predates this PR but is a one-word fix.

Happy to talk through any of these. The loop cap is the only one I'd call blocking, and the mastra fixture line is the one that makes the cross-integration worry go away entirely.

NathanTarbert and others added 2 commits October 27, 2026 10:46
- Restore a per-run loop cap: AG2 1.x has no max_consecutive_auto_reply, so
  a middleware now limits model calls per run, using each agent's old cap.
- Pin ag2==1.1.2 exactly, which also fixes the dependency set its extras pull
  in; drop unused pypdf. Ratchet the validate-pins baseline 24 -> 23.
- Share the reasoning-summary config with tool-rendering-reasoning-chain so
  its reasoning slot fills against a real model, and enable the reasoning
  cells in the manifest.
- Add the missing ag2 tool-rendering-reasoning-chain fixture (roll_dice).
- Patch only the usage-mapper binding the client calls and test it lands.
- Tell the MCP Apps agent not to call the server's built-in `ask` tool.
- Drop the stray turnIndex on mastra shared-state-read's second leg, so it
  passes with AIMOCK_STRICT_TURN_INDEX=1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vvlrff

vvlrff commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review, @NathanTarbert. Everything is addressed in c08e59f:

Loop cap (blocking). AG2 1.x does have a real replacement, just not as a config option. Middleware is instantiated per run, and on_llm_call can short-circuit the model. src/agents/_loop_cap.py allows at most N model calls per run. After that it ends the turn with a short text reply and no tool calls, which stops the loop. All 20 former max_consecutive_auto_reply sites have it back, with their old N (plus reasoning_agent). It counts model calls rather than auto-replies, so a single response that requests parallel tools counts once. That difference is noted in PARITY_NOTES.md. test_loop_cap.py checks that a scripted 10-round tool loop stops at 3.

aimock flag. You were right. I dropped the stray turnIndex: 0 on the second leg of aimock/d6/mastra/shared-state-read.json, and mastra:shared-state-read is now green with AIMOCK_STRICT_TURN_INDEX=1.

ag2 pin. Now ag2[openai,ag-ui,mcp]==1.1.2. Both patches name the version they target: _reasoning_summary.py (the reasoning.summary injection, which exists because 1.1.2's config has no reasoning field) and _usage_compat.py.

_usage_compat.py. Only the client-module binding is used in 1.1.2, so the no-op mappers rebind is gone. A new test asserts that after install_usage_compat() the client module calls the replacement.

Reasoning chain. The reasoning-summary config is now shared, and tool_rendering_reasoning_chain.py uses it, so the slot fills against a real model too. While checking this I found that the three reasoning cells were never in the manifest's features: list, so their probes had never run. They are listed now, and tool-rendering-reasoning-chain, reasoning-custom and reasoning-default are green on d6. ag2 also had no tool-rendering-reasoning-chain fixture at all. I added one, ported from langgraph-python (with roll_dice, which the shared probe expects). That was the roll_dice/roll_d20 mismatch.

MCP ask. AG2 1.1.2's MCPServer always registers it, and the runtime's mcpApps config has no per-server tool filter. So I restored a prompt line telling the model not to call it.

Dependencies. pypdf is removed. I did not add ag-ui-protocol, openai or httpx2 as separate lines. With ag2 pinned exactly, its extras fix which packages come in and their ranges (ag-ui-protocol>=1.0,<2, openai>=3.9.0,<4, and httpx2 via openai). They can only change when the ag2 pin moves, and I'd rather re-check them then than keep three pins that would have to move with it. Happy to add them if you'd prefer them explicit.

Multimodal. Agreed on the framing. I haven't yet confirmed whether the empty content comes from AG2 1.x dropping the legacy binary part. That is still open in Known gaps, and I'll check it before the aimock report goes further.

Verified: pytest 19/19 on Python 3.12 and 3.14; validate-parity, validate-pins (baseline ratcheted 24 → 23), validate-shared-symlinks and validate-fixture-tool-surface clean. d6 green on ag2 tool-rendering-reasoning-chain, reasoning-custom, reasoning-default, mcp-apps, agentic-chat, shared-state-read-write, subagents, and on mastra:shared-state-read.

@NathanTarbert

Copy link
Copy Markdown
Contributor

Hey @vvlrff, it looks like showcase is failing.

vvlrff and others added 2 commits October 31, 2026 11:31
The create_view fixture added to ag2 tool-rendering-reasoning-chain.json
in c08e59f duplicated mcp-apps.json[1] exactly, pushing the aimock
exact-duplicate count to 379, one past the 378 ceiling. mcp-apps.json
already covers this prompt, so remove the copy.
@vvlrff

vvlrff commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

@NathanTarbert could you please trigger the CI run for this PR? Thanks!

@NathanTarbert

Copy link
Copy Markdown
Contributor

@vvlrff, yes, doing it now.

@vvlrff

vvlrff commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

@NathanTarbert thanks for triggering the run! CI is green now (51 checks passed, 3 skipped), including showcase. Could you take another look and approve when you have a moment? Thanks!

@NathanTarbert

Copy link
Copy Markdown
Contributor

Hey @vvlrff, no problem. On it!

@NathanTarbert

Copy link
Copy Markdown
Contributor

Hey @vvlrff, thanks for working through all of that. The loop cap middleware is a nice way to get the old guarantee back, and the caps match what each agent had before.

One thing I'd like covered before this goes in. The docstring in _loop_cap.py says the count resets every run because AG2 creates middleware per run. That's the key property here. If it ever stops being true, an agent that is defined once at module level would hit its cap once and then answer every request after that with the limit message. Both tests in test_loop_cap.py call ask a single time, so they wouldn't notice. Could you add a test that calls ask twice on the same agent and checks that the second run gets its full allowance?

Also, could you refresh the Known gaps section in the PR description? It still lists the mastra:shared-state-read strict-mode failure and the roll_dice/roll_d20 mismatch, and both of those are fixed now. Whoever merges this will read that list, so it's worth keeping it accurate.

…e agent

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vvlrff

vvlrff commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

@NathanTarbert thanks! Added test_cap_resets_between_runs_of_the_same_agent, which calls ask twice on the same agent and checks that both runs get the full allowance. It fails if the count leaks across runs. I also removed the two fixed items from Known gaps.

@NathanTarbert

Copy link
Copy Markdown
Contributor

Thanks @vvlrff, that test covers it. Nothing else from me on this one.

@BenTaylorDev BenTaylorDev 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.

Reviewed independently against current main. No blockers. Nathan's review points are all addressed, and CI is green, including the ag2 pytest suite on 3.10 and 3.12.

Optional follow-ups, not blocking:

  • The "Pytest has not been run on Python 3.10" item in Known gaps is stale. CI runs it (20 passed).
  • agent_server.py reaches into the private mcp_apps_server._http. Please add a comment naming the AG2 1.1.2 pin, as the other two patches do.
  • _is_async_httpx_target checks isinstance only against httpx, so httpx2 clients use the low-confidence name fallback. An httpx2 check would fix this.

I bless the code with a glad heart

@BenTaylorDev
BenTaylorDev added this pull request to the merge queue Nov 3, 2026
Merged via the queue into CopilotKit:main with commit c5f6998 Nov 3, 2026
54 checks passed
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.

3 participants