This commit is contained in:
parent
5abfc83d4c
commit
714675cf5b
|
|
@ -396,7 +396,7 @@ def thinking(item: MessageHistoryItem) -> rx.Component:
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.cond(
|
rx.cond(
|
||||||
item.is_shown,
|
item.is_shown,
|
||||||
rx.text(
|
rx.markdown(
|
||||||
item.content,
|
item.content,
|
||||||
width="100%",
|
width="100%",
|
||||||
margin="4px 0",
|
margin="4px 0",
|
||||||
|
|
@ -418,6 +418,43 @@ def thinking(item: MessageHistoryItem) -> rx.Component:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def tool_call(item: MessageHistoryItem) -> rx.Component:
|
||||||
|
"""
|
||||||
|
工具调用
|
||||||
|
:return: Component
|
||||||
|
"""
|
||||||
|
return rx.vstack(
|
||||||
|
# 工具调用的标题栏
|
||||||
|
rx.hstack(
|
||||||
|
rx.icon(
|
||||||
|
"square-function",
|
||||||
|
width="14px",
|
||||||
|
height="14px",
|
||||||
|
color="var(--prismui-color-3)",
|
||||||
|
),
|
||||||
|
rx.text(
|
||||||
|
item.title,
|
||||||
|
font_size="var(--prismui-font-size-1)",
|
||||||
|
color="var(--prismui-color-3)",
|
||||||
|
class_name=rx.cond(item.is_running, "is_running", None),
|
||||||
|
),
|
||||||
|
align_items="center",
|
||||||
|
gap="4px",
|
||||||
|
margin_bottom="8px",
|
||||||
|
line_height="22px",
|
||||||
|
),
|
||||||
|
# 工具调用的内容
|
||||||
|
rx.markdown(
|
||||||
|
item.content,
|
||||||
|
width="100%",
|
||||||
|
margin="4px 0",
|
||||||
|
line_height="1.6",
|
||||||
|
font_size="var(--prismui-font-size-1)",
|
||||||
|
color="var(--prismui-color-3)",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def output(item: MessageHistoryItem) -> rx.Component:
|
def output(item: MessageHistoryItem) -> rx.Component:
|
||||||
"""
|
"""
|
||||||
输出
|
输出
|
||||||
|
|
@ -432,7 +469,6 @@ def output(item: MessageHistoryItem) -> rx.Component:
|
||||||
line_height="1.75",
|
line_height="1.75",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
|
||||||
),
|
),
|
||||||
"strong": lambda text: rx.text(
|
"strong": lambda text: rx.text(
|
||||||
text,
|
text,
|
||||||
|
|
@ -454,7 +490,6 @@ def output(item: MessageHistoryItem) -> rx.Component:
|
||||||
font_weight="var(--prismui-font-weight-3)",
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
|
||||||
),
|
),
|
||||||
"h2": lambda text: rx.text(
|
"h2": lambda text: rx.text(
|
||||||
text,
|
text,
|
||||||
|
|
@ -464,7 +499,6 @@ def output(item: MessageHistoryItem) -> rx.Component:
|
||||||
font_weight="var(--prismui-font-weight-3)",
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
|
||||||
),
|
),
|
||||||
"h3": lambda text: rx.text(
|
"h3": lambda text: rx.text(
|
||||||
text,
|
text,
|
||||||
|
|
@ -473,7 +507,6 @@ def output(item: MessageHistoryItem) -> rx.Component:
|
||||||
font_weight="var(--prismui-font-weight-3)",
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
|
||||||
),
|
),
|
||||||
"ul": lambda children: rx.vstack(
|
"ul": lambda children: rx.vstack(
|
||||||
children,
|
children,
|
||||||
|
|
@ -500,7 +533,6 @@ def output(item: MessageHistoryItem) -> rx.Component:
|
||||||
line_height="1.75",
|
line_height="1.75",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
|
||||||
),
|
),
|
||||||
align_items="center",
|
align_items="center",
|
||||||
justify_content="flex-start",
|
justify_content="flex-start",
|
||||||
|
|
@ -535,6 +567,7 @@ def output(item: MessageHistoryItem) -> rx.Component:
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
width="100%",
|
width="100%",
|
||||||
|
margin_bottom="8px",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -550,6 +583,7 @@ def message_history_item(item: MessageHistoryItem) -> rx.Component:
|
||||||
item.type,
|
item.type,
|
||||||
(MessageType.USER_PROMPT, user_prompt(item)),
|
(MessageType.USER_PROMPT, user_prompt(item)),
|
||||||
(MessageType.THINKING, thinking(item)),
|
(MessageType.THINKING, thinking(item)),
|
||||||
|
(MessageType.TOOL_CALL, tool_call(item)),
|
||||||
(MessageType.OUTPUT, output(item)),
|
(MessageType.OUTPUT, output(item)),
|
||||||
),
|
),
|
||||||
padding="0 16px",
|
padding="0 16px",
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,7 @@ class ConversationState(rx.State):
|
||||||
|
|
||||||
# 运行并流式输出事件
|
# 运行并流式输出事件
|
||||||
stream_events = run_stream_events(
|
stream_events = run_stream_events(
|
||||||
deps=dict(conversation.workflow.deps),
|
deps=conversation.workflow.deps,
|
||||||
user_prompt=user_prompt,
|
user_prompt=user_prompt,
|
||||||
message_history=await db_state.get_message_history(
|
message_history=await db_state.get_message_history(
|
||||||
conversation_id=self.actived_conversation_id
|
conversation_id=self.actived_conversation_id
|
||||||
|
|
@ -348,6 +348,7 @@ class ConversationState(rx.State):
|
||||||
# 若等待流式输出则将等待流式输出设置为否
|
# 若等待流式输出则将等待流式输出设置为否
|
||||||
if conversation.awaiting_stream:
|
if conversation.awaiting_stream:
|
||||||
conversation.awaiting_stream = False
|
conversation.awaiting_stream = False
|
||||||
|
print(event)
|
||||||
match event:
|
match event:
|
||||||
# ========== 开始事件 ==========
|
# ========== 开始事件 ==========
|
||||||
case PartStartEvent(
|
case PartStartEvent(
|
||||||
|
|
@ -452,6 +453,8 @@ class ConversationState(rx.State):
|
||||||
message = conversation.messages[
|
message = conversation.messages[
|
||||||
tool_name_map_to_message_id[tool_name]
|
tool_name_map_to_message_id[tool_name]
|
||||||
]
|
]
|
||||||
|
message.is_running = False
|
||||||
|
yield # 通知前端更新渲染
|
||||||
message.title = f"{tool_name}已完成"
|
message.title = f"{tool_name}已完成"
|
||||||
message.content = cast(
|
message.content = cast(
|
||||||
str, content
|
str, content
|
||||||
|
|
@ -516,7 +519,7 @@ class ConversationState(rx.State):
|
||||||
workflow = Workflow(type=type, deps=deps)
|
workflow = Workflow(type=type, deps=deps)
|
||||||
# 设置用户提示词
|
# 设置用户提示词
|
||||||
self.set_user_prompt(
|
self.set_user_prompt(
|
||||||
f"帮我查询并预定在 {deps.date.strftime('%Y-%m-%d')} 从 {deps.origin_airport_code} 到 {deps.destination_airport_code} 的航班"
|
f"帮我查询并预定在 {workflow.deps.date.strftime('%Y-%m-%d')} 从 {workflow.deps.origin_airport_code} 到 {workflow.deps.destination_airport_code} 的航班"
|
||||||
)
|
)
|
||||||
|
|
||||||
conversation.workflow = workflow
|
conversation.workflow = workflow
|
||||||
|
|
|
||||||
|
|
@ -299,8 +299,8 @@ class DatabaseState(rx.State):
|
||||||
) # 将 RunUsage 序列化为 JSON 字符串
|
) # 将 RunUsage 序列化为 JSON 字符串
|
||||||
if isinstance(workflow, Workflow):
|
if isinstance(workflow, Workflow):
|
||||||
record.workflow = workflow_dump_json(
|
record.workflow = workflow_dump_json(
|
||||||
Workflow(**asdict(workflow))
|
Workflow(**workflow.model_dump(mode="json"))
|
||||||
) # 将 Workflow 序列化为 JSON 字符串
|
) # 将 Workflow 序列化为 JSON 字符串(因 workflow 基于 pydantic 建模,故使用 model_dump 方法转为字典)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
async def create_message_record(
|
async def create_message_record(
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ async def search_flights(ctx: RunContext[Deps]) -> list[Flight]:
|
||||||
return searched_flights
|
return searched_flights
|
||||||
|
|
||||||
|
|
||||||
@agent.tool(name="预定航班", requires_approval=True)
|
@agent.tool(name="预定航班")
|
||||||
async def book_flight(ctx: RunContext[Deps]) -> Flight | NoResult:
|
async def book_flight(ctx: RunContext[Deps]) -> Flight | NoResult:
|
||||||
"""
|
"""
|
||||||
预定航班
|
预定航班
|
||||||
|
|
@ -211,7 +211,7 @@ async def book_flight(ctx: RunContext[Deps]) -> Flight | NoResult:
|
||||||
raise ModelRetry("必须先使用 search_flights 查询航班")
|
raise ModelRetry("必须先使用 search_flights 查询航班")
|
||||||
|
|
||||||
if not ctx.tool_call_approved:
|
if not ctx.tool_call_approved:
|
||||||
raise ApprovalRequired()
|
raise ApprovalRequired(metadata={"content": "您要预定哪班航班?"})
|
||||||
|
|
||||||
# 提取到的航班号
|
# 提取到的航班号
|
||||||
extracted_flight_number = (
|
extracted_flight_number = (
|
||||||
|
|
@ -286,10 +286,6 @@ async def run_stream_events(
|
||||||
"""
|
"""
|
||||||
运行并流式输出事件
|
运行并流式输出事件
|
||||||
"""
|
"""
|
||||||
# 构建智能体运行事件
|
|
||||||
yield AgentRunEvent(
|
|
||||||
content=f"正在预定 {deps.date.strftime('%Y-%m-%d')} 从 {deps.origin_airport_code} 到 {deps.destination_airport_code} 的航班"
|
|
||||||
)
|
|
||||||
tool_names = set()
|
tool_names = set()
|
||||||
async with agent.run_stream_events(
|
async with agent.run_stream_events(
|
||||||
user_prompt=user_prompt,
|
user_prompt=user_prompt,
|
||||||
|
|
@ -322,9 +318,9 @@ async def run_stream_events(
|
||||||
case "查询航班":
|
case "查询航班":
|
||||||
# 查询到的航班
|
# 查询到的航班
|
||||||
searched_flights = cast(list[Flight], content)
|
searched_flights = cast(list[Flight], content)
|
||||||
event.part.content = f"已查询到 **{len(searched_flights)} 班航班**:\n"
|
event.part.content = f"已查询到 **{len(searched_flights)}** 班航班:\n\n"
|
||||||
for searched_flight in searched_flights:
|
for searched_flight in searched_flights:
|
||||||
event.part.content += f"{searched_flight.number} {searched_flight.airfare} 于 {searched_flight.date.strftime('%Y-%m-%d')} 从 {searched_flight.origin_airport_code} 到 {searched_flight.destination_airport_code}\n"
|
event.part.content += f"{searched_flight.number} {searched_flight.airfare}$ 于 {searched_flight.date.strftime('%Y-%m-%d')} 从 {searched_flight.origin_airport_code} 到 {searched_flight.destination_airport_code}\n\n"
|
||||||
yield event
|
yield event
|
||||||
|
|
||||||
case "预定航班":
|
case "预定航班":
|
||||||
|
|
@ -334,7 +330,7 @@ async def run_stream_events(
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(content, Flight):
|
if isinstance(content, Flight):
|
||||||
event.part.content = f"已预定航班:\n{content.number} {content.airfare} 于 {content.date.strftime('%Y-%m-%d')} 从 {content.origin_airport_code} 到 {content.destination_airport_code}\n"
|
event.part.content = f"已预定航班:\n{content.number} {content.airfare}$ 于 {content.date.strftime('%Y-%m-%d')} 从 {content.origin_airport_code} 到 {content.destination_airport_code}\n"
|
||||||
yield event
|
yield event
|
||||||
|
|
||||||
case AgentRunResultEvent(
|
case AgentRunResultEvent(
|
||||||
|
|
|
||||||
|
|
@ -84,4 +84,25 @@ pre, pre code {
|
||||||
box-shadow: 12px 0 var(--prismui-color-9), -12px 0 var(--prismui-color-5);
|
box-shadow: 12px 0 var(--prismui-color-9), -12px 0 var(--prismui-color-5);
|
||||||
background: var(--prismui-color-5);
|
background: var(--prismui-color-5);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is_running {
|
||||||
|
/* 使用主题变量:普通文字色 --prismui-color-3,高光使用主题蓝色 --prismui-color-5 */
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--prismui-color-3) 0%,
|
||||||
|
var(--prismui-color-3) 35%,
|
||||||
|
var(--prismui-color-7) 50%,
|
||||||
|
var(--prismui-color-3) 65%,
|
||||||
|
var(--prismui-color-3) 100%
|
||||||
|
);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
color: transparent !important;
|
||||||
|
animation: shimmer 2.7s infinite linear;
|
||||||
|
}
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% { background-position: 200% 0; }
|
||||||
|
100% { background-position: -200% 0; }
|
||||||
}
|
}
|
||||||
Binary file not shown.
Loading…
Reference in New Issue