forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtool_rendering_reasoning_chain_agent.py
More file actions
189 lines (167 loc) · 6.21 KB
/
Copy pathtool_rendering_reasoning_chain_agent.py
File metadata and controls
189 lines (167 loc) · 6.21 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
"""Tool Rendering (Reasoning Chain) agent for MS Agent Framework.
Backs the three tool-rendering showcase cells:
- tool-rendering-default-catchall (no frontend renderers)
- tool-rendering-custom-catchall (wildcard renderer on frontend)
- tool-rendering-reasoning-chain (per-tool + reasoning + catch-all)
The tools mirror the LangGraph `tool_rendering_agent` so the frontends
can be shared one-to-one with the LangGraph showcase. Each tool returns
a small JSON payload suitable for rich per-tool renderers on the
frontend.
"""
from __future__ import annotations
import json
import os
from random import choice, randint
from textwrap import dedent
from typing import Annotated
from agent_framework import Agent, BaseChatClient, tool
from agent_framework.openai import OpenAIChatClient
from agent_framework_ag_ui import AgentFrameworkAgent
from pydantic import Field
@tool(
name="get_weather",
description=(
"Get the current weather for a given location. Useful on its "
"own for weather questions, and a great companion to "
"search_flights."
),
)
def get_weather(
location: Annotated[str, Field(description="The city or region to describe.")],
) -> str:
"""Return mock weather data as JSON."""
return json.dumps(
{
"city": location,
"temperature": 68,
"humidity": 55,
"wind_speed": 10,
"conditions": "Sunny",
}
)
@tool(
name="search_flights",
description=(
"Search mock flights from an origin airport to a destination "
"airport. Pairs naturally with get_weather: after searching "
"flights, check the weather at the destination."
),
)
def search_flights(
origin: Annotated[str, Field(description="Origin airport code, e.g. SFO.")],
destination: Annotated[str, Field(description="Destination airport code, e.g. JFK.")],
) -> str:
"""Return mock flight search results as JSON."""
return json.dumps(
{
"origin": origin,
"destination": destination,
"flights": [
{
"airline": "United",
"flight": "UA231",
"depart": "08:15",
"arrive": "16:45",
"price_usd": 348,
},
{
"airline": "Delta",
"flight": "DL412",
"depart": "11:20",
"arrive": "19:55",
"price_usd": 312,
},
{
"airline": "JetBlue",
"flight": "B6722",
"depart": "17:05",
"arrive": "01:30",
"price_usd": 289,
},
],
}
)
@tool(
name="get_stock_price",
description=(
"Get a mock current price for a stock ticker. When the user "
"asks about one ticker, consider pulling a related ticker for "
"comparison."
),
)
def get_stock_price(
ticker: Annotated[str, Field(description="Stock ticker symbol, e.g. AAPL.")],
) -> str:
"""Return mock stock price data as JSON."""
return json.dumps(
{
"ticker": ticker.upper(),
"price_usd": round(100 + randint(0, 400) + randint(0, 99) / 100, 2),
"change_pct": round(choice([-1, 1]) * (randint(0, 300) / 100), 2),
}
)
@tool(
name="roll_dice",
description=(
"Roll a single die with the given number of sides. Consider "
"rolling twice with different sides so the reply can show a "
"contrast."
),
)
def roll_dice(
sides: Annotated[int, Field(description="Number of sides on the die.")] = 6,
) -> str:
"""Return a mock dice roll as JSON."""
return json.dumps({"sides": sides, "result": randint(1, max(2, sides))})
SYSTEM_PROMPT = dedent(
"""
You are a helpful travel & lifestyle concierge. You have mock tools
for weather, flights, stock prices, and dice rolls — they all return
fake data, so call them liberally.
Your habit is to CHAIN tools when one answer naturally invites
another. For a single user question, call at least TWO tools in
succession when the topic allows before composing your final reply.
Examples of helpful chains you should default to:
- "What's the weather in Tokyo?" -> call get_weather("Tokyo"), then
call search_flights(origin="SFO", destination="Tokyo") so the user
also sees how to get there.
- "How is AAPL doing?" -> call get_stock_price("AAPL"), then call
get_stock_price on a related ticker (e.g. "MSFT" or "GOOGL") for
comparison.
- "Roll a d20" -> call roll_dice(20), then call roll_dice again with
a different number of sides so the user sees a contrast.
- "Find flights from SFO to JFK" -> call search_flights, then call
get_weather on the destination city.
Between tool calls, briefly narrate your reasoning so the user can
follow along. Only skip chaining when the user has clearly asked for
a single, atomic answer. Never fabricate data that a tool could
provide.
"""
).strip()
def create_tool_rendering_reasoning_chain_agent(
chat_client: BaseChatClient,
) -> AgentFrameworkAgent:
"""Instantiate the tool-rendering reasoning-chain demo agent."""
base_agent = Agent(
client=chat_client,
name="tool_rendering_reasoning_chain_agent",
instructions=SYSTEM_PROMPT,
tools=[get_weather, search_flights, get_stock_price, roll_dice],
)
return AgentFrameworkAgent(
agent=base_agent,
name="ToolRenderingReasoningChainAgent",
description=(
"Travel & lifestyle concierge that chains tool calls "
"(weather, flights, stocks, dice) for tool-rendering demos."
),
require_confirmation=False,
)
def build_default_chat_client() -> BaseChatClient:
"""Create a default OpenAI chat client from environment variables."""
if not os.getenv("OPENAI_API_KEY"):
raise ValueError("OPENAI_API_KEY environment variable is required")
return OpenAIChatClient(
model=os.getenv("OPENAI_CHAT_MODEL_ID", "gpt-4o-mini"),
api_key=os.getenv("OPENAI_API_KEY"),
)