Commit Graph

142 Commits

Author SHA1 Message Date
Rod Boev a76d59ae0b fix(sdk-python): capture subgraph context from run input (#3886) 2026-07-26 16:42:46 -04:00
Rod Boev fee7ec237c fix(sdk-python): bridge copilotkit context into LangGraph subgraphs 2026-07-24 16:19:13 -04:00
Rod Boev bb32138e15 fix(sdk-python): read copilotkit context from config when state is empty (subgraph support) 2026-07-24 16:13:05 -04:00
godququ5-code 44c43e4770 fix(python-sdk): fold app context into system prompt 2026-07-03 01:06:09 +03:00
Ran Shem Tov f13865a21f fix(sdk-python): declare ag-ui state channel and add a2ui_params host override
The middleware reads state["ag-ui"]["inject_a2ui_tool"] and
state["ag-ui"]["a2ui_schema"], but "ag-ui" was never declared on the
StateSchema, so create_agent's StateGraph dropped both keys before the
middleware ran — the generate_a2ui tool never injected and the catalog was
lost. Declare the "ag-ui" channel via StateSchema.__annotations__ so the flag
and catalog survive.

Also add an a2ui_params kwarg so a host can steer the auto-injected
generate_a2ui subagent (design/generation guidelines, catalog id, ...). The
middleware still injects the bound model and folds the registered catalog in,
but host-set values win.
2026-06-19 17:50:26 +02:00
Ran Shem Tov 5bb32b9dd5 feat(a2ui): use new ag-ui single-arg A2UIToolParams API (OSS-248)
ag-ui-langgraph's tool factory now takes one A2UIToolParams object (model
inside) and folds composition_guide into the guidelines bag.

- sdk-js middleware: getA2UITools(params) + type A2UIToolParams import;
  pin @ag-ui/langgraph 0.0.40 (the JS release carrying the new API).
- sdk-python middleware: get_a2ui_tools(params) + guarded A2UIToolParams
  import; pin ag-ui-langgraph >=0.0.41 (the py release with the new API).
- Update the a2ui injection test skip-reason wording.
2026-06-09 12:13:51 +02:00
Ran Shem Tov 3ca0f194b8 feat(sdk): gate auto-A2UI injection on injectA2UITool (opt-in)
The A2UI middleware (@ag-ui/a2ui-middleware) forwards injectA2UITool on
forwardedProps; ag-ui-langgraph surfaces it into agent state at
state["ag-ui"]["inject_a2ui_tool"]. The CopilotKit LangGraph middleware
(py + js) now reads that flag and only injects generate_a2ui when it is
truthy (opt-in), drops the runtime's render_a2ui so the model sees one
A2UI tool, and skips if the agent already defines generate_a2ui. The
catalog only binds surfaces; it is no longer the gate.

Reverts the earlier runtime-forward + context-channel approach.

Deps: ag-ui-langgraph>=0.0.38 (py), @ag-ui/langgraph 0.0.37 (sdk-js),
@ag-ui/a2ui-middleware 0.0.6 + @ag-ui/langgraph 0.0.37 (runtime);
.npmrc min-release-age exclude for @ag-ui/a2ui-middleware. Showcase
langgraph pins bumped to copilotkit==0.1.94a3 / sdk-js 1.59.3-alpha.3 /
@ag-ui/langgraph 0.0.37.
2026-06-04 18:37:03 +02:00
Ran Shem Tov 1bd944bd43 feat(sdk): source A2UI catalog wherever the frontend registered it
The auto-injected generate_a2ui tool now resolves the A2UI catalog from
both delivery paths: the CopilotKit runtime proxy (a copilotkit.context
entry) and the AG-UI native endpoint (state["ag-ui"].a2ui_schema). The
registered catalog id is extracted and bound to generated surfaces so
BYOC custom catalogs render their own components instead of the basic
catalog. Covers @copilotkit/sdk-js and the copilotkit Python SDK.
2026-06-04 18:36:12 +02:00
Ran Shem Tov ce4e4142b2 feat(sdk): auto-inject A2UI tool in CopilotKitMiddleware
Prebuilt agents get dynamic A2UI with no extra wiring — adding the
middleware is enough. When the frontend registers an A2UI catalog
(surfaced by the runtime into state["ag-ui"].a2ui_schema), the
middleware infers the agent's own model, advertises the generate_a2ui
tool in the model-call hook, and executes it in the tool-call hook.
No catalog → the tool is never advertised.

