import { createAgentRunEventsHandler, createGetAgentRunHandler, createPostAgentRunsHandler, } from '../agent-run-routes.mjs'; import { executeDeepSearchLlmGateway } from '../deep-search-llm-gateway.mjs'; function assertRouter(api) { if ( !api || typeof api.get !== 'function' || typeof api.post !== 'function' ) { throw new Error( 'attachPortalAgentRuntimeRoutes requires an Express-compatible router', ); } } function runHandlerChain(chain, req, res, next) { let index = 0; const run = (error) => { if (error) return next(error); const layer = chain[index++]; if (!layer) return; layer(req, res, run); }; run(); } export function attachPortalAgentRuntimeRoutes( api, { waitForUserAuthReady = async () => {}, getUserAuth = () => null, getTkmindProxy = () => null, getLlmProviderService = () => null, getAgentRunGateway = () => null, getSessionAccess = () => null, getMindSpaceAssetAgent = () => null, getCodeRunPolicyService = () => null, getUserToken = () => null, getDeepSearchInternalSecret = () => null, bearerToken = () => null, ownsAgentSession = async () => false, executeDeepSearchLlmGatewayFn = executeDeepSearchLlmGateway, createPostAgentRunsHandlerFn = createPostAgentRunsHandler, createGetAgentRunHandlerFn = createGetAgentRunHandler, createAgentRunEventsHandlerFn = createAgentRunEventsHandler, logger = console, } = {}, ) { assertRouter(api); api.post('/internal/deep-search/llm', async (req, res) => { try { const result = await executeDeepSearchLlmGatewayFn({ llmProviderService: getLlmProviderService(), expectedSecret: getDeepSearchInternalSecret(), providedSecret: bearerToken(req) ?? req.get('x-secret-key'), input: req.body ?? {}, }); return res.status(result.status).json(result.body); } catch (error) { logger.warn('[deep-search] LLM gateway failed:', error); return res.status(502).json({ ok: false, message: error instanceof Error ? error.message : 'Deep Search LLM gateway failed', }); } }); api.post('/llm/apply-local-fallback', async (req, res) => { // Client calls after creditsExhausted or relay 500 (see useTKMindChat). await waitForUserAuthReady(); const userAuth = getUserAuth(); const llmProviderService = getLlmProviderService(); const tkmindProxy = getTkmindProxy(); if (!userAuth || !llmProviderService || !tkmindProxy) { return res.status(503).json({ message: '未启用 LLM 配置' }); } const me = await userAuth.getMe(getUserToken(req)); if (!me) return res.status(401).json({ message: '未登录' }); const sessionId = String(req.body?.session_id ?? '').trim(); if (!sessionId) return res.status(400).json({ message: '缺少 session_id' }); const owns = await ownsAgentSession(me.id, sessionId); if (!owns) return res.status(403).json({ message: '无权访问该会话' }); try { const result = await tkmindProxy.applyLocalFallbackForSession(sessionId); if (!result.ok) return res.status(503).json(result); return res.json(result); } catch (error) { return res.status(500).json({ message: error instanceof Error ? error.message : '切换本地 LLM 失败', }); } }); api.post('/agent/start', async (req, res, next) => { await waitForUserAuthReady(); const userAuth = getUserAuth(); const tkmindProxy = getTkmindProxy(); if (!userAuth || !tkmindProxy) return next(); return runHandlerChain( tkmindProxy.handlers['POST /agent/start'], req, res, next, ); }); api.post('/agent/runs', async (req, res, next) => { await waitForUserAuthReady(); const userAuth = getUserAuth(); const tkmindProxy = getTkmindProxy(); const agentRunGateway = getAgentRunGateway(); if (!userAuth || !tkmindProxy || !agentRunGateway) return next(); return runHandlerChain( [ tkmindProxy.requireUser, tkmindProxy.ensureChatAllowed, createPostAgentRunsHandlerFn({ userAuth, sessionAccess: getSessionAccess(), agentRunGateway, mindSpaceAssetAgent: getMindSpaceAssetAgent(), codeRunPolicyService: getCodeRunPolicyService(), }), ], req, res, next, ); }); api.get('/agent/runs/:runId', async (req, res, next) => { await waitForUserAuthReady(); const userAuth = getUserAuth(); const tkmindProxy = getTkmindProxy(); const agentRunGateway = getAgentRunGateway(); if (!userAuth || !tkmindProxy || !agentRunGateway) return next(); return runHandlerChain( [ tkmindProxy.requireUser, createGetAgentRunHandlerFn({ agentRunGateway }), ], req, res, next, ); }); api.get('/agent/runs/:runId/events', async (req, res, next) => { await waitForUserAuthReady(); const userAuth = getUserAuth(); const tkmindProxy = getTkmindProxy(); const agentRunGateway = getAgentRunGateway(); if (!userAuth || !tkmindProxy || !agentRunGateway) return next(); return runHandlerChain( [ tkmindProxy.requireUser, createAgentRunEventsHandlerFn({ agentRunGateway }), ], req, res, next, ); }); api.post('/agent/resume', async (req, res, next) => { await waitForUserAuthReady(); const userAuth = getUserAuth(); const tkmindProxy = getTkmindProxy(); if (!userAuth || !tkmindProxy) return next(); return runHandlerChain( tkmindProxy.handlers['POST /agent/resume'], req, res, next, ); }); api.get('/sessions', async (req, res, next) => { await waitForUserAuthReady(); const userAuth = getUserAuth(); const tkmindProxy = getTkmindProxy(); if (!userAuth || !tkmindProxy) return next(); return runHandlerChain( tkmindProxy.handlers['GET /sessions'], req, res, next, ); }); }