Commit Graph

11 Commits

Author SHA1 Message Date
Martha Schumann 981734fb99 fix: propagate useCopilotReadable context and CopilotKit properties into Python LangGraph agent state
Two silent failures in the Python SDK prevented frontend context from reaching the agent:

1. langgraph_default_merge_state rebuilt copilotkit as {actions} only, dropping the
   useCopilotReadable items the TypeScript runtime had placed in state.copilotkit.context.
2. CopilotKitContext.properties were never forwarded through execute_agent → agent.execute(),
   so <CopilotKit properties={...} /> values never reached state.copilotkit.properties.

Both fields now land cleanly under state["copilotkit"] on every agent invocation.
Also adds tests, a showcase example, and a new docs page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 18:37:51 -07:00
Jordan Ritter de78dfdb68 fix: sanitize NaN/Infinity values in LangGraph state before JSON serialization (#3851)
## Summary
- Add sanitization pass over LangGraph agent state to replace NaN and
Infinity with null before JSON serialization
- Prevents `ValueError: Out of range float values are not JSON
compliant` in Python SDK

Closes #1955

---
*Split from #3847*
2026-04-14 14:06:07 -07:00
Jordan Ritter fe365d3f7f fix: extract all text parts when AIMessage content is a list (#3844)
Partially addresses #1748

When Anthropic models return multi-part content lists, only the first
element was used and the rest discarded. Now iterates all parts and
concatenates text blocks, preserving the full message content.

Split from #3838.
2026-04-14 14:06:04 -07:00
Jordan Ritter 76b1d73bb8 fix: convert Pydantic BaseModel instances to dicts before serialization (#2158) (#3816)
## Summary

Fixes #2158

Pydantic `BaseModel` instances in LangGraph agent state are not
serializable by `langchain_dumps`. This adds a recursive
`_serialize_state` helper that converts `BaseModel` instances to dicts
before serialization, preventing crashes when state contains Pydantic
models.

**Additional fixes (second commit):**
- Also applies `_serialize_state` to the `get_state()` code path, which
was missed in the original fix but has the same bug
- Fixes `filter_state_on_schema_keys` returning `None` implicitly when
schema keys are not set (the `except` branch returned `state` but the
non-matching `if` branch did not)
- Adds 17 tests covering `_serialize_state`, `_emit_state_sync_event`,
and `get_state` with Pydantic models

## Merge order note

This PR and #3851 both modify
`sdk-python/copilotkit/langgraph_agent.py`. Both add a helper function
at module level and call it from `_emit_state_sync_event` and
`get_state`. Whichever merges second will need a trivial rebase. No
semantic conflict — the fixes are complementary (this one handles
Pydantic models, #3851 handles NaN/Infinity).

## Test plan

- [x] 17 unit tests covering both code paths
- [x] Red-green verified: `get_state` tests fail without fix, pass with
it
- [x] Existing test suite (test_emit_filtering) still passes
- [x] Verify LangGraph agent with Pydantic BaseModel state serializes
correctly
- [x] Verify non-Pydantic state is unaffected
2026-04-14 14:06:00 -07:00
Jordan Ritter 6d9efa00a9 test: add comprehensive tests for _sanitize_for_json
27 tests covering:
- Passthrough of valid types (floats, ints, strings, booleans, None)
- NaN and +/-Infinity replacement with None
- Recursive sanitization through dicts, lists, and tuples
- Real-world event structures (on_chain_end, streaming chunks, state sync)
2026-04-13 08:30:07 -07:00
Jordan Ritter e76b7f435e test(sdk-python): replace mock test with integration tests for emit_state merge
The original test only tested the _merge_emit_state helper in isolation
using mocks. Replace with integration tests that simulate the actual
state-tracking loop from _stream_events, including:

- Sequential emits with different keys preserve all keys (core bug)
- Proof that the bug manifests without current_graph_state.update
- Three sequential emits accumulate correctly
- Same key emitted twice uses latest value
- Non-dict emit does not corrupt current_graph_state
- Initial state reference is not mutated
2026-04-13 08:29:15 -07:00
Jordan Ritter a559406bee fix: also serialize Pydantic state in get_state() and fix implicit None return
The original fix only covered _emit_state_sync_event but missed the
get_state() code path, which also returns state containing Pydantic
BaseModel instances to callers that will JSON-serialize downstream.

Also fixes filter_state_on_schema_keys returning None implicitly when
schema keys are not set (the except branch returned state but the
non-matching if branch did not).

Adds 17 tests covering _serialize_state, _emit_state_sync_event, and
get_state with Pydantic models (nested, lists, plain dicts, empty).
2026-04-13 08:24:10 -07:00
Jordan Ritter 2e92fe1bff test: add tests for multi-part AIMessage content extraction
Verifies langchain_messages_to_copilotkit correctly concatenates all text
parts from list-style content blocks (Anthropic models). Includes
regression tests for the exact scenario from #1748 (text + image blocks)
and tests for string lists, mixed content, empty lists, and edge cases.
2026-04-13 08:19:29 -07:00
Jordan Ritter ee9e9c37b8 fix(sdk-python): copilotkit_emit_state merges state instead of replacing (#3138)
Sequential emit_state calls with different keys now preserve all keys
in the snapshot. Previously, each call would replace the entire
manually_emitted_state, losing keys from earlier calls.
2026-04-12 13:21:53 -07:00
Jordan Ritter 8bad9f30ac test: add unit tests for emit_messages/emit_tool_calls filtering
Tests the two bugs fixed in this PR:
1. Dict raw_event metadata must be read with .get(), not getattr()
2. Filtered events must return None (not ""), and run() strips them

Adds pytest as a dev dependency.
2026-03-06 08:32:06 -08:00
Ariel Weinberger cd8ff1bdc6 feat(python-sdk): add to monorepo (#908) 2024-11-12 18:59:33 -06:00