收口 MNote P0 P1 P2 审查尾项
- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目 - 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线 - 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径 验证: - cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1 - cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1 - git diff --check - git diff --cached --check - codegraph index . --force && codegraph status . - codegraph sync . && codegraph status .
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
export function createSidebarPageAiProfileRuntime(context) {
|
||||
const {
|
||||
chatOnlyProfileRegistry,
|
||||
documentRef,
|
||||
pageAiAgentRecord,
|
||||
pageAiCurrentAgentId,
|
||||
pageAiNormalizeAgentId,
|
||||
pageUiState,
|
||||
} = context;
|
||||
const PAGE_AI_CHAT_ONLY_PROFILE_REGISTRY = Array.isArray(chatOnlyProfileRegistry) ? chatOnlyProfileRegistry : [];
|
||||
|
||||
function pageAiProviderLabel(provider) {
|
||||
if (provider === 'codex') return 'Codex';
|
||||
if (provider === 'claudecode') return 'ClaudeCode';
|
||||
return 'Hermes';
|
||||
}
|
||||
|
||||
function pageAiNormalizeArray(value) {
|
||||
return Array.isArray(value) ? value : [];
|
||||
}
|
||||
|
||||
function pageAiDefaultAcpRuntimes() {
|
||||
return [
|
||||
{
|
||||
name: 'reasonix',
|
||||
title: 'ACP · Reasonix',
|
||||
description: '通过 ACP 协议直连 Reasonix(DeepSeek 缓存优先)',
|
||||
model: 'deepseek-chat',
|
||||
preset: 'auto'
|
||||
},
|
||||
{
|
||||
name: 'hermes',
|
||||
title: 'ACP · Hermes',
|
||||
description: '通过 ACP 协议直连 Hermes agent runtime'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
function pageAiNormalizeAcpRuntimes(runtimes) {
|
||||
var byName = {};
|
||||
pageAiDefaultAcpRuntimes().forEach(function(runtime) {
|
||||
byName[runtime.name] = Object.assign({}, runtime);
|
||||
});
|
||||
pageAiNormalizeArray(runtimes).forEach(function(runtime) {
|
||||
var name = String(runtime && runtime.name || '').trim();
|
||||
if (name !== 'reasonix' && name !== 'hermes') return;
|
||||
byName[name] = Object.assign({}, byName[name] || {}, runtime, { name: name });
|
||||
});
|
||||
return ['reasonix', 'hermes'].map(function(name) { return byName[name]; }).filter(Boolean);
|
||||
}
|
||||
|
||||
function pageAiUnwrapUpstream(payload) {
|
||||
if (payload && typeof payload === 'object' && payload.upstream) return payload.upstream;
|
||||
return payload || null;
|
||||
}
|
||||
|
||||
function pageAiProfileValue(profile) {
|
||||
if (profile && typeof profile === 'object') {
|
||||
return String(profile.profileId || profile.name || profile.profile || profile.id || '').trim();
|
||||
}
|
||||
return String(profile || '').trim();
|
||||
}
|
||||
|
||||
function pageAiCurrentProfile() {
|
||||
var active = String(pageUiState.pageAiActiveProfileName || '').trim();
|
||||
if (active) return active;
|
||||
var selected = pageUiState.pageAiProfiles.find(function(profile) {
|
||||
return profile && profile.active;
|
||||
});
|
||||
return pageAiProfileValue(selected) || 'mnoteai';
|
||||
}
|
||||
|
||||
function pageAiRunProfile() {
|
||||
if (String(pageUiState.pageAiAcpRuntime || 'reasonix').trim() === 'reasonix') return 'reasonix';
|
||||
if (pageAiCurrentAgentId() === 'chat_only') return pageAiNormalizeChatOnlyProfileId(pageAiCurrentProfile());
|
||||
return pageAiCurrentProfile();
|
||||
}
|
||||
|
||||
function pageAiMnoteToolModel() {
|
||||
var doc = documentRef || document;
|
||||
return String(doc.documentElement.getAttribute('data-mnote-page-ai-tool-model') || 'deepseek-v4-flash').trim() || 'deepseek-v4-flash';
|
||||
}
|
||||
|
||||
function pageAiCurrentProfileRecord() {
|
||||
var active = pageAiCurrentProfile();
|
||||
return pageUiState.pageAiProfiles.find(function(profile) {
|
||||
return pageAiProfileValue(profile) === active;
|
||||
}) || null;
|
||||
}
|
||||
|
||||
function pageAiChatOnlyProfileSpec(profile) {
|
||||
var profileId = pageAiProfileValue(profile);
|
||||
var baseProfile = String(profile && profile.baseProfile || '').trim();
|
||||
var isolatedProfile = String(profile && profile.isolatedProfile || '').trim();
|
||||
return PAGE_AI_CHAT_ONLY_PROFILE_REGISTRY.find(function(spec) {
|
||||
return spec.profileId === profileId || spec.baseProfile === baseProfile || isolatedProfile.indexOf(spec.baseProfile) >= 0;
|
||||
}) || null;
|
||||
}
|
||||
|
||||
function pageAiDefaultChatOnlyProfileSpec() {
|
||||
return PAGE_AI_CHAT_ONLY_PROFILE_REGISTRY[0] || { profileId: 'shared_deepseek_chat', baseProfile: 'deepseek-chat', label: 'DeepSeek' };
|
||||
}
|
||||
|
||||
function pageAiNormalizeChatOnlyProfileId(profileId) {
|
||||
var profile = pageAiProfileRecordById(profileId) || { profileId: String(profileId || '').trim(), name: String(profileId || '').trim() };
|
||||
var spec = pageAiChatOnlyProfileSpec(profile);
|
||||
return (spec || pageAiDefaultChatOnlyProfileSpec()).profileId;
|
||||
}
|
||||
|
||||
function pageAiProfileDisplayLabel(profile, fallback) {
|
||||
var alias = String(profile && profile.alias || '').trim();
|
||||
var displayName = String(profile && (profile.displayName || profile.label || '') || '').trim();
|
||||
var name = pageAiProfileValue(profile);
|
||||
return alias || displayName || fallback || name || 'default';
|
||||
}
|
||||
|
||||
function pageAiProfileRecordById(profileId) {
|
||||
var normalized = String(profileId || '').trim();
|
||||
if (!normalized) return null;
|
||||
return pageAiNormalizeArray(pageUiState.pageAiProfiles).find(function(profile) {
|
||||
return pageAiProfileValue(profile) === normalized;
|
||||
}) || null;
|
||||
}
|
||||
|
||||
function pageAiSessionAgentFilterValue(session) {
|
||||
var agentId = pageAiNormalizeAgentId(session && session.agentId);
|
||||
if (agentId === 'reasonix') return 'reasonix';
|
||||
var profileId = String(session && (session.profileId || session.profile) || '').trim();
|
||||
if (agentId === 'chat_only') profileId = pageAiNormalizeChatOnlyProfileId(profileId);
|
||||
return agentId + ':' + profileId;
|
||||
}
|
||||
|
||||
function pageAiSessionAgentLabel(session) {
|
||||
var agentId = pageAiNormalizeAgentId(session && session.agentId);
|
||||
if (agentId === 'reasonix') return 'Reasonix';
|
||||
var profileId = String(session && (session.profileId || session.profile) || '').trim();
|
||||
var profile = pageAiProfileRecordById(profileId) || { profileId: profileId, name: profileId };
|
||||
var chatOnlySpec = pageAiChatOnlyProfileSpec(profile);
|
||||
if (agentId === 'chat_only') {
|
||||
return 'ChatOnly / ' + (chatOnlySpec || pageAiDefaultChatOnlyProfileSpec()).label;
|
||||
}
|
||||
if (agentId === 'hermes') return 'Hermes / ' + pageAiProfileDisplayLabel(profile, profileId);
|
||||
return pageAiAgentRecord(agentId).label;
|
||||
}
|
||||
|
||||
function pageAiSessionPreviewText(session) {
|
||||
var preview = Array.isArray(session && session.messages) && session.messages.length
|
||||
? String(session.messages.slice(-1)[0].content || '')
|
||||
: String(session && (session.snippet || session.preview || '暂无消息') || '暂无消息');
|
||||
preview = preview.replace(/\s+/g, ' ').trim();
|
||||
var limit = 96;
|
||||
return preview.length > limit ? preview.slice(0, limit) + '…' : preview;
|
||||
}
|
||||
|
||||
function pageAiSessionAgentFilterOptions(rows) {
|
||||
var byValue = { all: '全部 agent' };
|
||||
pageAiNormalizeArray(rows).forEach(function(session) {
|
||||
var value = pageAiSessionAgentFilterValue(session);
|
||||
byValue[value] = pageAiSessionAgentLabel(session);
|
||||
});
|
||||
return Object.keys(byValue).map(function(value) {
|
||||
return { value: value, label: byValue[value] };
|
||||
});
|
||||
}
|
||||
|
||||
function pageAiFilteredHistoryRows(rows) {
|
||||
var filterValue = String(pageUiState.pageAiSessionAgentFilter || 'all').trim() || 'all';
|
||||
var normalized = pageAiNormalizeArray(rows);
|
||||
if (filterValue === 'all') return normalized;
|
||||
return normalized.filter(function(session) {
|
||||
return pageAiSessionAgentFilterValue(session) === filterValue;
|
||||
});
|
||||
}
|
||||
|
||||
function pageAiTimestamp(value) {
|
||||
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
||||
if (typeof value === 'string' && value.trim()) {
|
||||
var parsed = Date.parse(value);
|
||||
if (Number.isFinite(parsed)) return parsed;
|
||||
}
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
function pageAiUsageSummary(usage) {
|
||||
if (!usage || typeof usage !== 'object') return '';
|
||||
var used = usage.used ?? usage.contextUsed ?? usage.input_tokens ?? usage.inputTokens ?? usage.prompt_tokens ?? usage.promptTokens;
|
||||
var size = usage.size ?? usage.contextSize ?? usage.total_tokens ?? usage.totalTokens;
|
||||
var output = usage.output_tokens ?? usage.outputTokens ?? usage.completion_tokens ?? usage.completionTokens;
|
||||
var parts = [];
|
||||
if (Number.isFinite(Number(used))) parts.push('ctx ' + Number(used));
|
||||
if (Number.isFinite(Number(size)) && Number(size) > 0) parts.push('/ ' + Number(size));
|
||||
if (Number.isFinite(Number(output)) && Number(output) > 0) parts.push('out ' + Number(output));
|
||||
return parts.join(' ') || '';
|
||||
}
|
||||
|
||||
return {
|
||||
pageAiProviderLabel,
|
||||
pageAiNormalizeArray,
|
||||
pageAiDefaultAcpRuntimes,
|
||||
pageAiNormalizeAcpRuntimes,
|
||||
pageAiUnwrapUpstream,
|
||||
pageAiProfileValue,
|
||||
pageAiCurrentProfile,
|
||||
pageAiRunProfile,
|
||||
pageAiMnoteToolModel,
|
||||
pageAiCurrentProfileRecord,
|
||||
pageAiChatOnlyProfileSpec,
|
||||
pageAiDefaultChatOnlyProfileSpec,
|
||||
pageAiNormalizeChatOnlyProfileId,
|
||||
pageAiProfileDisplayLabel,
|
||||
pageAiProfileRecordById,
|
||||
pageAiSessionAgentFilterValue,
|
||||
pageAiSessionAgentLabel,
|
||||
pageAiSessionPreviewText,
|
||||
pageAiSessionAgentFilterOptions,
|
||||
pageAiFilteredHistoryRows,
|
||||
pageAiTimestamp,
|
||||
pageAiUsageSummary
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user