From 32296cb4227b36d77106f6fd3ce618f82d2c4b92 Mon Sep 17 00:00:00 2001 From: john Date: Thu, 2 Jul 2026 21:32:34 +0800 Subject: [PATCH] Expose conversation package manifests --- mindspace-conversation-package-registry.mjs | 8 ++++ ...ace-conversation-package-registry.test.mjs | 40 +++++++++++++++++++ server.mjs | 31 ++++++++++++-- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/mindspace-conversation-package-registry.mjs b/mindspace-conversation-package-registry.mjs index e6f02dd..8a86e14 100644 --- a/mindspace-conversation-package-registry.mjs +++ b/mindspace-conversation-package-registry.mjs @@ -14,6 +14,7 @@ export function createConversationPackageRegistry({ store, service } = {}) { requireMethod(store, 'getPackageBySession', 'missing_conversation_package_store'); requireMethod(store, 'listArtifacts', 'missing_conversation_package_store'); requireMethod(service, 'putConversationManifest', 'missing_mindspace_service'); + requireMethod(service, 'buildConversationManifest', 'missing_mindspace_service'); return { async ensurePackage(input) { @@ -30,6 +31,13 @@ export function createConversationPackageRegistry({ store, service } = {}) { const artifacts = await store.listArtifacts(packageRecord.id); return service.putConversationManifest({ packageRecord, artifacts }); }, + + async readManifestForSession({ userId, sessionId }) { + const packageRecord = await store.getPackageBySession(userId, sessionId); + if (!packageRecord) return null; + const artifacts = await store.listArtifacts(packageRecord.id); + return service.buildConversationManifest({ packageRecord, artifacts }); + }, }; } diff --git a/mindspace-conversation-package-registry.test.mjs b/mindspace-conversation-package-registry.test.mjs index e18fa76..fa1b99e 100644 --- a/mindspace-conversation-package-registry.test.mjs +++ b/mindspace-conversation-package-registry.test.mjs @@ -150,6 +150,46 @@ test('conversation package registry records artifacts and writes manifest throug ]); }); +test('conversation package registry reads manifest without writing storage', async () => { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-registry-')); + const service = createMindSpaceServiceFacade({ + storageAdapter: createLocalMindSpaceStorageAdapter(root), + publicBaseUrl: 'https://m.tkmind.cn', + }); + const store = createConversationPackageStore(createFakePool()); + const registry = createConversationPackageRegistry({ store, service }); + const packageRecord = await registry.ensurePackage({ + userId: 'user-1', + sessionId: 'session-1', + title: '输入与页面', + now: 1000, + }); + await registry.recordArtifact({ + id: 'ca_image', + packageId: packageRecord.id, + artifactKind: 'input_image', + displayName: 'cover.png', + sortOrder: 1, + now: 1000, + }); + + const manifest = await registry.readManifestForSession({ + userId: 'user-1', + sessionId: 'session-1', + }); + + assert.equal(manifest.packageId, 'cp_session-1'); + assert.equal(manifest.title, '输入与页面'); + assert.deepEqual( + manifest.artifacts.map((item) => item.kind), + ['input_image'], + ); + assert.equal( + await service.statPackageObject({ packageRecord, relativePath: 'manifest.json' }).then((stat) => stat.exists), + false, + ); +}); + test('conversation package registry skips manifest writes for unknown sessions', async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-registry-')); const registry = createConversationPackageRegistry({ diff --git a/server.mjs b/server.mjs index 4d78b4b..6a1f2e9 100644 --- a/server.mjs +++ b/server.mjs @@ -253,6 +253,7 @@ let conversationMemoryService = null; let mindSpace = null; let mindSpaceAssets = null; let mindSpaceAudit = null; +let mindSpaceConversationPackageRegistry = null; let mindSpacePages = null; let mindSpacePageLiveEdit = null; let mindSpaceAssetAgent = null; @@ -303,7 +304,7 @@ async function bootstrapUserAuth() { }); const mindSpaceStorageRoot = process.env.MINDSPACE_STORAGE_ROOT ?? path.join(__dirname, 'data', 'mindspace'); - const conversationPackageRegistry = createConversationPackageRegistry({ + mindSpaceConversationPackageRegistry = createConversationPackageRegistry({ store: createConversationPackageStore(pool), service: createMindSpaceServiceFacade({ storageAdapter: createLocalMindSpaceStorageAdapter(mindSpaceStorageRoot), @@ -314,12 +315,12 @@ async function bootstrapUserAuth() { h5Root: __dirname, storageRoot: mindSpaceStorageRoot, maxFileBytes: Number(process.env.MINDSPACE_MAX_FILE_BYTES ?? DEFAULT_MAX_FILE_BYTES), - conversationPackageRegistry, + conversationPackageRegistry: mindSpaceConversationPackageRegistry, }); mindSpacePages = createPageService(pool, { h5Root: __dirname, storageRoot: mindSpaceStorageRoot, - conversationPackageRegistry, + conversationPackageRegistry: mindSpaceConversationPackageRegistry, }); const resolveUserIdForAgentSession = async (sessionId) => { const [rows] = await pool.query( @@ -340,7 +341,7 @@ async function bootstrapUserAuth() { h5Root: __dirname, storageRoot: mindSpaceStorageRoot, publicPageLimit: Number(process.env.MINDSPACE_FREE_PUBLIC_PAGE_LIMIT ?? 5), - conversationPackageRegistry, + conversationPackageRegistry: mindSpaceConversationPackageRegistry, }); setInterval(async () => { try { @@ -2486,6 +2487,28 @@ api.post('/internal/agent/jobs/:jobId/complete', async (req, res) => { } }); +api.get('/mindspace/v1/conversation-packages/:sessionId', async (req, res) => { + if (!mindSpaceConversationPackageRegistry || !ensureMindSpaceEnabled(res, req)) { + if (res.headersSent) return; + return res.status(503).json({ message: 'MindSpace 对话包未启用' }); + } + const sessionId = String(req.params.sessionId ?? '').trim(); + if (!sessionId) return res.status(400).json({ message: '缺少 sessionId' }); + if (!(await userAuth.ownsSession(req.currentUser.id, sessionId))) { + return res.status(403).json({ message: '无权访问该会话' }); + } + try { + const manifest = await mindSpaceConversationPackageRegistry.readManifestForSession({ + userId: req.currentUser.id, + sessionId, + }); + if (!manifest) return res.status(404).json({ message: '对话包不存在' }); + return sendData(res, req, manifest); + } catch (error) { + return mindSpaceError(res, req, error); + } +}); + api.post('/mindspace/v1/uploads', async (req, res) => { if (!mindSpaceAssets || !ensureMindSpaceEnabled(res, req, { upload: true })) return; try {