feat(h5): web 联网能力、实时查询路由与 session Finish 对齐
- 新增 web 能力并挂载 platform/web(web_search/fetch_url) - 实时查询强制 web skill,router fallback 与 await session Finish - Session Broker 覆盖率/指标、stream replay 与相关单测/E2E 脚本 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+34
-9
@@ -22,6 +22,7 @@ import {
|
||||
} from './agent-run-routes.mjs';
|
||||
import { createTkmindProxy, sanitizeSessionConversationPublicHtmlLinks } from './tkmind-proxy.mjs';
|
||||
import { createSessionAccess, isSessionBrokerEnabled } from './session-broker.mjs';
|
||||
import { isSessionBrokerMetricsEnabled } from './session-broker-metrics.mjs';
|
||||
import {
|
||||
clearUserSessionCookie,
|
||||
createUserAuth,
|
||||
@@ -173,7 +174,9 @@ import { createLlmProviderService, RELAY_BOOTSTRAP } from './llm-providers.mjs';
|
||||
import { createDirectChatService, isDirectChatSessionId, isPortalDirectChatSnapshot, sendDirectChatSessionEvents, shouldExpirePortalDirectChatSnapshot } from './direct-chat-service.mjs';
|
||||
import { repairSessionConversationFromDb } from './conversation-repair.mjs';
|
||||
import { filterNonemptyUserVisibleMessages } from './conversation-transcript-persist.mjs';
|
||||
import { createManagedChatIntentRouter } from './chat-intent-router.mjs';
|
||||
import { createSessionStreamStore } from './session-stream-store.mjs';
|
||||
import { isSessionStreamReplayEnabled } from './session-stream.mjs';
|
||||
import { createManagedChatIntentRouter, resolveNormalizedRouterDecisionMode } from './chat-intent-router.mjs';
|
||||
import { createSessionSnapshotService } from './session-snapshot.mjs';
|
||||
import { createConversationMemoryService } from './conversation-memory.mjs';
|
||||
import { createManagedMemoryV2Runtime } from './memory-v2-runtime.mjs';
|
||||
@@ -293,22 +296,27 @@ if (ACCESS_PASSWORD && !isDatabaseConfigured()) {
|
||||
|
||||
let userAuth = null;
|
||||
let sessionAccess = null;
|
||||
let sessionStreamStore = null;
|
||||
let tkmindProxy = null;
|
||||
|
||||
async function resolveActiveSessionAccess() {
|
||||
if (sessionAccess) return sessionAccess;
|
||||
if (!userAuth) return null;
|
||||
return createSessionAccess({ userAuth, enabled: isSessionBrokerEnabled() });
|
||||
}
|
||||
|
||||
async function ownsAgentSession(userId, sessionId) {
|
||||
if (!userId || !sessionId) return false;
|
||||
if (sessionAccess) return sessionAccess.validateOwnership(userId, sessionId);
|
||||
if (userAuth) return userAuth.ownsSession(userId, sessionId);
|
||||
return false;
|
||||
const access = await resolveActiveSessionAccess();
|
||||
if (!access) return false;
|
||||
return access.validateOwnership(userId, sessionId);
|
||||
}
|
||||
|
||||
async function unregisterAgentSessionForUser(userId, sessionId) {
|
||||
if (!userId || !sessionId) return;
|
||||
if (sessionAccess) {
|
||||
await sessionAccess.unregisterSession({ userId, sessionId });
|
||||
return;
|
||||
}
|
||||
if (userAuth) await unregisterAgentSessionForUser(userId, sessionId);
|
||||
const access = await resolveActiveSessionAccess();
|
||||
if (!access) return;
|
||||
await access.unregisterSession({ userId, sessionId });
|
||||
}
|
||||
let agentRunGateway = null;
|
||||
let chatIntentRouter = null;
|
||||
@@ -470,6 +478,19 @@ async function bootstrapUserAuth() {
|
||||
if (sessionAccess.enabled) {
|
||||
console.log('[Portal] Session Broker enabled (MEMIND_SESSION_BROKER_ENABLED=1)');
|
||||
}
|
||||
const routerDecisionMode = resolveNormalizedRouterDecisionMode(process.env);
|
||||
const h5SessionFlags = [
|
||||
sessionAccess.enabled && 'MEMIND_SESSION_BROKER_ENABLED',
|
||||
isSessionBrokerMetricsEnabled() && 'MEMIND_SESSION_BROKER_METRICS',
|
||||
routerDecisionMode !== 'off' && `MEMIND_ROUTER_NORMALIZED_DECISION=${routerDecisionMode}`,
|
||||
isSessionStreamReplayEnabled() && 'MEMIND_SESSION_STREAM_REPLAY',
|
||||
['1', 'true', 'yes', 'on'].includes(String(process.env.MEMIND_SSE_EVENT_TAXONOMY ?? '').trim().toLowerCase()) && 'MEMIND_SSE_EVENT_TAXONOMY',
|
||||
['1', 'true', 'yes', 'on'].includes(String(process.env.MEMIND_RUN_STREAM_REPLAY ?? '').trim().toLowerCase()) && 'MEMIND_RUN_STREAM_REPLAY',
|
||||
['1', 'true', 'yes', 'on'].includes(String(process.env.MEMIND_H5_HTML_FINISH_GUARD ?? '').trim().toLowerCase()) && 'MEMIND_H5_HTML_FINISH_GUARD',
|
||||
].filter(Boolean);
|
||||
if (h5SessionFlags.length) {
|
||||
console.log(`[Portal] H5 session flags: ${h5SessionFlags.join(', ')}`);
|
||||
}
|
||||
wechatPayClient = createWechatPayClient(loadWechatPayConfig());
|
||||
wechatOAuthService = createWechatOAuthService(pool, loadWechatOAuthConfig(), { userAuth });
|
||||
rechargeService = createRechargeService(pool, {
|
||||
@@ -575,6 +596,9 @@ async function bootstrapUserAuth() {
|
||||
conversationMemoryService,
|
||||
memoryV2,
|
||||
});
|
||||
if (isSessionStreamReplayEnabled()) {
|
||||
sessionStreamStore = createSessionStreamStore({ pool });
|
||||
}
|
||||
directChatService = createDirectChatService({
|
||||
userAuth,
|
||||
sessionAccess,
|
||||
@@ -595,6 +619,7 @@ async function bootstrapUserAuth() {
|
||||
apiSecret: API_SECRET,
|
||||
userAuth,
|
||||
sessionAccess,
|
||||
sessionStreamStore,
|
||||
llmProviderService,
|
||||
subscriptionService,
|
||||
sessionSnapshotService,
|
||||
|
||||
Reference in New Issue
Block a user