更新ios
This commit is contained in:
@@ -263,10 +263,10 @@ const StockCodeLink = memo(({ code, exchange, navigation }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handlePress = useCallback(() => {
|
const handlePress = useCallback(() => {
|
||||||
const stockCode = exchangeSuffix ? `${code}.${exchangeSuffix}` : code;
|
const fullStockCode = exchangeSuffix ? `${code}.${exchangeSuffix}` : code;
|
||||||
navigation?.navigate('StockDetail', {
|
navigation?.navigate('StockDetail', {
|
||||||
code: stockCode,
|
stockCode: fullStockCode,
|
||||||
name: stockCode, // 名称可以在详情页获取
|
stockName: fullStockCode, // 名称可以在详情页获取
|
||||||
});
|
});
|
||||||
}, [code, exchangeSuffix, navigation]);
|
}, [code, exchangeSuffix, navigation]);
|
||||||
|
|
||||||
|
|||||||
@@ -2662,27 +2662,36 @@ A股交易时间: 上午 9:30-11:30,下午 13:00-15:00
|
|||||||
# 将 assistant 消息添加到历史(包含 tool_calls)
|
# 将 assistant 消息添加到历史(包含 tool_calls)
|
||||||
messages.append(assistant_message)
|
messages.append(assistant_message)
|
||||||
|
|
||||||
# 如果是第一次工具调用,发送计划事件
|
# 构建当前轮次的步骤列表
|
||||||
if step_index == 0:
|
current_round_steps = []
|
||||||
# 构建计划数据
|
|
||||||
plan_data = {
|
|
||||||
"goal": f"分析用户问题:{user_query[:50]}...",
|
|
||||||
"reasoning": "使用工具获取相关数据进行分析",
|
|
||||||
"steps": []
|
|
||||||
}
|
|
||||||
for tc in native_tool_calls:
|
for tc in native_tool_calls:
|
||||||
try:
|
try:
|
||||||
args = json.loads(tc.function.arguments) if tc.function.arguments else {}
|
args = json.loads(tc.function.arguments) if tc.function.arguments else {}
|
||||||
except:
|
except:
|
||||||
args = {}
|
args = {}
|
||||||
plan_data["steps"].append({
|
current_round_steps.append({
|
||||||
"tool": tc.function.name,
|
"tool": tc.function.name,
|
||||||
"arguments": args,
|
"arguments": args,
|
||||||
"reason": f"调用 {tc.function.name}"
|
"reason": f"调用 {tc.function.name}"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# 如果是第一次工具调用,发送计划事件
|
||||||
|
if step_index == 0:
|
||||||
|
plan_data = {
|
||||||
|
"goal": f"分析用户问题:{user_query[:50]}...",
|
||||||
|
"reasoning": "使用工具获取相关数据进行分析",
|
||||||
|
"steps": current_round_steps
|
||||||
|
}
|
||||||
yield self._format_sse("plan", plan_data)
|
yield self._format_sse("plan", plan_data)
|
||||||
yield self._format_sse("status", {"stage": "executing", "message": f"开始执行 {len(native_tool_calls)} 个工具调用"})
|
yield self._format_sse("status", {"stage": "executing", "message": f"开始执行 {len(native_tool_calls)} 个工具调用"})
|
||||||
|
else:
|
||||||
|
# 多轮调用时,发送 plan_update 事件追加新步骤
|
||||||
|
yield self._format_sse("plan_update", {
|
||||||
|
"new_steps": current_round_steps,
|
||||||
|
"round": step_index // len(native_tool_calls) + 1 if native_tool_calls else 1,
|
||||||
|
"message": f"模型决定继续调用 {len(native_tool_calls)} 个工具"
|
||||||
|
})
|
||||||
|
yield self._format_sse("status", {"stage": "executing", "message": f"继续执行第 {step_index + 1} 步"})
|
||||||
|
|
||||||
# 执行每个工具调用
|
# 执行每个工具调用
|
||||||
for tool_call in native_tool_calls:
|
for tool_call in native_tool_calls:
|
||||||
@@ -2795,18 +2804,29 @@ A股交易时间: 上午 9:30-11:30,下午 13:00-15:00
|
|||||||
# 将 assistant 消息添加到历史
|
# 将 assistant 消息添加到历史
|
||||||
messages.append({"role": "assistant", "content": assistant_message.content})
|
messages.append({"role": "assistant", "content": assistant_message.content})
|
||||||
|
|
||||||
|
# 构建当前轮次的步骤列表
|
||||||
|
current_round_steps = [
|
||||||
|
{"tool": tc["name"], "arguments": tc["arguments"], "reason": f"调用 {tc['name']}"}
|
||||||
|
for tc in text_tool_calls
|
||||||
|
]
|
||||||
|
|
||||||
# 如果是第一次工具调用,发送计划事件
|
# 如果是第一次工具调用,发送计划事件
|
||||||
if step_index == 0:
|
if step_index == 0:
|
||||||
plan_data = {
|
plan_data = {
|
||||||
"goal": f"分析用户问题:{user_query[:50]}...",
|
"goal": f"分析用户问题:{user_query[:50]}...",
|
||||||
"reasoning": "使用工具获取相关数据进行分析",
|
"reasoning": "使用工具获取相关数据进行分析",
|
||||||
"steps": [
|
"steps": current_round_steps
|
||||||
{"tool": tc["name"], "arguments": tc["arguments"], "reason": f"调用 {tc['name']}"}
|
|
||||||
for tc in text_tool_calls
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
yield self._format_sse("plan", plan_data)
|
yield self._format_sse("plan", plan_data)
|
||||||
yield self._format_sse("status", {"stage": "executing", "message": f"开始执行 {len(text_tool_calls)} 个工具调用"})
|
yield self._format_sse("status", {"stage": "executing", "message": f"开始执行 {len(text_tool_calls)} 个工具调用"})
|
||||||
|
else:
|
||||||
|
# 多轮调用时,发送 plan_update 事件追加新步骤
|
||||||
|
yield self._format_sse("plan_update", {
|
||||||
|
"new_steps": current_round_steps,
|
||||||
|
"round": step_index // len(text_tool_calls) + 1 if text_tool_calls else 1,
|
||||||
|
"message": f"模型决定继续调用 {len(text_tool_calls)} 个工具"
|
||||||
|
})
|
||||||
|
yield self._format_sse("status", {"stage": "executing", "message": f"继续执行第 {step_index + 1} 步"})
|
||||||
|
|
||||||
# 执行每个工具调用
|
# 执行每个工具调用
|
||||||
for tc in text_tool_calls:
|
for tc in text_tool_calls:
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
case MessageTypes.AGENT_PLAN:
|
case MessageTypes.AGENT_PLAN:
|
||||||
|
const planStepsToShow = message.plan?.steps || [];
|
||||||
return (
|
return (
|
||||||
<Flex justify="flex-start" w="100%">
|
<Flex justify="flex-start" w="100%">
|
||||||
<HStack align="start" spacing={3} maxW={{ base: '95%', md: '85%', lg: '80%' }} w="100%">
|
<HStack align="start" spacing={3} maxW={{ base: '95%', md: '85%', lg: '80%' }} w="100%">
|
||||||
@@ -420,13 +421,13 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
<Text fontSize="sm" fontWeight="medium" color="purple.300">
|
<Text fontSize="sm" fontWeight="medium" color="purple.300">
|
||||||
执行计划
|
执行计划
|
||||||
</Text>
|
</Text>
|
||||||
{message.plan?.steps && (
|
{planStepsToShow.length > 0 && (
|
||||||
<Badge
|
<Badge
|
||||||
bgGradient="linear(to-r, purple.500, pink.500)"
|
bgGradient="linear(to-r, purple.500, pink.500)"
|
||||||
color="white"
|
color="white"
|
||||||
fontSize="xs"
|
fontSize="xs"
|
||||||
>
|
>
|
||||||
{message.plan.steps.length} 个步骤
|
{planStepsToShow.length} 个步骤
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
@@ -437,14 +438,16 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{message.plan?.steps && (
|
{planStepsToShow.length > 0 && (
|
||||||
<VStack align="stretch" spacing={2}>
|
<VStack align="stretch" spacing={2}>
|
||||||
{message.plan.steps.map((step, idx) => (
|
<AnimatePresence>
|
||||||
|
{planStepsToShow.map((step, idx) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={idx}
|
key={`plan-step-${idx}-${step.tool}`}
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
transition={{ delay: idx * 0.1 }}
|
transition={{ delay: idx * 0.1 }}
|
||||||
|
layout
|
||||||
>
|
>
|
||||||
<HStack
|
<HStack
|
||||||
p={2}
|
p={2}
|
||||||
@@ -469,6 +472,7 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
</HStack>
|
</HStack>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
|
</AnimatePresence>
|
||||||
</VStack>
|
</VStack>
|
||||||
)}
|
)}
|
||||||
</CardBody>
|
</CardBody>
|
||||||
@@ -479,10 +483,42 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
case MessageTypes.AGENT_EXECUTING:
|
case MessageTypes.AGENT_EXECUTING:
|
||||||
const steps = message.plan?.steps || [];
|
// 从 plan 中获取步骤列表,如果没有 plan,则从 stepResults 中构建
|
||||||
|
const planSteps = message.plan?.steps || [];
|
||||||
const completedSteps = message.stepResults || [];
|
const completedSteps = message.stepResults || [];
|
||||||
const currentStepIndex = completedSteps.length;
|
|
||||||
const progress = steps.length > 0 ? (completedSteps.length / steps.length) * 100 : 0;
|
// 如果有当前步骤但不在 planSteps 中,需要动态添加
|
||||||
|
const currentStepInfo = message.currentStep;
|
||||||
|
const activeStepIndex = message.currentStepIndex;
|
||||||
|
|
||||||
|
// 构建完整的步骤列表:已完成的步骤 + 当前步骤(如果有)
|
||||||
|
// 这样即使在多轮调用时 plan 还没更新,也能显示当前正在执行的步骤
|
||||||
|
let displaySteps = [...planSteps];
|
||||||
|
|
||||||
|
// 如果 planSteps 为空但有 completedSteps,从 completedSteps 构建
|
||||||
|
if (displaySteps.length === 0 && completedSteps.length > 0) {
|
||||||
|
displaySteps = completedSteps.map(s => ({ tool: s.tool, arguments: {} }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前有正在执行的步骤,且不在显示列表中,添加它
|
||||||
|
if (currentStepInfo && activeStepIndex !== null && activeStepIndex !== undefined) {
|
||||||
|
while (displaySteps.length <= activeStepIndex) {
|
||||||
|
if (displaySteps.length === activeStepIndex) {
|
||||||
|
displaySteps.push({ tool: currentStepInfo.tool, arguments: currentStepInfo.arguments });
|
||||||
|
} else {
|
||||||
|
// 填充中间可能缺失的步骤(从已完成结果中获取)
|
||||||
|
const stepResult = completedSteps[displaySteps.length];
|
||||||
|
if (stepResult) {
|
||||||
|
displaySteps.push({ tool: stepResult.tool, arguments: {} });
|
||||||
|
} else {
|
||||||
|
displaySteps.push({ tool: '未知步骤', arguments: {} });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalSteps = Math.max(displaySteps.length, completedSteps.length + (activeStepIndex !== null ? 1 : 0));
|
||||||
|
const progress = totalSteps > 0 ? (completedSteps.length / totalSteps) * 100 : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex justify="flex-start" w="100%">
|
<Flex justify="flex-start" w="100%">
|
||||||
@@ -520,8 +556,13 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
正在执行
|
正在执行
|
||||||
</Text>
|
</Text>
|
||||||
<Badge colorScheme="blue" fontSize="xs">
|
<Badge colorScheme="blue" fontSize="xs">
|
||||||
{completedSteps.length} / {steps.length}
|
{completedSteps.length}{totalSteps > 0 ? ` / ${totalSteps}` : ''}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
{activeStepIndex !== null && activeStepIndex !== undefined && currentStepInfo && (
|
||||||
|
<Text fontSize="xs" color="blue.200" ml={2}>
|
||||||
|
→ {currentStepInfo.tool}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
{/* 进度条 */}
|
{/* 进度条 */}
|
||||||
@@ -539,15 +580,17 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
{/* 步骤列表 */}
|
{/* 步骤列表 */}
|
||||||
<VStack align="stretch" spacing={2}>
|
<VStack align="stretch" spacing={2}>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{steps.map((step, idx) => {
|
{displaySteps.map((step, idx) => {
|
||||||
const result = completedSteps[idx];
|
const result = completedSteps[idx];
|
||||||
const isCompleted = idx < completedSteps.length;
|
const isCompleted = idx < completedSteps.length;
|
||||||
const isRunning = idx === currentStepIndex;
|
const isRunning = activeStepIndex !== null && activeStepIndex !== undefined
|
||||||
const isPending = idx > currentStepIndex;
|
? idx === activeStepIndex
|
||||||
|
: idx === completedSteps.length;
|
||||||
|
const isPending = !isCompleted && !isRunning;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={idx}
|
key={`step-${idx}-${step.tool}`}
|
||||||
initial={{ opacity: 0, y: -10 }}
|
initial={{ opacity: 0, y: -10 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ delay: idx * 0.05 }}
|
transition={{ delay: idx * 0.05 }}
|
||||||
@@ -641,6 +684,15 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
{result.execution_time.toFixed(2)}s
|
{result.execution_time.toFixed(2)}s
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 执行失败时显示错误提示 */}
|
||||||
|
{result?.status === 'failed' && result?.error && (
|
||||||
|
<Tooltip label={result.error}>
|
||||||
|
<Text fontSize="xs" color="red.400" cursor="help">
|
||||||
|
失败
|
||||||
|
</Text>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -59,6 +59,16 @@ export interface UserMessage extends BaseMessage {
|
|||||||
files?: MessageFile[];
|
files?: MessageFile[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前执行步骤信息
|
||||||
|
*/
|
||||||
|
export interface CurrentStep {
|
||||||
|
/** 工具名称 */
|
||||||
|
tool: string;
|
||||||
|
/** 工具参数 */
|
||||||
|
arguments: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Agent 消息接口
|
* Agent 消息接口
|
||||||
*/
|
*/
|
||||||
@@ -79,6 +89,10 @@ export interface AgentMessage extends BaseMessage {
|
|||||||
execution_time?: number;
|
execution_time?: number;
|
||||||
error?: string;
|
error?: string;
|
||||||
}>;
|
}>;
|
||||||
|
/** 当前正在执行的步骤索引(用于 AGENT_EXECUTING 类型)*/
|
||||||
|
currentStepIndex?: number | null;
|
||||||
|
/** 当前正在执行的步骤信息(用于 AGENT_EXECUTING 类型)*/
|
||||||
|
currentStep?: CurrentStep | null;
|
||||||
/** 深度思考内容(用于 AGENT_DEEP_THINKING 类型)*/
|
/** 深度思考内容(用于 AGENT_DEEP_THINKING 类型)*/
|
||||||
thinkingContent?: string;
|
thinkingContent?: string;
|
||||||
/** 是否正在思考中 */
|
/** 是否正在思考中 */
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ export const useAgentChat = ({
|
|||||||
isDeepThinking: boolean; // 是否正在进行深度思考
|
isDeepThinking: boolean; // 是否正在进行深度思考
|
||||||
plan: any;
|
plan: any;
|
||||||
stepResults: any[];
|
stepResults: any[];
|
||||||
|
currentStep: { tool: string; arguments: any } | null; // 当前正在执行的步骤
|
||||||
sessionId: string | null;
|
sessionId: string | null;
|
||||||
sessionTitle: string | null;
|
sessionTitle: string | null;
|
||||||
}>({
|
}>({
|
||||||
@@ -135,6 +136,7 @@ export const useAgentChat = ({
|
|||||||
isDeepThinking: false,
|
isDeepThinking: false,
|
||||||
plan: null,
|
plan: null,
|
||||||
stepResults: [],
|
stepResults: [],
|
||||||
|
currentStep: null,
|
||||||
sessionId: null,
|
sessionId: null,
|
||||||
sessionTitle: null,
|
sessionTitle: null,
|
||||||
});
|
});
|
||||||
@@ -196,6 +198,7 @@ export const useAgentChat = ({
|
|||||||
isDeepThinking: false,
|
isDeepThinking: false,
|
||||||
plan: null,
|
plan: null,
|
||||||
stepResults: [],
|
stepResults: [],
|
||||||
|
currentStep: null,
|
||||||
sessionId: null,
|
sessionId: null,
|
||||||
sessionTitle: null,
|
sessionTitle: null,
|
||||||
};
|
};
|
||||||
@@ -409,11 +412,35 @@ export const useAgentChat = ({
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'plan_update':
|
||||||
|
// 多轮工具调用时,追加新的步骤到计划中
|
||||||
|
if (data?.new_steps && streamStateRef.current.plan) {
|
||||||
|
streamStateRef.current.plan.steps = [
|
||||||
|
...(streamStateRef.current.plan.steps || []),
|
||||||
|
...data.new_steps
|
||||||
|
];
|
||||||
|
// 更新 AGENT_PLAN 消息
|
||||||
|
updateLastMessage(MessageTypes.AGENT_PLAN, {
|
||||||
|
plan: { ...streamStateRef.current.plan },
|
||||||
|
});
|
||||||
|
// 更新 AGENT_EXECUTING 消息
|
||||||
|
updateLastMessage(MessageTypes.AGENT_EXECUTING, {
|
||||||
|
plan: { ...streamStateRef.current.plan },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'step_start':
|
case 'step_start':
|
||||||
// 步骤开始执行 - 保留已完成的步骤结果,更新当前执行状态
|
// 步骤开始执行 - 记录当前步骤,更新执行状态
|
||||||
|
streamStateRef.current.currentStep = {
|
||||||
|
tool: data?.tool || '工具',
|
||||||
|
arguments: data?.arguments || {},
|
||||||
|
};
|
||||||
updateLastMessage(MessageTypes.AGENT_EXECUTING, {
|
updateLastMessage(MessageTypes.AGENT_EXECUTING, {
|
||||||
content: `正在执行步骤 ${(data?.step_index || 0) + 1}: ${data?.tool || '工具'}...`,
|
content: `正在执行步骤 ${(data?.step_index || 0) + 1}: ${data?.tool || '工具'}...`,
|
||||||
stepResults: [...streamStateRef.current.stepResults], // 保留已完成的步骤
|
stepResults: [...streamStateRef.current.stepResults],
|
||||||
|
currentStepIndex: data?.step_index,
|
||||||
|
currentStep: streamStateRef.current.currentStep,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -424,11 +451,15 @@ export const useAgentChat = ({
|
|||||||
tool: data.tool,
|
tool: data.tool,
|
||||||
status: data.status,
|
status: data.status,
|
||||||
result: data.result,
|
result: data.result,
|
||||||
|
error: data.error,
|
||||||
execution_time: data.execution_time,
|
execution_time: data.execution_time,
|
||||||
});
|
});
|
||||||
|
streamStateRef.current.currentStep = null;
|
||||||
updateLastMessage(MessageTypes.AGENT_EXECUTING, {
|
updateLastMessage(MessageTypes.AGENT_EXECUTING, {
|
||||||
content: `已完成 ${streamStateRef.current.stepResults.length} 个步骤`,
|
content: `已完成 ${streamStateRef.current.stepResults.length} 个步骤`,
|
||||||
stepResults: [...streamStateRef.current.stepResults],
|
stepResults: [...streamStateRef.current.stepResults],
|
||||||
|
currentStepIndex: null,
|
||||||
|
currentStep: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user