Covers both @copilotkit/sdk-js and the copilotkit Python SDK. Bumps
the A2UI tool-factory dependency to where get_a2ui_tools ships
(@ag-ui/langgraph 0.0.35, ag-ui-langgraph >=0.0.37).
2026-06-04 18:36:12 +02:00
github-actions[bot] b2f10f6753 style: auto-fix formatting 2026-05-29 03:58:54 +00:00
Jordan Ritter 59eff59b7f fix(sdk-python): strip copilotkit_forwarded_headers from LLM prompt (App Context + expose_state)
langgraph-api auto-copies the entire config.configurable dict into runtime.context. That dict
carries the CopilotKit-internal transport key `copilotkit_forwarded_headers`, populated solely
to drive the httpx header-forwarding hook (it is not user-visible state). The middleware's
before_agent step then rendered runtime.context into the LLM prompt as an "App Context" system
message, and the expose_state path could surface the same key via the state note — either path
leaks transport headers into the prompt body and, under strict fixture matching (D6/aimock),
changes the request payload and breaks the match.

Fix: hard-exclude `copilotkit_forwarded_headers` from both render paths. The App Context
renderer strips the reserved key before serialization, and the expose_state allowlist applies
the same exclusion so an explicit allow cannot reintroduce the leak. The httpx hook is
unchanged, so the key still reaches aimock as an HTTP header — pure conveyance, no body
pollution.

