feat(consultation): unify server-distributed agents without fixed roles
This commit is contained in:
@@ -20,12 +20,12 @@ interface TeacherSession {
|
||||
type Json = Record<string, unknown>;
|
||||
function object(value: unknown): Json {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value))
|
||||
throw new TeacherError(502, 'teacher_protocol_invalid', '老师服务返回的数据无效。');
|
||||
throw new TeacherError(502, 'teacher_protocol_invalid', '智能体服务返回的数据无效。');
|
||||
return value as Json;
|
||||
}
|
||||
function identifier(value: unknown): string {
|
||||
if (typeof value !== 'string' || !value)
|
||||
throw new TeacherError(502, 'teacher_protocol_invalid', '老师服务未返回有效的运行标识。');
|
||||
throw new TeacherError(502, 'teacher_protocol_invalid', '智能体服务未返回有效的运行标识。');
|
||||
return value;
|
||||
}
|
||||
export interface TeacherCloudTransport {
|
||||
@@ -60,7 +60,7 @@ export function teacherCloudTransport(account: TeacherAccount): TeacherCloudTran
|
||||
typeof session.api_base_url !== 'string' ||
|
||||
!/^https?:\/\//.test(session.api_base_url)
|
||||
) {
|
||||
throw new TeacherError(502, 'teacher_session_invalid', '老师接入凭据无效,请重新连接。');
|
||||
throw new TeacherError(502, 'teacher_session_invalid', '智能体接入凭据无效,请重新连接。');
|
||||
}
|
||||
}
|
||||
if (!stopping) assertTeacherAccount(account);
|
||||
@@ -100,7 +100,7 @@ export function teacherCloudTransport(account: TeacherAccount): TeacherCloudTran
|
||||
throw new TeacherError(
|
||||
response.status,
|
||||
'teacher_cloud_failed',
|
||||
typeof message === 'string' ? message : '老师服务暂不可用,请稍后重试。'
|
||||
typeof message === 'string' ? message : '智能体服务暂不可用,请稍后重试。'
|
||||
);
|
||||
}
|
||||
return response;
|
||||
@@ -110,7 +110,7 @@ export function teacherCloudTransport(account: TeacherAccount): TeacherCloudTran
|
||||
await delay(500, undefined, { signal });
|
||||
}
|
||||
}
|
||||
throw new TeacherError(502, 'teacher_connection_failed', '连接老师失败。');
|
||||
throw new TeacherError(502, 'teacher_connection_failed', '连接智能体失败。');
|
||||
};
|
||||
return {
|
||||
async json(path, body, signal) {
|
||||
@@ -122,7 +122,7 @@ export function teacherCloudTransport(account: TeacherAccount): TeacherCloudTran
|
||||
async events(path, signal, accept) {
|
||||
const response = await fetchCloud(path, undefined, signal);
|
||||
if (!response.body)
|
||||
throw new TeacherError(502, 'teacher_stream_missing', '老师回复连接不可用。');
|
||||
throw new TeacherError(502, 'teacher_stream_missing', '智能体回复连接不可用。');
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = '';
|
||||
@@ -165,9 +165,7 @@ export function prepareCloudTeacher(
|
||||
saveRequestId: (id: string) => Promise<void>,
|
||||
transport: TeacherCloudTransport = teacherCloudTransport(account)
|
||||
) {
|
||||
const tools = topic.role === 'friend' || topic.definition.teacher_id === 'coding-friend'
|
||||
? undefined
|
||||
: createTeacherReadTools(access);
|
||||
const tools = createTeacherReadTools(access);
|
||||
return {
|
||||
// The cloud query contract is byte-bounded. Compile against the exact JSON
|
||||
// envelope instead of reserving a fixed amount for unpredictable escaping.
|
||||
@@ -237,9 +235,9 @@ export function prepareCloudTeacher(
|
||||
throw new TeacherError(
|
||||
409,
|
||||
'teacher_request_stopped',
|
||||
'老师提问未能启动,请重新提问。'
|
||||
'智能体提问未能启动,请重新提问。'
|
||||
);
|
||||
onProgress('正在等待老师…');
|
||||
onProgress('正在等待智能体…');
|
||||
await delay(800, undefined, { signal: bounded });
|
||||
queued = await transport.json(
|
||||
'/requests/' + encodeURIComponent(questionId),
|
||||
@@ -273,7 +271,7 @@ export function prepareCloudTeacher(
|
||||
throw new TeacherError(
|
||||
409,
|
||||
'teacher_interaction_unsupported',
|
||||
'老师请求了当前面板不支持的交互,请联系运营调整该智能体。'
|
||||
'智能体请求了当前面板不支持的交互,请联系运营调整该智能体。'
|
||||
);
|
||||
if (
|
||||
pending.context_id !== requestId ||
|
||||
@@ -285,14 +283,14 @@ export function prepareCloudTeacher(
|
||||
throw new TeacherError(
|
||||
409,
|
||||
'teacher_context_expired',
|
||||
'老师读取请求已失效,请重新提问。'
|
||||
'智能体读取请求已失效,请重新提问。'
|
||||
);
|
||||
onProgress('正在读取项目与会话…');
|
||||
const results = [];
|
||||
for (const raw of pending.calls) {
|
||||
const call = object(raw);
|
||||
if (typeof call.tool_call_id !== 'string' || typeof call.name !== 'string')
|
||||
throw new TeacherError(502, 'teacher_protocol_invalid', '老师读取请求无效。');
|
||||
throw new TeacherError(502, 'teacher_protocol_invalid', '智能体读取请求无效。');
|
||||
results.push({
|
||||
tool_call_id: call.tool_call_id,
|
||||
...(await tools.executeResult(call.name, JSON.stringify(call.arguments), bounded)),
|
||||
@@ -308,7 +306,7 @@ export function prepareCloudTeacher(
|
||||
cursor = '0-0';
|
||||
runText = '';
|
||||
messageId = '';
|
||||
onProgress('老师正在继续思考…');
|
||||
onProgress('智能体正在继续思考…');
|
||||
continue;
|
||||
}
|
||||
if (view.status === 'completed') {
|
||||
@@ -328,11 +326,11 @@ export function prepareCloudTeacher(
|
||||
throw new TeacherError(
|
||||
409,
|
||||
'teacher_run_failed',
|
||||
typeof detail === 'string' ? detail : '老师回复已停止。'
|
||||
typeof detail === 'string' ? detail : '智能体回复已停止。'
|
||||
);
|
||||
}
|
||||
const threadId = identifier(view.thread_id);
|
||||
onProgress('老师正在思考…');
|
||||
onProgress('智能体正在思考…');
|
||||
try {
|
||||
await transport.events(
|
||||
'/runs/' +
|
||||
@@ -342,7 +340,7 @@ export function prepareCloudTeacher(
|
||||
bounded,
|
||||
(_event, envelope, id) => {
|
||||
if (id) cursor = id;
|
||||
// Yuxi 的父 Run 也包含子线程事件,老师正文只接收云端主线程文本。
|
||||
// Yuxi 的父 Run 也包含子线程事件,智能体正文只接收云端主线程文本。
|
||||
if (envelope.thread_id !== threadId) return;
|
||||
const payload = envelope.payload ? object(envelope.payload) : {};
|
||||
for (const item of Array.isArray(payload.items)
|
||||
@@ -368,11 +366,11 @@ export function prepareCloudTeacher(
|
||||
bounded.throwIfAborted();
|
||||
access.assertCurrent();
|
||||
if (error instanceof TeacherError && error.status < 500) throw error;
|
||||
onProgress('连接中断,正在恢复老师回复…');
|
||||
onProgress('连接中断,正在恢复智能体回复…');
|
||||
}
|
||||
await delay(400, undefined, { signal: bounded });
|
||||
}
|
||||
throw new TeacherError(408, 'teacher_question_expired', '本次老师提问已超时,请重新提问。');
|
||||
throw new TeacherError(408, 'teacher_question_expired', '本次智能体提问已超时,请重新提问。');
|
||||
} finally {
|
||||
if (!completed) {
|
||||
await transport
|
||||
|
||||
Reference in New Issue
Block a user