feat(coding): keep one ongoing conversation per delivered agent
This commit is contained in:
@@ -17,6 +17,8 @@ export async function handleCodingTeacherRoutes(
|
||||
url: URL,
|
||||
ctx: HostApiContext
|
||||
): Promise<boolean> {
|
||||
const legacy = url.pathname.match(/^\/api\/coding\/projects\/([^/]+)\/agent-history(?:\/([^/]+))?$/);
|
||||
const conversation = url.pathname.match(/^\/api\/coding\/agent-conversations\/([^/]+)(?:\/(messages|events|save|seen|discussion|requests\/([^/]+)\/cancel))?$/);
|
||||
const source = url.pathname.match(
|
||||
/^\/api\/coding\/projects\/([^/]+)\/conversations\/([^/]+)\/teacher-topics(?:\/([^/]+))?(?:\/(messages|events|save|discussion|requests\/([^/]+)\/cancel))?$/
|
||||
);
|
||||
@@ -32,7 +34,7 @@ export async function handleCodingTeacherRoutes(
|
||||
const catalog = url.pathname === '/api/coding/teacher/teachers';
|
||||
const draft = url.pathname === '/api/coding/teacher-preview';
|
||||
const pending = url.pathname === '/api/coding/teacher-preview/pending-link';
|
||||
if (!source && !preview && !projectTopics && !checkIn && !config && !catalog && !draft && !pending) return false;
|
||||
if (!legacy && !conversation && !source && !preview && !projectTopics && !checkIn && !config && !catalog && !draft && !pending) return false;
|
||||
if ((config || catalog || draft || pending) && req.method !== 'GET') {
|
||||
sendJson(res, 405, { error: '不支持此操作。' });
|
||||
return true;
|
||||
@@ -47,6 +49,27 @@ export async function handleCodingTeacherRoutes(
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
if (legacy) {
|
||||
if (req.method !== 'GET') sendJson(res, 405, { error: '旧记录仅供查看。' });
|
||||
else sendJson(res, 200, await service.legacyHistory(decodeURIComponent(legacy[1]), legacy[2] ? {
|
||||
id: decodeURIComponent(legacy[2]), sourceId: url.searchParams.get('source') ?? 'project', friend: url.searchParams.get('friend') === 'true',
|
||||
} : undefined));
|
||||
return true;
|
||||
}
|
||||
const agentId = conversation ? decodeURIComponent(conversation[1]) : undefined;
|
||||
if (agentId && !conversation![2] && req.method === 'GET') {
|
||||
sendJson(res, 200, await service.conversation(agentId, url.searchParams.get('before') ?? undefined));
|
||||
return true;
|
||||
}
|
||||
if (agentId && conversation![2] === 'messages' && req.method === 'POST') {
|
||||
sendJson(res, 202, await service.sendConversation(agentId, await parseJsonBody<TeacherSend>(req)));
|
||||
return true;
|
||||
}
|
||||
if (agentId && conversation![2] === 'seen' && req.method === 'POST') {
|
||||
const input = await parseJsonBody<{ requestId: string }>(req);
|
||||
sendJson(res, 200, await service.markConversationSeen(agentId, input.requestId));
|
||||
return true;
|
||||
}
|
||||
if (checkIn) {
|
||||
if (req.method !== 'POST') sendJson(res, 405, { error: '不支持此操作。' });
|
||||
else sendJson(res, 200, await service.checkIn(
|
||||
@@ -70,14 +93,16 @@ export async function handleCodingTeacherRoutes(
|
||||
sendJson(res, 200, await service.previewDefinition(revision));
|
||||
return true;
|
||||
}
|
||||
const scope: TeacherScope = source
|
||||
const continuous = agentId ? await service.conversation(agentId) : undefined;
|
||||
if (agentId && !continuous?.topic) throw new TeacherError(404, 'teacher_topic_not_found', '智能体聊天尚未开始。');
|
||||
const scope: TeacherScope = agentId ? { projectId: '', sourceId: 'project', agentId } : source
|
||||
? { projectId: decodeURIComponent(source[1]), sourceId: decodeURIComponent(source[2]) }
|
||||
: projectTopics
|
||||
? { projectId: decodeURIComponent(projectTopics[1]), sourceId: 'project', role }
|
||||
: { projectId: 'preview', sourceId: 'preview' };
|
||||
const id = source?.[3] ?? projectTopics?.[3] ?? preview?.[1],
|
||||
action = source?.[4] ?? projectTopics?.[4] ?? preview?.[2],
|
||||
requestId = source?.[5] ?? projectTopics?.[5] ?? preview?.[3];
|
||||
const id = continuous?.topic?.id ?? source?.[3] ?? projectTopics?.[3] ?? preview?.[1],
|
||||
action = conversation?.[2] ?? source?.[4] ?? projectTopics?.[4] ?? preview?.[2],
|
||||
requestId = conversation?.[3] ?? source?.[5] ?? projectTopics?.[5] ?? preview?.[3];
|
||||
if (!id && req.method === 'GET') {
|
||||
sendJson(res, 200, await service.list(scope));
|
||||
return true;
|
||||
@@ -112,6 +137,9 @@ export async function handleCodingTeacherRoutes(
|
||||
const buffered: unknown[] = [];
|
||||
let started = false;
|
||||
const close = await service.subscribe(scope, id, (topic) => {
|
||||
// GET owns paged history. Stream only the current turn and metadata;
|
||||
// Renderer merges by request ID/revision without replacing older pages.
|
||||
if (conversation) topic = { ...topic, requests: topic.requests.slice(-1) };
|
||||
if (!started) {
|
||||
buffered.push(topic);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user