refactor: Business logic and dependencies updates

- 核心服务代码更新 (db, server, auth, proxy)
- Agent 相关模块更新 (mindspace, experience)
- 前端组件和 hooks 更新
- 数据库 schema 更新
- 依赖版本更新
This commit is contained in:
john
2026-06-27 08:25:02 +08:00
parent f1220a7905
commit 25f8223253
20 changed files with 1458 additions and 116 deletions
+53 -4
View File
@@ -6,6 +6,7 @@ import { evaluateProxyRequest, isNativeH5ApiPath } from './policies.mjs';
import { buildSandboxSessionConstraints } from './user-publish.mjs';
import { buildTaskRoutingAgentText } from './user-memory-profile.mjs';
import { reconcileAgentSession } from './session-reconcile.mjs';
import { createImgproxySigner } from './imgproxy-signer.mjs';
const insecureDispatcher = new Agent({
connect: { rejectUnauthorized: false },
@@ -158,6 +159,7 @@ export async function buildVisionPayload({
publishLayout,
localFetchAsset,
llmProviderService,
imgproxySigner = null,
}) {
if (!localFetchAsset || !llmProviderService || !userId) return null;
const rawImageUrls = extractImageUrlsFromMessage(userMessage);
@@ -166,10 +168,39 @@ export async function buildVisionPayload({
const imageItems = [];
for (const rawUrl of rawImageUrls) {
try {
const match = rawUrl.match(/\/mindspace\/v1\/assets\/([^/?#]+)\/download/);
const match = rawUrl.match(/\/mindspace\/v1\/assets\/([^/?#]+)(?:\/download)?/);
if (!match) continue;
const assetId = decodeURIComponent(match[1]);
const { buffer, mimeType } = await localFetchAsset(userId, assetId);
let buffer;
let mimeType = 'image/jpeg';
if (imgproxySigner) {
try {
const visionUrl = imgproxySigner.buildUrl(
process.env.IMGPROXY_BASE_URL || 'https://img.tkmind.cn',
`users/${userId}/assets/${assetId}`,
'vision'
);
const visionResponse = await undiciFetch(visionUrl);
if (visionResponse.ok) {
buffer = Buffer.from(await visionResponse.arrayBuffer());
mimeType = visionResponse.headers.get('content-type') || 'image/jpeg';
} else {
throw new Error(`Vision fetch failed: ${visionResponse.status}`);
}
} catch (visionErr) {
console.warn(`Vision fetch fallback for asset ${assetId}:`, visionErr instanceof Error ? visionErr.message : visionErr);
const asset = await localFetchAsset(userId, assetId);
buffer = asset.buffer;
mimeType = asset.mimeType;
}
} else {
const asset = await localFetchAsset(userId, assetId);
buffer = asset.buffer;
mimeType = asset.mimeType;
}
let relativePath = rawUrl;
try {
const parsed = new URL(rawUrl);
@@ -240,6 +271,19 @@ export function createTkmindProxy({ apiTarget, apiTargets, apiSecret, userAuth,
const primaryTarget = targets[0] ?? apiTarget ?? '';
let rrIdx = 0;
let imgproxySigner = null;
if (process.env.IMGPROXY_BASE_URL && process.env.IMGPROXY_SIGNING_KEY && process.env.IMGPROXY_SIGNING_SALT) {
try {
imgproxySigner = createImgproxySigner(
process.env.IMGPROXY_SIGNING_KEY,
process.env.IMGPROXY_SIGNING_SALT,
);
console.log('[TKMindProxy] imgproxy signer initialized');
} catch (err) {
console.warn('[TKMindProxy] imgproxy signer init failed:', err instanceof Error ? err.message : err);
}
}
async function targetHealthy(target) {
try {
const upstream = await apiFetch(target, apiSecret, '/status', {
@@ -265,7 +309,11 @@ export function createTkmindProxy({ apiTarget, apiTargets, apiSecret, userAuth,
async function resolveTarget(sessionId) {
if (targets.length <= 1 || !sessionId) return primaryTarget;
try {
const node = await userAuth.getSessionNode(sessionId);
const { target, node } = await userAuth.getSessionTarget(sessionId);
// Prefer the pinned URL: stable across reordering/resizing the target list.
// Only honor it if that upstream is still configured; otherwise fall back to
// the legacy integer index, then to primary.
if (target && targets.includes(target)) return target;
return targets[node] ?? primaryTarget;
} catch {
return primaryTarget;
@@ -323,6 +371,7 @@ export function createTkmindProxy({ apiTarget, apiTargets, apiSecret, userAuth,
publishLayout,
localFetchAsset,
llmProviderService,
imgproxySigner,
});
}
@@ -416,7 +465,7 @@ export function createTkmindProxy({ apiTarget, apiTargets, apiSecret, userAuth,
await userAuth.registerAgentSession(
req.currentUser.id,
session.id,
Math.max(0, targets.indexOf(startTarget)),
startTarget,
);
if (sessionPolicy.gooseMode) {
const modeRes = await apiFetch(startTarget, apiSecret, '/agent/update_session', {