2026-06-01 09:29:12 +08:00
|
|
|
export function createSidebarPageAiSkillRuntime(context) {
|
|
|
|
|
const {
|
|
|
|
|
pageAiCurrentAgentId,
|
|
|
|
|
pageAiCurrentProfile,
|
|
|
|
|
pageAiLoadSkills,
|
|
|
|
|
pageAiNormalizeArray,
|
|
|
|
|
pageAiPersistAiPreference,
|
|
|
|
|
pageAiPersistRawAiPreference,
|
|
|
|
|
pageAiProfileValue,
|
|
|
|
|
pageUiState,
|
|
|
|
|
renderPageAiControls,
|
|
|
|
|
} = context;
|
|
|
|
|
|
|
|
|
|
function pageAiSkillSourceOptions() {
|
|
|
|
|
var options = [
|
2026-06-05 23:00:53 +08:00
|
|
|
{ value: 'mnote', group: 'mnote', label: 'MNote 公共能力', profile: '' },
|
|
|
|
|
{ value: 'reasonix', group: 'reasonix', label: 'Reasonix skill(查看)', profile: '', readonly: true }
|
2026-06-01 09:29:12 +08:00
|
|
|
];
|
|
|
|
|
pageAiNormalizeArray(pageUiState.pageAiProfiles).forEach(function(profile) {
|
|
|
|
|
var profileId = pageAiProfileValue(profile);
|
2026-06-05 23:00:53 +08:00
|
|
|
if (!profileId || pageAiProfileIsChatOnlySkillSource(profile)) return;
|
|
|
|
|
var label = profile.kind === 'shared' ? 'Hermes 共享 skill(查看)' : 'Hermes skill(查看)';
|
|
|
|
|
var alias = String(profile.alias || profile.displayName || '').trim();
|
2026-06-01 09:29:12 +08:00
|
|
|
options.push({
|
|
|
|
|
value: 'hermes:' + profileId,
|
|
|
|
|
group: 'hermes',
|
|
|
|
|
profile: profileId,
|
|
|
|
|
label: alias && alias !== label ? label + ' · ' + alias : label,
|
2026-06-05 23:00:53 +08:00
|
|
|
readonly: true
|
2026-06-01 09:29:12 +08:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-05 23:00:53 +08:00
|
|
|
function pageAiProfileIsChatOnlySkillSource(profile) {
|
|
|
|
|
var profileId = String(pageAiProfileValue(profile) || '').trim().toLowerCase();
|
|
|
|
|
var baseProfile = String(profile && profile.baseProfile || '').trim().toLowerCase();
|
|
|
|
|
var label = String(profile && (profile.displayName || profile.alias || profile.name) || '').trim().toLowerCase();
|
|
|
|
|
var providerKind = String(profile && profile.providerKind || '').trim().toLowerCase();
|
|
|
|
|
return profileId.indexOf('chat') >= 0
|
|
|
|
|
|| baseProfile.indexOf('chat') >= 0
|
|
|
|
|
|| label.indexOf('chat') >= 0
|
|
|
|
|
|| providerKind.indexOf('chat') >= 0
|
|
|
|
|
|| profileId === 'shared_lite'
|
|
|
|
|
|| baseProfile === 'lite';
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-01 09:29:12 +08:00
|
|
|
function pageAiDefaultSkillSource() {
|
|
|
|
|
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,
|
2026-06-05 23:00:53 +08:00
|
|
|
categoryTitle: skill.categoryTitle || category.title || category.name || '',
|
2026-06-01 09:29:12 +08:00
|
|
|
id: id,
|
|
|
|
|
name: skill.name || id,
|
|
|
|
|
title: skill.title || skill.name || id,
|
|
|
|
|
description: skill.description || '',
|
2026-06-05 23:00:53 +08:00
|
|
|
enabled: group === 'mnote' ? (skill.enabled !== false && overrides[id] !== false) : skill.enabled !== false,
|
|
|
|
|
toggleable: group === 'mnote' && skill.toggleable !== false,
|
2026-06-01 09:29:12 +08:00
|
|
|
source: skill.source || group,
|
|
|
|
|
origin: skill.origin || '',
|
2026-06-05 23:00:53 +08:00
|
|
|
readOnly: group !== 'mnote' || skill.readOnly === true || skill.readonly === true || skill.configurable === false,
|
2026-06-01 09:29:12 +08:00
|
|
|
builtin: pageAiSkillIsBuiltin(skill),
|
|
|
|
|
configurable: skill.configurable !== false,
|
|
|
|
|
configScope: skill.configScope || '',
|
|
|
|
|
skillKind: skill.skillKind || '',
|
|
|
|
|
profileId: skill.profileId || '',
|
|
|
|
|
toolNames: skill.toolNames || [],
|
2026-06-05 23:00:53 +08:00
|
|
|
tools: skill.tools || [],
|
|
|
|
|
toolCount: Number(skill.toolCount || 0),
|
|
|
|
|
disabledToolCount: Number(skill.disabledToolCount || 0),
|
|
|
|
|
status: skill.status || '',
|
|
|
|
|
capabilityId: skill.capabilityId || '',
|
|
|
|
|
capabilityKind: skill.capabilityKind || '',
|
|
|
|
|
uiKind: skill.uiKind || '',
|
2026-06-01 09:29:12 +08:00
|
|
|
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',
|
2026-06-05 23:00:53 +08:00
|
|
|
categoryTitle: skill.categoryTitle || 'archived',
|
2026-06-01 09:29:12 +08:00
|
|
|
id: id,
|
|
|
|
|
name: skill.name || id,
|
|
|
|
|
title: skill.title || skill.name || id,
|
|
|
|
|
description: skill.description || '',
|
2026-06-05 23:00:53 +08:00
|
|
|
enabled: group === 'mnote' ? (skill.enabled !== false && overrides[id] !== false) : skill.enabled !== false,
|
|
|
|
|
toggleable: group === 'mnote' && skill.toggleable !== false,
|
2026-06-01 09:29:12 +08:00
|
|
|
source: skill.source || group,
|
|
|
|
|
origin: skill.origin || '',
|
2026-06-05 23:00:53 +08:00
|
|
|
readOnly: group !== 'mnote' || skill.readOnly === true || skill.readonly === true || skill.configurable === false,
|
2026-06-01 09:29:12 +08:00
|
|
|
builtin: pageAiSkillIsBuiltin(skill),
|
|
|
|
|
configurable: skill.configurable !== false,
|
|
|
|
|
configScope: skill.configScope || '',
|
|
|
|
|
skillKind: skill.skillKind || '',
|
|
|
|
|
profileId: skill.profileId || '',
|
|
|
|
|
toolNames: skill.toolNames || [],
|
2026-06-05 23:00:53 +08:00
|
|
|
tools: skill.tools || [],
|
|
|
|
|
toolCount: Number(skill.toolCount || 0),
|
|
|
|
|
disabledToolCount: Number(skill.disabledToolCount || 0),
|
|
|
|
|
status: skill.status || '',
|
|
|
|
|
capabilityId: skill.capabilityId || '',
|
|
|
|
|
capabilityKind: skill.capabilityKind || '',
|
|
|
|
|
uiKind: skill.uiKind || '',
|
2026-06-01 09:29:12 +08:00
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
}
|