Skip to content

Commit 5d1a55e

Browse files
committed
fix(showcase/langgraph-python): close remaining D5 cells (framework + fixtures)
Lands the Bucket A framework fix and the fixture-correctness changes needed to flip the remaining D4/D2 cells in the langgraph-python column to D5. Full local D5 sweep is green (1 passed, 0 failed). Framework: every Python `ToolMessage` constructed via `Command(update=...)` now sets `name=` and `id=str(uuid.uuid4())`. Without these, @ag-ui/langgraph synthesises TOOL_CALL_START events with `toolCallName: null` and `parentMessageId: null`, which @ag-ui/client@0.0.53's Zod schema rejects; the rejection is silently swallowed by `withAbortErrorHandling -> EMPTY`, completing the SSE observable mid-stream so post-tool state never reaches the consumer. Fix is applied across shared_state_streaming, shared_state_read_write, gen_ui_agent, beautiful_chat, subagents (2 sites). Single-flag change in a2ui_dynamic flips the secondary `_design_a2ui_surface` LLM call to `streaming=True` so aimock's record/replay (SSE-only) sees it. Fixtures (d5-all.json): - toolCallId follow-ups for set_steps (3), display_flight, generate_a2ui (4), schedule_meeting (2), generateSandboxedUi (7), and revenue chart so multi-turn probes don't recurse into recursion-limit loops - four hand-crafted secondary `_design_a2ui_surface` fixtures so A2UI dynamic renders without a real LLM - mcp-apps fixture rewritten to emit `create_view` tool call with a minimal Excalidraw element payload; runtime middleware fetches the UI resource and the iframe mounts - AAPL and revenue `hasToolResult: true` follow-ups tightened to `toolCallId` so they don't match cross-turn after prior turns' tool results - voice fast-path content-only fixture - beautiful-chat-schedule-meeting first-turn fixture gains content so the conversation runner sees an assistant message before the picker click assertion Probes: bumped per-card waitForSelector in d5-gen-ui-headless-complete from 15s to 60s — recharts ResponsiveContainer can be slow under 4 sequential turns. Shell-dojo: hide CLI Start Command from the dojo navigation via `HIDDEN_DOJO_FEATURE_IDS`. Registry/manifests untouched so harness/parity/dashboard still see it.
1 parent af9fbd5 commit 5d1a55e

10 files changed

Lines changed: 288 additions & 25 deletions

File tree

showcase/aimock/d5-all.json

Lines changed: 247 additions & 19 deletions
Large diffs are not rendered by default.