Adds red-green unit coverage for both paths (App Context strip, expose_state default + allowlist).
2026-05-28 20:57:37 -07:00
Jordan Ritter 3110cf9b00 docs(sdk-python): document header_propagation module purpose and scope
Adds a module-level docstring at the top of header_propagation.py that explains in plain
English what the module does (forwards CopilotKit request-context x-* headers onto
outbound LLM/provider HTTP calls so downstream services like the aimock test server and
proxies can correlate the outbound call with the original inbound request), the precise
scope (only headers the application itself set via set_forwarded_headers; no request
bodies, cookies, user data, credentials, or telemetry), and the mechanics (walks the
._client chain to find the httpx client and attaches an async hook for AsyncClient or a
sync hook for Client). Also softens a few comments and docstrings whose wording could
read as surveillance language ("inject" / "installing an async hook ... silently dropped")
to neutral engineering phrasing ("attach" / "the forwarded headers would not be attached
to the outbound request") without losing any technical meaning or warnings. No executable
logic, signatures, conditionals, or string literals in code paths were changed; the diff
is comments and docstrings only.

In response to review feedback on PR #5088.
2026-05-28 14:39:07 -07:00
Jordan Ritter 3e6fc5ca32 fix(sdk-python): walk _client chain and install async hook on AsyncClient
Forwarded headers (e.g. X-AIMock-Context) were dropped before reaching the
wire in two cases. First, install_httpx_hook only attached to the immediate
client, missing an httpx client nested one or more ._client hops deep; it now
walks the ._client chain (bounded) to find the object that carries
event_hooks. Second, a sync def hook installed on an httpx.AsyncClient was
invoked as a coroutine and never awaited, silently dropping headers; the hook
is now async def for AsyncClient and sync def for Client. Async detection
prefers isinstance against the real httpx classes and falls back to an EXACT
"AsyncClient" MRO class-name match (not startswith("Async"), which would
misclassify a sync client whose MRO includes an Async*-named base).
2026-05-28 14:39:07 -07:00
Ran Shemtov 9158241c10 Merge branch 'main' into wt-4995-29229-6154 2026-05-27 17:39:28 +02:00
Maxim dff634d462 Merge branch 'main' into feature/emit-tool-call-optional-id 2026-05-27 15:12:10 +02:00
ryker 8e5901133c fix(python): serialize AGUI agent metadata safely 2026-05-27 14:10:12 +08:00
Jordan Ritter 7b2f1e9be6 fix(sdk-python): forwarded-header extraction with precedence, normalization, and exception-safe clearing
Extract incoming x-* headers from LangGraph's runtime config and republish
them via the forwarded-headers ContextVar so the httpx hook can attach
them to outbound provider requests. Apply documented precedence
(context > configurable, wrapper-dict > raw x-*) by processing sources
in order with first-write-wins and lowercasing keys at insertion so
mixed-case headers do not silently overwrite each other downstream.

Always clear the ContextVar on early exits so stale headers from a prior
request never leak into the next: explicit set_forwarded_headers({}) on
the RuntimeError no-active-runnable path and on the generic exception
fallback. The happy path already overwrites the ContextVar
unconditionally, even with an empty dict.

The change also installs the httpx event hook once per chat-model client
via a module-level set keyed by id(client), so models reused across
requests pick up fresh per-request headers without re-hooking.
2026-05-22 14:36:43 -07:00
Jordan Ritter 9107e00a9a fix(runtime): close header propagation gap for LangGraphAgent
The if (agent.headers) guard in configureAgentForRequest silently
skipped header forwarding when agent.headers was undefined (the
default for LangGraphAgent). This meant x-aimock-context, x-test-id,
and other x-* headers were never forwarded to agent backends.

Also wires install_httpx_hook in the Python SDK middleware so
forwarded headers propagate to outgoing LLM API calls.

Closes the gap documented in PR #4773 spec as out-of-scope.
2026-05-21 01:39:28 -07:00
Maxim 2169cc9383 fix(sdk): widen AG-UI dispatcher args validation to match emitter contracts
The AG-UI dispatcher's ManuallyEmitToolCall handler rejected non-dict,
non-string args with CopilotKitMisuseError, but all three emitters
(JS, Python LangGraph, Python CrewAI) accept any JSON-serializable
value. This mismatch caused JS-emitted list/number args to crash the
Python dispatcher.

Replace the strict isinstance(dict, str) check with a None guard and
rely on the existing json.dumps try/except for serializability.

Call-site enumeration:
- langgraph_agui_agent.py:129 — changed from isinstance check to None guard
- test_emit_tool_call_optional_id.py — updated test_missing_args_raises match,
  test_non_serializable_args_raises match, converted test_list_args_raises and
  test_int_args_raises from negative to positive tests
- No other call sites reference the removed isinstance pattern

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:26 +02:00
Maxim 570bcf4264 fix(sdk): remove dead try/except in emit_message, drop unused imports in sdk.py
Remove no-op `try/except CancelledError: raise` around asyncio.shield
in copilotkit_emit_message (the shield handles cancellation on its own).
Remove unused CopilotKitError and CopilotKitMisuseError imports from
sdk.py (already re-exported via __init__.py).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:26 +02:00
Maxim f434418df5 fix(sdk): restore batched queue_put for atomicity, fix end_dispatched flag ordering
The split queue_put calls introduced interleaving risk (6 yield points
vs 2) and the end_attempted flag was set before the END dispatch,
causing the compensating END to be skipped when END itself failed.

- CrewAI: restore single batched queue_put(start, args, end) call;
  compensating END is now unconditional on batch failure
- AG-UI agent: rename end_attempted → end_dispatched, set after
  successful END dispatch so compensation fires for all failure modes
- Tests: rewrite CrewAI compensating tests for batch semantics,
  add test_failure_on_end_emits_compensating_end for AG-UI agent

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:25 +02:00
Maxim 90de3cef88 fix(sdk): wrap dispatch errors instead of mutating, fix duplicate-END, use UUID for tool call IDs
- Replace JS error.message mutation with wrapped Error + cause chain
  (safe for frozen errors, shared references, non-Error throwables)
- Rename dispatched_end → end_attempted, set before END dispatch to
  prevent duplicate TOOL_CALL_END when END partially flushes before throwing
- Switch JS randomId() (ck-prefixed) to randomUUID() for cross-SDK parity
  with Python's str(uuid.uuid4())

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:25 +02:00
Maxim d395501de0 fix(sdk): enrich JS dispatch errors, shield emit_message, standardize validation order
- Wrap JS dispatchCustomEvent in try/catch that enriches error messages
  with tool name and ID for debuggability
- Apply asyncio.shield to copilotkit_emit_message's post-dispatch sleep
  to match copilotkit_emit_tool_call's behavior under task cancellation
- Reorder validation in LangGraph Python and JS to name → toolCallId →
  args, matching CrewAI's order (cheap checks before serialization)
- Narrow AG-UI dispatcher's except clause around json.dumps from
  Exception to (TypeError, ValueError), matching sibling SDK variants
- Add CancelledError propagation and warning-log tests for the shielded
  sleep path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:24 +02:00
Maxim e1da79a5ea fix(sdk): fix CancelledError swallow, dispatched_end ordering, add JS args validation
- Re-raise CancelledError after logging in langgraph copilotkit_emit_tool_call
  to honor asyncio cancellation contract (was silently un-cancelling tasks)
- Move dispatched_end flag to after ToolCallEndEvent dispatch in AG-UI agent
  so compensating END fires when END itself throws
- Add dispatched_end tracking to CrewAI variant to prevent double-END on
  partial failure
- Add JSON.stringify(args) validation in JS SDK matching Python parity
- Add 4 CrewAI compensating-END tests and 1 JS serializability test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:24 +02:00
Maxim 4a6d364e2c fix(sdk): harden error handling, revert args strictness, shield sleep
Address code review findings across all three SDK variants:

- Shield asyncio.sleep(0.02) with asyncio.shield() so task cancellation
  doesn't prevent returning the tool_call_id after dispatch
- Revert args validation to original permissiveness (JS: undefined-only
  check, Python: no isinstance check) to avoid breaking existing callers
- Add upfront json.dumps() serializability check in Python variants
- Fix compensating TOOL_CALL_END double-emit by tracking dispatched_end
- Add compensating action_execution_end to CrewAI variant (queue_put is
  non-atomic)
- Use exc_info=True in compensating-END error logging
- Export all exception types from copilotkit package root (__init__.py)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:23 +02:00
github-actions[bot] 1df8a80e58 style: auto-fix formatting 2026-05-20 00:18:23 +02:00
Maxim be9b60c8a9 fix(sdk): harden AG-UI dispatch, add exception hierarchy, fix docstrings
Address code review findings:
- Wrap AG-UI tool call dispatch in try/except with compensating
  TOOL_CALL_END to prevent clients hanging on partial emission
- Reject non-dict/non-str args at the dispatch layer (lists, ints, None)
- Guard against None event value before calling .get()
- Fix docstring examples that reuse variable names (won't compile)
- Introduce CopilotKitError base class; all exceptions now inherit from
  it; CopilotKitMisuseError inherits from both CopilotKitError and
  ValueError
- Add missing validation tests for name and args across LangGraph and
  CrewAI Python variants, plus AG-UI dispatch edge cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:22 +02:00
github-actions[bot] d5cc135c5c style: auto-fix formatting 2026-05-20 00:18:22 +02:00
Maxim 9cb8996056 fix(sdk): harden validation, error types, and dispatch safety across SDKs
Address code review findings: stop mislabeling dispatch errors as
CopilotKitMisuseError in JS (let them propagate naturally), add
CopilotKitMisuseError(ValueError) to Python SDK, pre-serialize args
in AG-UI handler to prevent partial event emission, align whitespace
validation across all SDKs and the dispatch layer, tighten JS args
type to Record<string, unknown>, and add comprehensive negative tests
for AG-UI dispatch validation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:21 +02:00
github-actions[bot] 6fb417a90a style: auto-fix formatting 2026-05-20 00:18:21 +02:00
Maxim 50301b7bf0 fix(sdk): restore error type, rename options.id, add validation parity
- Restore CopilotKitMisuseError for dispatch failures in JS (was bare Error)
- Rename JS options.id to options.toolCallId for cross-SDK naming parity
- Add name/args validation to Python LangGraph and CrewAI variants
- Add defensive field validation in AG-UI dispatch handler
- Add missing CrewAI whitespace-only ID test
- Add JS dispatch failure test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:21 +02:00
Maxim 09ede29d58 fix(sdk): align whitespace validation, improve error handling and docs
Align JS whitespace-only ID rejection with Python (.trim()), show
returned ID in docstring examples, strengthen CrewAI test assertions
to verify event payloads structurally, and stop miscategorizing
dispatch errors as CopilotKitMisuseError (preserve original stack).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:20 +02:00
Maxim c7693e938e fix(sdk): validate id param, rename to tool_call_id, use options bag in JS
Address review feedback on copilotkit_emit_tool_call:
- Add non-empty string validation for the tool call ID in all 3 SDKs
- Rename Python `id` param to `tool_call_id` to avoid shadowing the builtin
- Refactor JS 4th positional arg to options bag `{ id?: string }` for extensibility
- Document that the ID is also used as parentMessageId in AG-UI events
- Add JS tests for the new parameter (generated ID, custom ID, validation)
- Add Python validation tests (empty string, whitespace rejection)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:20 +02:00
Maxim 865991b463 feat(sdk): add optional id parameter to copilotkit_emit_tool_call
Allow callers to supply a custom tool call ID for correlation,
idempotency, and observability. Falls back to uuid4 when omitted.
Applied consistently across Python LangGraph, Python CrewAI, and JS SDK.
Also returns the tool call ID from all variants for downstream reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 00:18:19 +02:00
Jordan Ritter 2482317ccc style: apply ruff format to Python codebase
320 files reformatted. One-time alignment to match the ruff format
check added to CI in #4812.
2026-05-13 23:10:35 -07:00
Jordan Ritter a260ffe106 feat: widen header forwarding from x-aimock-* to all x-* headers
Matches the CopilotKit runtime's extractForwardableHeaders() which
already forwards all x-* prefixed headers. Enables any custom
x-* header to propagate from browser through AG-UI to LLM calls.
2026-05-11 20:55:33 -07:00
Jordan Ritter fce31b5079 feat(sdk-python): add header propagation for X-AIMock-Strict
ContextVar-based ambient state + httpx event hook. Incoming
x-aimock-* headers from AG-UI requests are forwarded to outgoing
LLM API calls. Keys normalized to lowercase. Warning emitted when
install_httpx_hook receives an unrecognized client type.
2026-05-11 13:36:55 -07:00
Ran Shem Tov 6c14258a39 feat(langgraph): add state injection to copilotkit middleware 2026-04-28 13:24:41 +02:00
Max Korp bec1fd0811 fix(a2ui): document id="root" entry-point requirement in generation guidelines
The A2UI React renderer (packages/a2ui-renderer/src/react-renderer/a2ui-react/A2uiSurface.tsx:152)
always begins rendering at the component with id="root":

    export const A2uiSurface: React.FC<{...}> = ({ surface }) => {
      // The root component always has ID 'root' and base path '/'
      return <DeferredChild surface={surface} id="root" basePath="/" />;
    };

If no component has that ID, DeferredChild falls through to its loading-
shimmer placeholder, so the surface silently renders as an empty ~30px
rectangle regardless of how many other components are on the surface.

The generation guidelines shipped to the sub-LLM (in @copilotkit/shared
and copilotkit sdk-python) never stated this requirement. Fixed-schema
demos hard-code a component with id="root" in their JSON and work; dynamic
demos relied on the LLM guessing, which it sometimes did and sometimes
didn't. The failure mode is particularly nasty: no error, no warning,
just a loading spinner that never resolves.

Adds the requirement to COMPONENT ID RULES in both the TS and Python
guideline strings. Both strings are injected into the sub-LLM's context
by A2UICatalogContext (packages/react-core) and
copilotkit.a2ui.a2ui_prompt() respectively, so every A2UI-enabled app
picks it up automatically — no per-demo change needed.

Stacked on #4216, which restores the same instruction to the
langgraph-python-threads demo's tool docstring (belt-and-braces until
consumers update their shared package version).
2026-04-23 13:21:07 -07:00
Martha Schumann 66c6af5c41 fix(sdk-python): restore json import dropped by main merge
Our branch commit 506a1e8e9 removed the unused 'import json' from
copilotkit/langgraph.py. Main PR #3784 subsequently added a dict-resume
path in copilotkit_interrupt that calls json.dumps(response) and re-added
the import.

The 3-way merge had no textual conflict (the lines around the import
didn't change on both sides), so git silently took our "delete" over
main's "unchanged." Result: json.dumps() called with json undefined.

Verified: sdk-python test suite now 74/74 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:53:46 -07:00
Martha Schumann 96e8112039 Merge remote-tracking branch 'origin/main' into claude/langgraph-tests-cleanup-1jVZ3 2026-04-22 09:48:55 -07:00
Alem Tuzlak 35a68aea90 Merge remote-tracking branch 'origin/main' into fix/crewai-import-compat-3268
# Conflicts:
#	sdk-python/pyproject.toml
2026-04-22 14:36:35 +02:00
Alem Tuzlak 3f6c80d8a0 Merge branch 'main' into fix/issue-2921 2026-04-22 12:59:18 +02:00
Alem Tuzlak ae1219455a Merge branch 'main' into fix/crewai-import-compat-3268 2026-04-22 12:58:24 +02:00
Alem Tuzlak b8349d2067 fix(sdk-python): copilotkit_interrupt handles non-list resume values (#3096) (#3784)
## Summary
- `copilotkit_interrupt` now handles string and dict resume values from
LangGraph 1.x's `interrupt()`
- Previously crashed with `AttributeError: 'str' object has no attribute
'content'` or `KeyError: -1`
- Type-checks response: str returned directly, dict JSON-serialized,
list uses existing `[-1].content` path

## Test plan
- [x] Red-green test: string resume value returns without crash
- [x] Red-green test: dict resume value returns JSON string
- [x] Test: list resume value still works (existing behavior)
- [x] Full test suite passes (15/15)

Closes #3096
2026-04-22 12:33:27 +02:00
Alem Tuzlak d6ff5772ed fix(sdk-python): LangGraphAGUIAgent serializes Context objects to dicts (#3690) (#3787)
## Summary
- `LangGraphAGUIAgent.langgraph_default_merge_state` now calls
`model_dump()` on Pydantic Context objects before storing in copilotkit
state
- Previously stored raw Pydantic objects, causing JSON serialization
failures downstream
- Handles mixed types: Pydantic objects get `model_dump()`, plain dicts
pass through unchanged
- Matches the existing pattern already used in `CopilotKitMiddleware`

## Test plan
- [x] Red-green test: AG-UI Context objects stored as plain dicts, not
Pydantic
- [x] Red-green test: mixed Pydantic + dict context items all
serializable
- [x] Full test suite passes (15/15)

Closes #3690
2026-04-22 12:33:14 +02:00
Alem Tuzlak 95fe4889b6 Merge remote-tracking branch 'origin/main' into fix/crewai-import-compat-3268
# Conflicts:
#	sdk-python/pyproject.toml
2026-04-22 12:26:49 +02:00
Martha Schumann 0e77affe14 Merge main: remove langgraph_agent.py (deprecated), resolve lock conflict
- Keep deletion of sdk-python/copilotkit/langgraph_agent.py (deprecated LangGraphAgent
  removed in this PR; main's unrelated bug fixes are superseded by our removal)
- Resolve poetry.lock conflict by taking main's ag_ui_langgraph 0.0.33

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 12:10:19 -07:00
Maxim 85dbf25c74 Merge branch 'main' into fix/always-emit-assistant-message 2026-04-17 14:42:22 +02:00
Markus Ecker 0f02aae198 fix: align A2UI schema format with v0.9 spec and improve path binding prompts
- Replace custom { name, props } schema format with spec-aligned inline
  catalog format (allOf + properties) so the LLM sees the same flat
  structure it must produce — eliminates "props" nesting confusion.
- Restructure generation prompts: inline literal values are the default,
  path binding is a narrow schema-driven exception for form inputs.
- Export InlineCatalogSchema type from a2ui-renderer.
2026-04-15 12:28:13 +02:00