fix(teacher): 合并续接工具活动并修正暂停状态
This commit is contained in:
@@ -11,22 +11,24 @@ function object(value: unknown): Record<string, unknown> | undefined {
|
||||
}
|
||||
|
||||
/** Project Yuxi's typed tool events; arguments, outputs and internal errors never enter the UI. */
|
||||
export function cloudToolActivity(chunk: Record<string, unknown>, runId: string): ToolActivityUpdate | undefined {
|
||||
export function cloudToolActivity(chunk: Record<string, unknown>, requestId: string): ToolActivityUpdate | undefined {
|
||||
const event = object(chunk.stream_event);
|
||||
if (event?.type === 'tool_call' || event?.type === 'tool_call_delta') {
|
||||
if (typeof event.tool_call_id !== 'string' || !event.tool_call_id || typeof event.name !== 'string' || !event.name) return;
|
||||
return { id: runId + ':' + event.tool_call_id, name: event.name, status: 'running' };
|
||||
return { id: requestId + ':' + event.tool_call_id, name: event.name, status: 'running' };
|
||||
}
|
||||
const custom = object(chunk.event);
|
||||
if (chunk.status !== 'stream_event' || custom?.method !== 'tools') return;
|
||||
const data = object(custom.data);
|
||||
if (!data || typeof data.tool_call_id !== 'string' || !data.tool_call_id) return;
|
||||
if (data.event !== 'tool-started' && data.event !== 'tool-finished' && data.event !== 'tool-error') return;
|
||||
// A raw tool-error can be a checkpoint interrupt. Only a tool result or the
|
||||
// question's terminal state establishes failure, as in Yuxi's tool audit.
|
||||
if (data.event !== 'tool-started' && data.event !== 'tool-finished') return;
|
||||
const output = object(data.output);
|
||||
return {
|
||||
id: runId + ':' + data.tool_call_id,
|
||||
id: requestId + ':' + data.tool_call_id,
|
||||
...(typeof data.tool_name === 'string' && data.tool_name ? { name: data.tool_name } : {}),
|
||||
status: data.event === 'tool-started' ? 'running'
|
||||
: data.event === 'tool-error' || data.error || output?.status === 'error' || output?.status === 'failed' ? 'failed' : 'completed',
|
||||
: data.error || output?.status === 'error' || output?.status === 'failed' ? 'failed' : 'completed',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -320,13 +320,13 @@ export function prepareCloudTeacher(
|
||||
const call = object(raw);
|
||||
if (typeof call.tool_call_id !== 'string' || typeof call.name !== 'string')
|
||||
throw new TeacherError(502, 'teacher_protocol_invalid', '智能体读取请求无效。');
|
||||
reportActivity({ id: runId + ':' + call.tool_call_id, name: call.name, status: 'running' });
|
||||
reportActivity({ id: requestId + ':' + call.tool_call_id, name: call.name, status: 'running' });
|
||||
const result = await tools.executeResult(call.name, JSON.stringify(call.arguments), bounded);
|
||||
results.push({
|
||||
tool_call_id: call.tool_call_id,
|
||||
...result,
|
||||
});
|
||||
reportActivity({ id: runId + ':' + call.tool_call_id, name: call.name, status: result.status === 'success' ? 'completed' : 'failed' });
|
||||
reportActivity({ id: requestId + ':' + call.tool_call_id, name: call.name, status: result.status === 'success' ? 'completed' : 'failed' });
|
||||
}
|
||||
// POST 重试使用完全相同的结果,文件变化也不会导致重复续接或不同输入。
|
||||
const resumed = await transport.json(
|
||||
@@ -383,7 +383,8 @@ export function prepareCloudTeacher(
|
||||
? [payload.chunk]
|
||||
: []) {
|
||||
const chunk = object(item);
|
||||
const activity = cloudToolActivity(chunk, runId);
|
||||
// A checkpoint continuation changes Run, not the logical tool call.
|
||||
const activity = cloudToolActivity(chunk, requestId);
|
||||
if (activity) reportActivity(activity);
|
||||
const event = chunk.stream_event ? object(chunk.stream_event) : {};
|
||||
if (event.type === 'message_delta' && typeof event.content === 'string') {
|
||||
@@ -409,6 +410,9 @@ export function prepareCloudTeacher(
|
||||
throw new TeacherError(408, 'teacher_question_expired', '本次智能体提问已超时,请重新提问。');
|
||||
} finally {
|
||||
if (!completed) {
|
||||
for (const activity of activities.values()) {
|
||||
if (activity.status === 'running') reportActivity({ ...activity, status: 'failed' });
|
||||
}
|
||||
await transport
|
||||
.json(
|
||||
'/questions/' + encodeURIComponent(requestId) + '/cancel',
|
||||
|
||||
Reference in New Issue
Block a user