showcase/harness/fixtures/d5/beautiful-chat-schedule-meeting.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"hasToolResult": false
88
},
99
"response": {
10+
"content": "Sure — pulling up a 30-minute slot.",
1011
"toolCalls": [
1112
{
1213
"id": "call_d5_bc_schedule_time_001",

showcase/harness/src/probes/scripts/d5-gen-ui-headless-complete.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,11 @@ export function buildTurns(_ctx: D5BuildContext): ConversationTurn[] {
199199
try {
200200
await page.waitForSelector(exp.cardSelector, {
201201
state: "visible",
202-
timeout: 15_000,
202+
timeout: 60_000,
203203
});
204204
} catch {
205205
throw new Error(
206-
`gen-ui-headless-complete ${exp.chipMatchAliases.join("|")}: expected ${exp.cardSelector} to mount within 15s — tool result may not have landed or the renderer wiring drifted`,
206+
`gen-ui-headless-complete ${exp.chipMatchAliases.join("|")}: expected ${exp.cardSelector} to mount within 60s — tool result may not have landed or the renderer wiring drifted`,
207207
);
208208
}
209209
const text = await readAllAssistantText(page);

showcase/integrations/langgraph-python/src/agents/a2ui_dynamic.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ def generate_a2ui(runtime: ToolRuntime[Any]) -> str:
111111

112112
prompt = f"{_GENERATE_A2UI_PROMPT_HEADER}\n\n{context_text}".strip()
113113

114-
model = ChatOpenAI(model="gpt-4.1")
114+
# `streaming=True` so aimock's record/replay (which only intercepts
115+
# SSE streams) sees this secondary LLM call. Without it the call
116+
# bypasses fixture matching in replay mode, surfacing as
117+
# "An internal error occurred" on the demo page.
118+
model = ChatOpenAI(model="gpt-4.1", streaming=True)
115119
model_with_tool = model.bind_tools(
116120
[_design_a2ui_surface],
117121
tool_choice="_design_a2ui_surface",

showcase/integrations/langgraph-python/src/agents/beautiful_chat.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ def manage_todos(todos: list[Todo], runtime: ToolRuntime) -> Command:
6666
"messages": [
6767
ToolMessage(
6868
content="Successfully updated todos",
69+
name="manage_todos",
70+
id=str(uuid.uuid4()),
6971
tool_call_id=runtime.tool_call_id
7072
)
7173
]

showcase/integrations/langgraph-python/src/agents/gen_ui_agent.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from __future__ import annotations
1919

20+
import uuid
2021
from typing import Annotated, Any, Literal
2122

2223
from copilotkit import CopilotKitMiddleware
@@ -57,7 +58,10 @@ def set_steps(
5758
"steps": steps,
5859
"messages": [
5960
ToolMessage(
60-
f"Published {len(steps)} step(s).", tool_call_id=tool_call_id
61+
f"Published {len(steps)} step(s).",
62+
name="set_steps",
63+
id=str(uuid.uuid4()),
64+
tool_call_id=tool_call_id,
6165
)
6266
],
6367
}

showcase/integrations/langgraph-python/src/agents/shared_state_read_write.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
state: frontend writes, backend reads AND writes, frontend re-renders.
1616
"""
1717

18+
import uuid
1819
from typing import Any, Awaitable, Callable, TypedDict
1920

2021
from langchain.agents import AgentState as BaseAgentState, create_agent
@@ -65,6 +66,8 @@ def set_notes(notes: list[str], runtime: ToolRuntime) -> Command:
6566
"messages": [
6667
ToolMessage(
6768
content="Notes updated.",
69+
name="set_notes",
70+
id=str(uuid.uuid4()),
6871
tool_call_id=runtime.tool_call_id,
6972
)
7073
],

showcase/integrations/langgraph-python/src/agents/shared_state_streaming.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
docs.copilotkit.ai/integrations/langgraph/shared-state/predictive-state-updates
1313
"""
1414

15+
import uuid
16+
1517
from langchain.agents import AgentState as BaseAgentState, create_agent
1618
from langchain.tools import ToolRuntime, tool
1719
from langchain_core.messages import ToolMessage
@@ -47,6 +49,8 @@ def write_document(document: str, runtime: ToolRuntime) -> Command:
4749
"messages": [
4850
ToolMessage(
4951
content="Document written to shared state.",
52+
name="write_document",
53+
id=str(uuid.uuid4()),
5054
tool_call_id=runtime.tool_call_id,
5155
)
5256
],

showcase/integrations/langgraph-python/src/agents/subagents.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ def _delegation_update(
181181
"messages": [
182182
ToolMessage(
183183
content=result,
184+
name=sub_agent,
185+
id=str(uuid.uuid4()),
184186
tool_call_id=tool_call_id,
185187
)
186188
],
@@ -257,6 +259,8 @@ def critique_agent(task: str, runtime: ToolRuntime) -> Command:
257259
"messages": [
258260
ToolMessage(
259261
content=skip_message,
262+
name="critique_agent",
263+
id=str(uuid.uuid4()),
260264
tool_call_id=runtime.tool_call_id,
261265
)
262266
],

showcase/shell-dojo/src/lib/registry.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,29 @@ export interface Registry {
4949

5050
const registry = registryData as Registry;
5151

52+
// Hide registry entries with no dojo route. Kept in the registry so
53+
// harness/parity/dashboard still see them.
54+
const HIDDEN_DOJO_FEATURE_IDS = new Set<string>(["cli-start"]);
55+
56+
function withVisibleDemos(integration: Integration): Integration {
57+
const visible = integration.demos.filter(
58+
(d) => !HIDDEN_DOJO_FEATURE_IDS.has(d.id),
59+
);
60+
if (visible.length === integration.demos.length) return integration;
61+
return { ...integration, demos: visible };
62+
}
63+
5264
export function getRegistry(): Registry {
5365
return registry;
5466
}
5567

5668
export function getIntegrations(): Integration[] {
57-
return registry.integrations;
69+
return registry.integrations.map(withVisibleDemos);
5870
}
5971

6072
export function getIntegration(slug: string): Integration | undefined {
61-
return registry.integrations.find((i) => i.slug === slug);
73+
const found = registry.integrations.find((i) => i.slug === slug);
74+
return found ? withVisibleDemos(found) : undefined;
6275
}
6376

6477
export function getFeatures(): Feature[] {

0 commit comments

Comments
 (0)