forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreasoning_agent.py
More file actions
95 lines (82 loc) · 3.38 KB
/
Copy pathreasoning_agent.py
File metadata and controls
95 lines (82 loc) · 3.38 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
"""
MS Agent Framework — reasoning demo agent.
Shared by two demos:
- agentic-chat-reasoning — custom rendered reasoning block
- reasoning-default-render — default rendering of reasoning content
Approach
--------
The LangGraph reference agent relies on AG-UI REASONING_MESSAGE_* events, which
CopilotKit renders natively via `CopilotChatReasoningMessage`. The MS Agent
Framework's current AG-UI bridge does not surface reasoning tokens as
first-class REASONING_MESSAGE events, so we fall back to the closest portable
pattern: a `think` tool.
Flow:
1. The agent MUST call `think(thought=...)` before producing its final
answer. Its `thought` field contains the step-by-step reasoning.
2. The frontend renders the tool call with `useRenderTool("think", ...)` as
a visible reasoning block (custom or default style, per demo).
3. The agent then produces a concise final answer as a normal assistant
message.
"""
from __future__ import annotations
from textwrap import dedent
from typing import Annotated
from agent_framework import Agent, BaseChatClient, tool
from agent_framework_ag_ui import AgentFrameworkAgent
from pydantic import Field
@tool(
name="think",
description=(
"Record a step-by-step reasoning trace that the UI will render as a "
"visible thinking block. Always call this tool BEFORE answering the "
"user's question. Use a single call per user turn."
),
)
def think(
thought: Annotated[
str,
Field(
description=(
"A concise, step-by-step reasoning chain leading toward the "
"final answer. Write in first person (e.g., 'First I'll..., "
"then I'll...'). Keep it under ~5 short steps."
)
),
],
) -> str:
"""Accept the reasoning; the UI displays it as a thinking block."""
# The tool body is intentionally trivial: the useful payload is `thought`,
# which the frontend receives via the tool-call args (rendered live).
return "Reasoning recorded."
def create_reasoning_agent(chat_client: BaseChatClient) -> AgentFrameworkAgent:
"""Create the MS Agent Framework reasoning demo agent."""
base_agent = Agent(
client=chat_client,
name="reasoning_agent",
instructions=dedent(
"""
You are a helpful assistant that shows its work.
Required workflow for EVERY user question:
1. Call the `think` tool exactly once with a concise,
step-by-step reasoning chain describing how you will
approach the answer.
2. After the tool call returns, produce a clear, concise
final assistant message with the actual answer.
Rules:
- You MUST call `think` before your final answer. Never skip it.
- Keep the `thought` focused on reasoning, not the final answer.
- Keep the final answer short (1-3 short paragraphs).
- Do NOT repeat the reasoning in the final answer; just give
the user the conclusion.
""".strip()
),
tools=[think],
)
return AgentFrameworkAgent(
agent=base_agent,
name="CopilotKitMicrosoftAgentFrameworkReasoningAgent",
description=(
"Demonstrates a visible reasoning chain via the `think` tool."
),
require_confirmation=False,
)