Files
next-tjwater-agent/src/routes/chat-topic-routes.ts
T
jiang 7d47a2df86
Generic Container CI/CD / test-build-publish (push) Failing after 8m25s
Agent CI/CD / build-test-publish-and-deploy (push) Failing after 8m25s
feat: add scoped history and artifacts
2026-10-22 18:40:20 +08:00

44 lines
2.5 KiB
TypeScript

import type { Router } from "express";
import { z } from "zod";
import { getLocalAgentContext } from "../context/localContext.js";
import { readPurpose, type SessionMetadataStore } from "../sessions/metadataStore.js";
const nameSchema = z.object({ name: z.string().trim().min(1).max(80) }).strict();
const membershipSchema = z.object({ topic_id: z.string().uuid().nullable() }).strict();
export function registerChatTopicRoutes(router: Router, sessions: SessionMetadataStore) {
router.get("/topics", async (req, res) => {
res.json({ topics: await sessions.topics.list(getLocalAgentContext(req)) });
});
router.post("/topics", async (req, res) => {
const parsed = nameSchema.safeParse(req.body);
if (!parsed.success) { res.status(400).json({ message: "主题名称须为 1 至 80 个字符" }); return; }
res.status(201).json(await sessions.topics.create(getLocalAgentContext(req), parsed.data.name));
});
router.patch("/topics/:topic_id", async (req, res) => {
const parsed = nameSchema.safeParse(req.body);
if (!parsed.success) { res.status(400).json({ message: "主题名称须为 1 至 80 个字符" }); return; }
const topic = await sessions.topics.rename(getLocalAgentContext(req), req.params.topic_id, parsed.data.name);
if (!topic) { res.status(404).json({ message: "主题不存在" }); return; }
res.json(topic);
});
router.delete("/topics/:topic_id", async (req, res) => {
// Removing a grouping never deletes conversations. Old IDs resolve as unclassified.
const removed = await sessions.topics.remove(getLocalAgentContext(req), req.params.topic_id);
if (!removed) { res.status(404).json({ message: "主题不存在" }); return; }
res.status(204).end();
});
router.patch("/session/:session_id/topic", async (req, res) => {
const parsed = membershipSchema.safeParse(req.body);
if (!parsed.success) { res.status(400).json({ message: "invalid topic membership" }); return; }
const context = getLocalAgentContext(req);
const record = await sessions.get(context, req.params.session_id);
if (!record || readPurpose(record) === "task_execution") { res.status(404).json({ message: "session not found" }); return; }
if (parsed.data.topic_id && !await sessions.topics.get(context, parsed.data.topic_id)) {
res.status(404).json({ message: "主题不存在" }); return;
}
await sessions.touch(record, { topicId: parsed.data.topic_id });
res.json({ session_id: record.sessionId, topic_id: parsed.data.topic_id });
});
}