The 315-case language-neutral corpus was only ever *validated* in TypeScript.
`sdk-python/tests/test_intelligence.py` and `IntelligenceClientTests.cs` read it
solely to extract the canonical error-code enums, so every declarative
assertion was unenforced outside TypeScript. Measured: 112 of the corpus's
negative cases are accepted by a vanilla Draft 2020-12 validator and are
enforceable only through `x-copilotkit-equal-properties` and
`x-copilotkit-assertions`, which existed in TypeScript alone.
Adds portable validators to both SDKs, peers of
`packages/intelligence/src/portable-validator.ts`, covering the Draft 2020-12
subset the corpus uses plus both custom keywords and all fifteen assertion
operations (compare, compare-values, unique, all-equal, strictly-increasing,
contiguous, values-in-range, references, disjoint, ordered-ranges, lookup-equal,
lookup-references, count, utf8-byte-length, bounded-json) with their
`caseFold`/`unicode` normalization, `where` predicates, and bounds. Both consume
the same corpus JSON with no per-language restatement of any rule, and both
reuse their language's single case-folding definition site.
Two properties keep the three implementations honest:
- Unknown schema keywords and unknown assertion operations are hard errors, not
ignored annotations, so a future corpus keyword fails loudly instead of
silently under-enforcing.
- ECMAScript `pattern` values are translated into each host dialect explicitly.
Untranslated, `$` would also match before a trailing newline and `\d` would
match non-ASCII digits in both Python and .NET, accepting strings the
TypeScript reference validator rejects.
All 315 cases now pass in all three languages, each suite independently
re-measures the 112 figure as a regression guard, and the Python suite asserts
that every corpus assertion operation decides at least one case.
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>
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.
Ran confirmed LangGraphAGUIAgent is the only relevant path going forward.
Removes LangGraphAgent, _StreamingStateExtractor, CopilotKitConfig, and
langgraph_default_merge_state from sdk-python (the AG-UI base class
provides this now). Also removes the use_function_call=True code path
from copilotkit_messages_to_langchain (no callers, function_call format
is obsolete).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>