forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patha2ui_fixed.py
More file actions
101 lines (83 loc) · 3.69 KB
/
Copy patha2ui_fixed.py
File metadata and controls
101 lines (83 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""
LangGraph agent for the Declarative Generative UI (A2UI — Fixed Schema) demo.
Fixed-schema A2UI: the component tree (schema) is authored ahead of time as
JSON and loaded at startup via `a2ui.load_schema(...)`. The agent only
streams *data* into the data model at runtime. The frontend registers a
matching catalog (see `src/app/demos/a2ui-fixed-schema/a2ui/catalog.ts`)
that pins the schema's component names to real React implementations.
Reference:
examples/integrations/langgraph-python/agent/src/a2ui_fixed_schema.py
"""
# @region[backend-render-operations]
# @region[backend-schema-json-load]
from __future__ import annotations
from pathlib import Path
from typing import TypedDict
from copilotkit import CopilotKitMiddleware, a2ui
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_openai import ChatOpenAI
CATALOG_ID = "copilotkit://flight-fixed-catalog"
SURFACE_ID = "flight-fixed-schema"
_SCHEMAS_DIR = Path(__file__).parent / "a2ui_schemas"
# The schema is JSON so it can be authored and reviewed independently of the
# Python code. `a2ui.load_schema` is just a thin `json.load` wrapper.
FLIGHT_SCHEMA = a2ui.load_schema(_SCHEMAS_DIR / "flight_schema.json")
# @endregion[backend-schema-json-load]
class Flight(TypedDict):
"""Shape the LLM should fill in when calling `display_flight`.
LangGraph serializes this TypedDict into the tool's JSON schema, so
defining it narrowly is how we steer the LLM to produce data that fits
the frontend `FlightCard` component's props.
"""
origin: str
destination: str
airline: str
price: str
@tool
def display_flight(origin: str, destination: str, airline: str, price: str) -> str:
"""Show a flight card for the given trip.
Use short airport codes (e.g. "SFO", "JFK") for origin/destination and a
price string like "$289".
After this tool returns, the flight card is already rendered to the user
via the A2UI surface — the JSON returned here is the surface descriptor
the renderer consumes, NOT a status code. Do NOT call this tool again
for the same flight (the user already sees the card). Reply with one
short confirmation sentence and stop.
"""
# The A2UI middleware detects the `a2ui_operations` container in this
# tool result and forwards the ops to the frontend renderer. The frontend
# catalog resolves component names to the local React components.
#
# Note: schema-swap-on-action (e.g. swapping to a "booked" schema when
# the card's button is clicked) will be added once the Python SDK
# exposes `action_handlers=` on `a2ui.render`.
return a2ui.render(
operations=[
a2ui.create_surface(SURFACE_ID, catalog_id=CATALOG_ID),
a2ui.update_components(SURFACE_ID, FLIGHT_SCHEMA),
a2ui.update_data_model(
SURFACE_ID,
{
"origin": origin,
"destination": destination,
"airline": airline,
"price": price,
},
),
],
)
# @endregion[backend-render-operations]
graph = create_agent(
model=ChatOpenAI(model="gpt-5.4"),
tools=[display_flight],
middleware=[CopilotKitMiddleware()],
system_prompt=(
"You help users find flights. When asked about a flight, call "
"`display_flight` exactly ONCE with origin, destination, airline, "
"and price. The tool's JSON return value is an A2UI surface "
"descriptor — the flight card is already rendered to the user; do "
"NOT call `display_flight` again for the same trip. After the tool "
"returns, reply with one short confirmation sentence and stop."
),
)