Files
mnote/rust/crates/mnote-web/browser/sidebar-page-ai-skill-runtime.js
T
lix-2026 1882db7681 收口 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 .
2026-06-01 09:29:12 +08:00

286 lines
11 KiB
JavaScript

export function createSidebarPageAiSkillRuntime(context) {
const {
pageAiCurrentAgentId,
pageAiCurrentProfile,
pageAiLoadSkills,
pageAiNormalizeArray,
pageAiPersistAiPreference,
pageAiPersistRawAiPreference,
pageAiProfileValue,
pageUiState,
renderPageAiControls,
} = context;
function pageAiSkillSourceOptions() {
var options = [
{ value: 'mnote', group: 'mnote', label: 'mnote', profile: '' },
{ value: 'reasonix', group: 'reasonix', label: 'reasonix', profile: '' }
];
pageAiNormalizeArray(pageUiState.pageAiProfiles).forEach(function(profile) {
var profileId = pageAiProfileValue(profile);
if (!profileId) return;
var label = profile.kind === 'shared'
? (profile.baseProfile === 'lite' || profileId === 'shared_lite' ? 'hermes_lite' : 'Hermes_shared')
: 'Hermes_user';
var alias = String(profile.alias || '').trim();
options.push({
value: 'hermes:' + profileId,
group: 'hermes',
profile: profileId,
label: alias && alias !== label ? label + ' · ' + alias : label,
readonly: profile.readonly === true
});
});
return options;
}
function pageAiDefaultSkillSource() {
if (pageAiCurrentAgentId() === 'hermes') return 'hermes:' + pageAiCurrentProfile();
if (pageAiCurrentAgentId() === 'reasonix') return 'reasonix';
return 'mnote';
}
function pageAiNormalizeSkillSource(source) {
var value = String(source || '').trim();
var options = pageAiSkillSourceOptions();
if (options.some(function(option) { return option.value === value; })) return value;
if (value === 'hermes') return 'hermes:' + pageAiCurrentProfile();
if (value === 'mnote_builtin') return 'mnote';
var fallback = pageAiDefaultSkillSource();
if (options.some(function(option) { return option.value === fallback; })) return fallback;
return options.length ? options[0].value : 'mnote';
}
function pageAiCurrentSkillSource() {
var normalized = pageAiNormalizeSkillSource(pageUiState.pageAiActiveSkillSource);
pageUiState.pageAiActiveSkillSource = normalized;
return normalized;
}
function pageAiSetSkillSource(source) {
var normalized = pageAiNormalizeSkillSource(source);
pageUiState.pageAiActiveSkillSource = normalized;
pageAiPersistAiPreference('skills.active_source', normalized);
pageUiState.pageAiSkills = { categories: [], archived: [] };
pageUiState.pageAiSkillError = '';
void pageAiLoadSkills();
renderPageAiControls();
}
function pageAiSkillSourceParts(source) {
var normalized = pageAiNormalizeSkillSource(source);
if (normalized.indexOf('hermes:') === 0) {
return { group: 'hermes', profile: normalized.slice('hermes:'.length), source: normalized };
}
if (normalized === 'reasonix') return { group: 'reasonix', profile: '', source: normalized };
return { group: 'mnote', profile: '', source: 'mnote' };
}
function pageAiCurrentSkillSourceLabel() {
var source = pageAiCurrentSkillSource();
var option = pageAiSkillSourceOptions().find(function(item) { return item.value === source; });
return option ? option.label : source;
}
function pageAiSkillOriginLabel(skill) {
var origin = String(skill && skill.origin || '').trim();
if (origin === 'generated' || String(skill && skill.createdBy || '') === 'agent') return '生成';
if (origin === 'installed') return '安装';
if (origin === 'builtin') return '内置';
if (origin === 'copied') return '本地';
var source = String(skill && skill.source || '').trim();
if (source === 'hub') return '安装';
if (source === 'builtin') return '内置';
if (source === 'reasonix') {
if (origin === 'project') return 'Reasonix 项目';
if (origin === 'global') return 'Reasonix 全局';
return 'Reasonix';
}
return '本地';
}
function pageAiSkillPreferenceKey(group, profile) {
var groupName = String(group || '').trim();
if (groupName === 'mnote') return 'ai.agent.mnote_builtin.skills.enabled';
if (groupName === 'reasonix') return 'ai.agent.reasonix.skills.enabled';
if (groupName === 'hermes') {
var nextProfile = String(profile || pageAiCurrentProfile() || 'default').trim() || 'default';
return 'ai.agent.hermes.profile.' + nextProfile + '.skills.enabled';
}
return '';
}
function pageAiSkillPreferenceTable(group, profile) {
var key = pageAiSkillPreferenceKey(group, profile);
var preferences = pageUiState.pageAiSkillPreferences || {};
var value = preferences[key];
if (value && typeof value === 'object' && !Array.isArray(value)) return value;
return {};
}
function pageAiHermesHideBuiltinPreferenceKey(profile) {
return 'ai.agent.hermes.skills.hide_builtin';
}
function pageAiHideHermesBuiltinSkills(profile) {
var preferences = pageUiState.pageAiSkillPreferences || {};
return preferences[pageAiHermesHideBuiltinPreferenceKey(profile)] === true;
}
function pageAiReasonixMemoryEnabled() {
var preferences = pageUiState.pageAiSkillPreferences || {};
return preferences['ai.agent.reasonix.memory_enabled'] === true;
}
function pageAiSetReasonixMemoryEnabled(enabled) {
var preferences = Object.assign({}, pageUiState.pageAiSkillPreferences || {});
preferences['ai.agent.reasonix.memory_enabled'] = Boolean(enabled);
pageUiState.pageAiSkillPreferences = preferences;
pageAiPersistRawAiPreference('ai.agent.reasonix.memory_enabled', Boolean(enabled));
renderPageAiControls();
}
function pageAiSetHideHermesBuiltinSkills(enabled, profile) {
var key = pageAiHermesHideBuiltinPreferenceKey(profile);
var preferences = Object.assign({}, pageUiState.pageAiSkillPreferences || {});
preferences[key] = Boolean(enabled);
pageUiState.pageAiSkillPreferences = preferences;
pageAiPersistRawAiPreference(key, Boolean(enabled));
renderPageAiControls();
}
function pageAiSkillIsBuiltin(skill) {
var origin = String(skill && skill.origin || '').trim();
var source = String(skill && skill.source || '').trim();
return origin === 'builtin' || source === 'builtin';
}
function pageAiToggleableSkillEntries(group, profile) {
var catalogKey = group === 'hermes' && profile ? 'hermes:' + profile : group;
var catalog = pageUiState.pageAiSkillCatalogs && pageUiState.pageAiSkillCatalogs[catalogKey]
? pageUiState.pageAiSkillCatalogs[catalogKey]
: pageUiState.pageAiSkillCatalogs && pageUiState.pageAiSkillCatalogs[group]
? pageUiState.pageAiSkillCatalogs[group]
: { categories: [], archived: [] };
var overrides = pageAiSkillPreferenceTable(group, profile);
var result = [];
pageAiNormalizeArray(catalog.categories).forEach(function(category) {
pageAiNormalizeArray(category.skills).forEach(function(skill) {
var id = String(skill.id || skill.name || '').trim();
if (!id) return;
result.push({
group: group,
profile: profile || '',
category: category.name,
id: id,
name: skill.name || id,
title: skill.title || skill.name || id,
description: skill.description || '',
enabled: group === 'hermes' ? skill.enabled !== false : (skill.enabled !== false && overrides[id] !== false),
toggleable: skill.toggleable !== false,
source: skill.source || group,
origin: skill.origin || '',
readOnly: skill.readOnly === true || skill.readonly === true || skill.configurable === false,
builtin: pageAiSkillIsBuiltin(skill),
configurable: skill.configurable !== false,
configScope: skill.configScope || '',
skillKind: skill.skillKind || '',
profileId: skill.profileId || '',
toolNames: skill.toolNames || [],
requiresContextRefs: skill.requiresContextRefs || []
});
});
});
pageAiNormalizeArray(catalog.archived).forEach(function(skill) {
var id = String(skill.id || skill.name || '').trim();
if (!id) return;
result.push({
group: group,
profile: profile || '',
category: 'archived',
id: id,
name: skill.name || id,
title: skill.title || skill.name || id,
description: skill.description || '',
enabled: group === 'hermes' ? skill.enabled !== false : (skill.enabled !== false && overrides[id] !== false),
toggleable: skill.toggleable !== false,
source: skill.source || group,
origin: skill.origin || '',
readOnly: skill.readOnly === true || skill.readonly === true || skill.configurable === false,
builtin: pageAiSkillIsBuiltin(skill),
configurable: skill.configurable !== false,
configScope: skill.configScope || '',
skillKind: skill.skillKind || '',
profileId: skill.profileId || '',
toolNames: skill.toolNames || [],
requiresContextRefs: skill.requiresContextRefs || []
});
});
return result;
}
function pageAiAllSkillEntries() {
return []
.concat(pageAiToggleableSkillEntries('mnote', ''))
.concat(pageAiToggleableSkillEntries('reasonix', ''))
.concat(pageAiToggleableSkillEntries('hermes', pageAiCurrentProfile()));
}
function pageAiSkillGroupCollapsed(group) {
var table = pageUiState.pageAiCollapsedSkillGroups || {};
return table[String(group || '').trim()] === true;
}
function pageAiToggleSkillGroup(group) {
var normalized = String(group || '').trim();
if (!normalized) return;
var table = Object.assign({}, pageUiState.pageAiCollapsedSkillGroups || {});
table[normalized] = table[normalized] !== true;
pageUiState.pageAiCollapsedSkillGroups = table;
pageAiPersistRawAiPreference('ai.common.skills.groups.collapsed', table);
renderPageAiControls();
}
function pageAiSetSkillPreference(group, skillId, enabled, profile) {
var key = pageAiSkillPreferenceKey(group, profile);
if (!key || !skillId) return;
var preferences = Object.assign({}, pageUiState.pageAiSkillPreferences || {});
var current = preferences[key] && typeof preferences[key] === 'object' && !Array.isArray(preferences[key])
? Object.assign({}, preferences[key])
: {};
current[skillId] = Boolean(enabled);
preferences[key] = current;
pageUiState.pageAiSkillPreferences = preferences;
pageAiPersistRawAiPreference(key, current);
}
function pageAiSkillEnabled(skill) {
return skill.enabled !== false;
}
return {
pageAiSkillSourceOptions,
pageAiDefaultSkillSource,
pageAiNormalizeSkillSource,
pageAiCurrentSkillSource,
pageAiSetSkillSource,
pageAiSkillSourceParts,
pageAiCurrentSkillSourceLabel,
pageAiSkillOriginLabel,
pageAiSkillPreferenceKey,
pageAiSkillPreferenceTable,
pageAiHermesHideBuiltinPreferenceKey,
pageAiHideHermesBuiltinSkills,
pageAiReasonixMemoryEnabled,
pageAiSetReasonixMemoryEnabled,
pageAiSetHideHermesBuiltinSkills,
pageAiSkillIsBuiltin,
pageAiToggleableSkillEntries,
pageAiAllSkillEntries,
pageAiSkillGroupCollapsed,
pageAiToggleSkillGroup,
pageAiSetSkillPreference,
pageAiSkillEnabled
};
}