fix: isolate delivered agent chats by project

This commit is contained in:
2026-09-28 16:21:14 +08:00
parent a21a1f077c
commit 4b41c23a3a
15 changed files with 518 additions and 165 deletions

View File

@@ -18,7 +18,7 @@ export async function handleCodingTeacherRoutes(
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 conversation = url.pathname.match(/^\/api\/coding\/projects\/([^/]+)\/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))?$/
);
@@ -56,18 +56,22 @@ export async function handleCodingTeacherRoutes(
} : 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));
const projectId = conversation ? decodeURIComponent(conversation[1]) : undefined;
const agentId = conversation ? decodeURIComponent(conversation[2]) : undefined;
if (agentId && !conversation![3] && req.method === 'GET') {
sendJson(res, 200, await service.conversation(projectId!, 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)));
if (agentId && conversation![3] === 'messages' && req.method === 'POST') {
const input = await parseJsonBody<TeacherSend>(req);
if (input.projectId && input.projectId !== projectId)
throw new TeacherError(422, 'teacher_project_mismatch', '提问不属于当前项目。');
sendJson(res, 202, await service.sendConversation(agentId, { ...input, projectId }));
return true;
}
if (agentId && conversation![2] === 'seen' && req.method === 'POST') {
if (agentId && conversation![3] === 'seen' && req.method === 'POST') {
const input = await parseJsonBody<{ requestId: string }>(req);
sendJson(res, 200, await service.markConversationSeen(agentId, input.requestId));
sendJson(res, 200, await service.markConversationSeen(projectId!, agentId, input.requestId));
return true;
}
if (checkIn) {
@@ -93,16 +97,16 @@ export async function handleCodingTeacherRoutes(
sendJson(res, 200, await service.previewDefinition(revision));
return true;
}
const continuous = agentId ? await service.conversation(agentId) : undefined;
const continuous = agentId ? await service.conversation(projectId!, agentId) : undefined;
if (agentId && !continuous?.topic) throw new TeacherError(404, 'teacher_topic_not_found', '智能体聊天尚未开始。');
const scope: TeacherScope = agentId ? { projectId: '', sourceId: 'project', agentId } : source
const scope: TeacherScope = agentId ? { projectId: 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 = 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];
action = conversation?.[3] ?? source?.[4] ?? projectTopics?.[4] ?? preview?.[2],
requestId = conversation?.[4] ?? source?.[5] ?? projectTopics?.[5] ?? preview?.[3];
if (!id && req.method === 'GET') {
sendJson(res, 200, await service.list(scope));
return true;