Files
mnote/rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js
T

3579 lines
163 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createSidebarPageAiMarkdownRuntime } from './sidebar-page-ai-markdown-runtime.js';
import { createSidebarPageAiPermissionRuntime } from './sidebar-page-ai-permission-runtime.js';
import { createSidebarPageAiProfileRuntime } from './sidebar-page-ai-profile-runtime.js';
import { createSidebarPageAiRenderRuntime } from './sidebar-page-ai-render-runtime.js';
import { createSidebarPageAiSessionRuntime } from './sidebar-page-ai-session-runtime.js';
import { createSidebarPageAiSkillRuntime } from './sidebar-page-ai-skill-runtime.js';
import { createSidebarPageAiTargetRuntime } from './sidebar-page-ai-target-runtime.js';
export function createSidebarPageAiRuntime(context) {
const {
buildLocalFileOpenUrl,
currentDocumentId,
currentPageAggregate,
currentPageOptions,
currentRootUri,
currentSourceKind,
escapeHtml,
cssEscape,
openLocalResourceInActiveTab,
pageUiState,
resolveWorkspaceId,
searchText,
} = context;
var PAGE_AI_SESSION_STORAGE_VERSION = 3;
// Page AI 请求合同:agentId 只负责路由;contextRefs 是用户勾选的上下文地址;
// allowedRoots 只展示 SQLite directory_grants 解析结果,服务端仍会按当前用户重算;
// runTargetSnapshot 必须来自 OpenEditorsSnapshot,避免运行中 UI 切换导致目标漂移。
var PAGE_AI_AGENT_FALLBACK_REGISTRY = [
{ id: 'hermes', label: 'Hermes', acpRuntime: 'hermes', canWriteFiles: true },
{ id: 'reasonix', label: 'Reasonix', acpRuntime: 'reasonix', canWriteFiles: true },
{ id: 'chat_only', label: 'Chat-only', acpRuntime: 'hermes', canWriteFiles: false }
];
var PAGE_AI_DESCRIPTOR_SCHEMA = 'mnote.ai_agent_descriptor.v1';
var PAGE_AI_CHAT_ONLY_PROFILE_REGISTRY = [
{ profileId: 'shared_deepseek_chat', baseProfile: 'deepseek-chat', label: 'DeepSeek' },
{ profileId: 'shared_doubao_chat', baseProfile: 'doubao-chat', label: '豆包' },
{ profileId: 'shared_gemini_chat', baseProfile: 'gemini-chat', label: 'Gemini' },
{ profileId: 'shared_api_deepseek_flash_chat', baseProfile: 'api-deepseek-flash-chat', label: 'DeepSeek Flash', providerKind: 'api-chat' },
{ profileId: 'shared_api_deepseek_pro_chat', baseProfile: 'api-deepseek-pro-chat', label: 'DeepSeek Pro', providerKind: 'api-chat' },
{ profileId: 'shared_api_gpt_chat', baseProfile: 'api-gpt-chat', label: 'GPT', providerKind: 'api-chat' },
{ profileId: 'shared_api_kimi_chat', baseProfile: 'api-kimi-chat', label: 'Kimi', providerKind: 'api-chat' },
{ profileId: 'shared_api_gemini_chat', baseProfile: 'api-gemini-chat', label: 'Gemini API', providerKind: 'api-chat' },
{ profileId: 'shared_api_grok_chat', baseProfile: 'api-grok-chat', label: 'Grok API', providerKind: 'api-chat' }
];
var PAGE_AI_CONTEXT_REF_REGISTRY = [
{ id: 'current_page', label: '当前页' },
{ id: 'selection', label: '选区' },
{ id: 'active_editor', label: '打开资源' },
{ id: 'file', label: '文件' },
{ id: 'folder', label: '文件夹' },
{ id: 'changed_files', label: '最近修改' }
];
var pageAiDelegatesInstalled = false;
var PAGE_AI_DRAWER_WIDTH_STORAGE_KEY = 'mnote.page_ai.drawer_width';
var PAGE_AI_DRAWER_DEFAULT_WIDTH = 440;
var PAGE_AI_DRAWER_MIN_WIDTH = 340;
var PAGE_AI_DRAWER_MAX_WIDTH = 760;
function clonePageAiDefaultValue(value) {
if (Array.isArray(value)) return value.slice();
if (value && typeof value === 'object') return Object.assign({}, value);
return value;
}
function pageAiClampDrawerWidth(width) {
var viewportMax = Math.max(PAGE_AI_DRAWER_MIN_WIDTH, Math.min(PAGE_AI_DRAWER_MAX_WIDTH, window.innerWidth - 24));
var numeric = Number(width);
if (!Number.isFinite(numeric) || numeric <= 0) numeric = PAGE_AI_DRAWER_DEFAULT_WIDTH;
return Math.max(PAGE_AI_DRAWER_MIN_WIDTH, Math.min(viewportMax, Math.round(numeric)));
}
function pageAiStoredDrawerWidth() {
try {
return pageAiClampDrawerWidth(window.localStorage ? window.localStorage.getItem(PAGE_AI_DRAWER_WIDTH_STORAGE_KEY) : PAGE_AI_DRAWER_DEFAULT_WIDTH);
} catch (_error) {
return pageAiClampDrawerWidth(PAGE_AI_DRAWER_DEFAULT_WIDTH);
}
}
function pageAiApplyDrawerWidth(drawer, width) {
var target = drawer instanceof HTMLElement ? drawer : document.querySelector('[data-testid="wolai-page-ai-drawer"]');
if (!(target instanceof HTMLElement)) return;
var next = pageAiClampDrawerWidth(width == null ? pageAiStoredDrawerWidth() : width);
target.style.setProperty('--mnote-page-ai-width', next + 'px');
}
function handlePageAiPointerDown(event, helpers) {
var closestAction = helpers && helpers.closestAction;
if (typeof closestAction !== 'function') return false;
var handle = closestAction(event.target, '[data-page-ai-resize-handle]');
if (!(handle instanceof HTMLElement)) return false;
var drawer = handle.closest('[data-testid="wolai-page-ai-drawer"]');
var panel = drawer instanceof HTMLElement ? drawer.querySelector('.wolai-page-ai-panel') : null;
if (!(drawer instanceof HTMLElement) || !(panel instanceof HTMLElement)) return false;
event.preventDefault();
var pointerId = event.pointerId;
var startX = Number(event.clientX || 0);
var startWidth = panel.getBoundingClientRect().width || pageAiStoredDrawerWidth();
drawer.setAttribute('data-page-ai-resizing', 'true');
document.documentElement.setAttribute('data-mnote-page-ai-resizing', 'true');
try {
handle.setPointerCapture(pointerId);
} catch (_error) {}
function move(nextEvent) {
var nextWidth = startWidth + (startX - Number(nextEvent.clientX || 0));
pageAiApplyDrawerWidth(drawer, nextWidth);
}
function finish(nextEvent) {
move(nextEvent);
var value = drawer.style.getPropertyValue('--mnote-page-ai-width').replace('px', '').trim();
try {
if (window.localStorage) window.localStorage.setItem(PAGE_AI_DRAWER_WIDTH_STORAGE_KEY, String(pageAiClampDrawerWidth(value)));
} catch (_error) {}
drawer.removeAttribute('data-page-ai-resizing');
document.documentElement.removeAttribute('data-mnote-page-ai-resizing');
window.removeEventListener('pointermove', move, true);
window.removeEventListener('pointerup', finish, true);
window.removeEventListener('pointercancel', finish, true);
try {
handle.releasePointerCapture(pointerId);
} catch (_error) {}
}
window.addEventListener('pointermove', move, true);
window.addEventListener('pointerup', finish, true);
window.addEventListener('pointercancel', finish, true);
return true;
}
function ensurePageAiStateFacade(state) {
var defaults = {
pageAiOpen: false,
pageAiBusy: false,
pageAiMessages: [],
pageAiSuggestionIndex: 0,
pageAiProvider: 'hermes',
pageAiPage: 'chat',
pageAiRunStatus: 'idle',
pageAiCurrentRunId: '',
pageAiAcpRuntime: 'reasonix',
pageAiAcpRuntimes: [],
pageAiQueueLength: 0,
pageAiQueuedItems: [],
pageAiStoppedRunIds: {},
pageAiAbortController: null,
pageAiContextScope: 'page',
pageAiContextPopoverOpen: false,
pageAiTargetPopoverOpen: false,
pageAiSelectedTargetId: '',
pageAiSelectedContextRefs: null,
pageAiCurrentRunTargetSnapshot: null,
pageAiAllowedRoots: [],
pageAiAllowedRootsError: '',
pageAiAgentId: 'reasonix',
pageAiAgentPopoverOpen: false,
pageAiAgentDescriptors: [],
pageAiAgentDescriptorError: '',
pageAiAgentDescriptorsLoaded: false,
pageAiTools: [],
pageAiToolsError: '',
pageAiGatewayHealth: null,
pageAiGatewayHealthError: '',
pageAiLastToolCall: null,
pageAiProfiles: [],
pageAiActiveProfileName: 'mnoteai',
pageAiProfileError: '',
pageAiProfileMemory: { memory: '', user: '', soul: '' },
pageAiProfileMemoryDrafts: { memory: '', user: '', soul: '' },
pageAiProfileMemoryError: '',
pageAiSkills: { categories: [], archived: [] },
pageAiSkillCatalogs: {
mnote: { categories: [], archived: [] },
reasonix: { categories: [], archived: [] },
hermes: { categories: [], archived: [] }
},
pageAiSkillPreferences: {},
pageAiCollapsedSkillGroups: {},
pageAiSkillQuery: '',
pageAiSkillError: '',
pageAiSkillLoadSeq: 0,
pageAiActiveSkillSource: 'mnote',
pageAiSessions: [],
pageAiActiveSessionId: '',
pageAiSessionSearchQuery: '',
pageAiSessionSearchResults: [],
pageAiSessionSearchTimer: 0,
pageAiSessionAgentFilter: 'all',
pageAiSelectedSessionIds: {},
pageAiSessionError: '',
pageAiPermissionRequests: []
};
Object.keys(defaults).forEach(function(key) {
if (typeof state[key] === 'undefined') {
state[key] = clonePageAiDefaultValue(defaults[key]);
}
});
if (!state.pageAiSkillCatalogs || typeof state.pageAiSkillCatalogs !== 'object') {
state.pageAiSkillCatalogs = clonePageAiDefaultValue(defaults.pageAiSkillCatalogs);
}
if (!state.pageAiProfileMemory || typeof state.pageAiProfileMemory !== 'object') {
state.pageAiProfileMemory = clonePageAiDefaultValue(defaults.pageAiProfileMemory);
}
if (!state.pageAiProfileMemoryDrafts || typeof state.pageAiProfileMemoryDrafts !== 'object') {
state.pageAiProfileMemoryDrafts = clonePageAiDefaultValue(defaults.pageAiProfileMemoryDrafts);
}
if (!state.pageAiSkills || typeof state.pageAiSkills !== 'object') {
state.pageAiSkills = clonePageAiDefaultValue(defaults.pageAiSkills);
}
return state;
}
ensurePageAiStateFacade(pageUiState);
function closestAction(target, selector) {
var node = target && target.nodeType === Node.TEXT_NODE ? target.parentElement : target;
return node && typeof node.closest === 'function' ? node.closest(selector) : null;
}
const pageAiMarkdown = createSidebarPageAiMarkdownRuntime({ escapeHtml });
const textFromUnknown = (...args) => pageAiMarkdown.textFromUnknown(...args);
const renderPageAiMarkdown = (...args) => pageAiMarkdown.renderPageAiMarkdown(...args);
let pageAiRenderRuntime = null;
function pageAiRenderApi() {
if (!pageAiRenderRuntime) throw new Error('page_ai_render_runtime_not_ready');
return pageAiRenderRuntime;
}
function ensurePageAiDrawer(...args) { return pageAiRenderApi().ensurePageAiDrawer(...args); }
function humanizePageAiResponse(...args) { return pageAiRenderApi().humanizePageAiResponse(...args); }
function pageAiContextButtonSummary(...args) { return pageAiRenderApi().pageAiContextButtonSummary(...args); }
function pageAiContextRefDetail(...args) { return pageAiRenderApi().pageAiContextRefDetail(...args); }
function pageAiContextRefDisabled(...args) { return pageAiRenderApi().pageAiContextRefDisabled(...args); }
function pageAiContextRefLabel(...args) { return pageAiRenderApi().pageAiContextRefLabel(...args); }
function pageAiContextScopeLabel(...args) { return pageAiRenderApi().pageAiContextScopeLabel(...args); }
function pageAiCurrentAgentSelectionLabel(...args) { return pageAiRenderApi().pageAiCurrentAgentSelectionLabel(...args); }
function pageAiCurrentModelLabel(...args) { return pageAiRenderApi().pageAiCurrentModelLabel(...args); }
function pageAiFilteredSkillEntries(...args) { return pageAiRenderApi().pageAiFilteredSkillEntries(...args); }
function pageAiFormatChangedFiles(...args) { return pageAiRenderApi().pageAiFormatChangedFiles(...args); }
function pageAiMemoryFileLabel(...args) { return pageAiRenderApi().pageAiMemoryFileLabel(...args); }
function pageAiRenderAgentProfileOption(...args) { return pageAiRenderApi().pageAiRenderAgentProfileOption(...args); }
function pageAiRunStatusLabel(...args) { return pageAiRenderApi().pageAiRunStatusLabel(...args); }
function pageAiSuggestions(...args) { return pageAiRenderApi().pageAiSuggestions(...args); }
function pageAiTargetDetail(...args) { return pageAiRenderApi().pageAiTargetDetail(...args); }
function pageAiTargetLabel(...args) { return pageAiRenderApi().pageAiTargetLabel(...args); }
function renderPageAiControls(...args) { return pageAiRenderApi().renderPageAiControls(...args); }
function renderPageAiConversation(...args) { return pageAiRenderApi().renderPageAiConversation(...args); }
function renderPageAiProviderButtons(...args) { return pageAiRenderApi().renderPageAiProviderButtons(...args); }
function renderPageAiSuggestions(...args) { return pageAiRenderApi().renderPageAiSuggestions(...args); }
function readLocalEditorBlocks() {
var editor = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror');
if (!(editor instanceof HTMLElement)) return [];
return Array.from(editor.children).filter(function(node) {
return node instanceof HTMLElement;
}).map(function(node, index) {
var tag = String(node.tagName || '').toUpperCase();
var headingMatch = tag.match(/^H([1-6])$/);
var type = headingMatch ? 'heading' : 'paragraph';
var text = searchText(node.textContent || '');
var id = searchText(node.getAttribute('data-id') || node.id || 'local-block-' + index);
var props = headingMatch ? { level: Number(headingMatch[1]) } : {};
return { id: id, type: type, props: props, content: text };
}).filter(function(block) {
return block.content || block.type === 'heading';
});
}
function buildPageAiLocalSubtree(blocks, title) {
var documentId = currentDocumentId() || 'current-page';
var rootNodeId = 'page:' + documentId;
var headingCounters = [0, 0, 0, 0, 0, 0];
var headingStack = [];
var nodes = [{
id: rootNodeId,
nodeId: rootNodeId,
nodeType: 'page',
blockId: null,
blockType: 'page',
title: title || '',
parentNodeId: null,
headingLevel: null
}];
var outline = [];
var evidence = [];
blocks.forEach(function(block, index) {
var level = block.type === 'heading' ? Math.max(1, Math.min(6, Number(block.props && block.props.level || 1))) : null;
if (level != null) {
while (headingStack.length && headingStack[headingStack.length - 1].level >= level) headingStack.pop();
}
var parentNodeId = headingStack.length ? headingStack[headingStack.length - 1].nodeId : rootNodeId;
var nodeId = 'local-node:' + String(block.id || index);
var titleText = block.content || (block.type === 'heading' ? '未命名标题' : '');
nodes.push({
id: nodeId,
nodeId: nodeId,
nodeType: 'block',
blockId: block.id,
blockType: block.type,
title: titleText,
parentNodeId: parentNodeId,
headingLevel: level
});
if (level != null) {
headingCounters[level - 1] += 1;
for (var i = level; i < headingCounters.length; i += 1) headingCounters[i] = 0;
var numbering = headingCounters.slice(0, level).filter(function(count) { return count > 0; }).join('.');
outline.push({
id: 'local-outline:' + String(block.id || index),
nodeId: nodeId,
anchorBlockId: block.id,
level: level,
title: titleText,
numbering: numbering
});
headingStack.push({ level: level, nodeId: nodeId });
}
if (titleText) {
evidence.push({
id: 'local-evidence:' + String(block.id || index),
nodeId: nodeId,
anchorBlockId: block.id,
text: titleText,
kind: block.type
});
}
});
return {
projectionId: 'local-editor-dom:' + documentId,
rootNode: {
id: rootNodeId,
documentId: documentId,
title: title || '',
nodeType: 'page'
},
subtree: {
rootNodeId: rootNodeId,
nodes: nodes
},
outline: outline,
evidence: evidence,
stats: {
nodeCount: nodes.length,
headingCount: outline.length,
evidenceCount: evidence.length
},
source: 'local'
};
}
function currentPageAiContextSnapshot() {
var aggregate = currentPageAggregate();
var body = aggregate.body || {};
var serverSubtree = aggregate.tree && aggregate.tree.pageSubtree ? aggregate.tree.pageSubtree : null;
return {
aggregate: aggregate,
body: body,
subtree: serverSubtree,
pageSubtreeSource: serverSubtree ? 'server' : 'none'
};
}
function pageAiNormalizeAgentDescriptor(descriptor) {
if (!descriptor || typeof descriptor !== 'object') return null;
var agentId = String(descriptor.agentId || descriptor.id || '').trim();
if (!agentId) return null;
return Object.assign({}, descriptor, {
id: agentId,
agentId: agentId,
label: String(descriptor.displayName || descriptor.label || agentId).trim() || agentId,
acpRuntime: String(descriptor.acpRuntime || descriptor.acp_runtime || '').trim() || (agentId === 'reasonix' ? 'reasonix' : 'hermes'),
canWriteFiles: descriptor.canWriteFiles !== false,
capabilities: pageAiNormalizeArray(descriptor.capabilities),
fields: pageAiNormalizeArray(descriptor.fields),
tools: pageAiNormalizeArray(descriptor.tools),
capabilityPacks: pageAiNormalizeArray(descriptor.capabilityPacks),
schema: String(descriptor.schema || PAGE_AI_DESCRIPTOR_SCHEMA).trim()
});
}
function pageAiAgentRegistry() {
var descriptors = pageAiNormalizeArray(pageUiState.pageAiAgentDescriptors)
.map(pageAiNormalizeAgentDescriptor)
.filter(Boolean);
return descriptors.length ? descriptors : PAGE_AI_AGENT_FALLBACK_REGISTRY;
}
function pageAiAgentDescriptor(agentId) {
var normalized = String(agentId || '').trim();
if (!normalized) normalized = pageAiCurrentAgentId();
return pageAiAgentRegistry().find(function(agent) { return agent.id === normalized || agent.agentId === normalized; }) || null;
}
function pageAiNormalizeAgentId(agentId) {
var value = String(agentId || '').trim();
return pageAiAgentRegistry().some(function(agent) { return agent.id === value; }) ? value : 'reasonix';
}
function pageAiAgentRecord(agentId) {
var normalized = pageAiNormalizeAgentId(agentId);
return pageAiAgentRegistry().find(function(agent) { return agent.id === normalized; }) || pageAiAgentRegistry()[1] || PAGE_AI_AGENT_FALLBACK_REGISTRY[1];
}
function pageAiCurrentAgentId() {
var explicit = String(pageUiState.pageAiAgentId || '').trim();
if (explicit) return pageAiNormalizeAgentId(explicit);
var runtime = String(pageUiState.pageAiAcpRuntime || 'reasonix').trim();
if (runtime === 'hermes') return 'hermes';
return 'reasonix';
}
const pageAiProfileRuntime = createSidebarPageAiProfileRuntime({
chatOnlyProfileRegistry: PAGE_AI_CHAT_ONLY_PROFILE_REGISTRY,
documentRef: document,
pageAiAgentRecord,
pageAiCurrentAgentId,
pageAiNormalizeAgentId,
pageUiState,
});
const pageAiProviderLabel = (...args) => pageAiProfileRuntime.pageAiProviderLabel(...args);
const pageAiNormalizeArray = (...args) => pageAiProfileRuntime.pageAiNormalizeArray(...args);
const pageAiDefaultAcpRuntimes = (...args) => pageAiProfileRuntime.pageAiDefaultAcpRuntimes(...args);
const pageAiNormalizeAcpRuntimes = (...args) => pageAiProfileRuntime.pageAiNormalizeAcpRuntimes(...args);
const pageAiUnwrapUpstream = (...args) => pageAiProfileRuntime.pageAiUnwrapUpstream(...args);
const pageAiProfileValue = (...args) => pageAiProfileRuntime.pageAiProfileValue(...args);
const pageAiCurrentProfile = (...args) => pageAiProfileRuntime.pageAiCurrentProfile(...args);
const pageAiRunProfile = (...args) => pageAiProfileRuntime.pageAiRunProfile(...args);
const pageAiMnoteToolModel = (...args) => pageAiProfileRuntime.pageAiMnoteToolModel(...args);
const pageAiCurrentProfileRecord = (...args) => pageAiProfileRuntime.pageAiCurrentProfileRecord(...args);
const pageAiChatOnlyProfileSpec = (...args) => pageAiProfileRuntime.pageAiChatOnlyProfileSpec(...args);
const pageAiDefaultChatOnlyProfileSpec = (...args) => pageAiProfileRuntime.pageAiDefaultChatOnlyProfileSpec(...args);
const pageAiNormalizeChatOnlyProfileId = (...args) => pageAiProfileRuntime.pageAiNormalizeChatOnlyProfileId(...args);
const pageAiProfileDisplayLabel = (...args) => pageAiProfileRuntime.pageAiProfileDisplayLabel(...args);
const pageAiProfileRecordById = (...args) => pageAiProfileRuntime.pageAiProfileRecordById(...args);
const pageAiSessionAgentFilterValue = (...args) => pageAiProfileRuntime.pageAiSessionAgentFilterValue(...args);
const pageAiSessionAgentLabel = (...args) => pageAiProfileRuntime.pageAiSessionAgentLabel(...args);
const pageAiSessionPreviewText = (...args) => pageAiProfileRuntime.pageAiSessionPreviewText(...args);
const pageAiSessionAgentFilterOptions = (...args) => pageAiProfileRuntime.pageAiSessionAgentFilterOptions(...args);
const pageAiFilteredHistoryRows = (...args) => pageAiProfileRuntime.pageAiFilteredHistoryRows(...args);
const pageAiTimestamp = (...args) => pageAiProfileRuntime.pageAiTimestamp(...args);
const pageAiUsageSummary = (...args) => pageAiProfileRuntime.pageAiUsageSummary(...args);
const pageAiPermissionRuntime = createSidebarPageAiPermissionRuntime({
documentRef: document,
pageAiPreviewValue,
pageUiState,
renderPageAiConversation,
});
const pageAiPermissionMessage = (...args) => pageAiPermissionRuntime.pageAiPermissionMessage(...args);
const pageAiApplyPermissionEvent = (...args) => pageAiPermissionRuntime.pageAiApplyPermissionEvent(...args);
const pageAiResolvePermission = (...args) => pageAiPermissionRuntime.pageAiResolvePermission(...args);
const pageAiHidePermissionDialog = (...args) => pageAiPermissionRuntime.pageAiHidePermissionDialog(...args);
const pageAiShowPermissionDialog = (...args) => pageAiPermissionRuntime.pageAiShowPermissionDialog(...args);
const pageAiSessionRuntime = createSidebarPageAiSessionRuntime({
currentDocumentId,
currentRootUri,
currentSourceKind,
documentRef: document,
pageAiApplyRuntimeState,
pageAiCurrentAgentId,
pageAiCurrentProfile,
pageAiErrorMessage,
pageAiNormalizeAgentId,
pageAiNormalizeArray,
pageAiNormalizeChatOnlyProfileId,
pageAiPermissionMessage,
pageAiPreviewValue,
pageAiRunProfile,
pageAiSetActiveProfile,
pageAiTimestamp,
pageUiState,
renderPageAiControls,
renderPageAiConversation,
resolveWorkspaceId,
sessionStorageVersion: PAGE_AI_SESSION_STORAGE_VERSION,
windowRef: window,
});
const pageAiStorageKey = (...args) => pageAiSessionRuntime.pageAiStorageKey(...args);
const pageAiBackendSessionQuery = (...args) => pageAiSessionRuntime.pageAiBackendSessionQuery(...args);
const pageAiNewSession = (...args) => pageAiSessionRuntime.pageAiNewSession(...args);
const pageAiNormalizeSessions = (...args) => pageAiSessionRuntime.pageAiNormalizeSessions(...args);
const pageAiNormalizeBackendSessionRow = (...args) => pageAiSessionRuntime.pageAiNormalizeBackendSessionRow(...args);
const pageAiMergeSessions = (...args) => pageAiSessionRuntime.pageAiMergeSessions(...args);
const pageAiSessionStorageLabel = (...args) => pageAiSessionRuntime.pageAiSessionStorageLabel(...args);
const pageAiLoadSessions = (...args) => pageAiSessionRuntime.pageAiLoadSessions(...args);
const pageAiLoadBackendSessions = (...args) => pageAiSessionRuntime.pageAiLoadBackendSessions(...args);
const pageAiMessageFromRuntimeEvent = (...args) => pageAiSessionRuntime.pageAiMessageFromRuntimeEvent(...args);
const pageAiApplyBackendSessionDetail = (...args) => pageAiSessionRuntime.pageAiApplyBackendSessionDetail(...args);
const pageAiLoadBackendSessionDetail = (...args) => pageAiSessionRuntime.pageAiLoadBackendSessionDetail(...args);
const pageAiSearchBackendSessions = (...args) => pageAiSessionRuntime.pageAiSearchBackendSessions(...args);
const pageAiPersistSessions = (...args) => pageAiSessionRuntime.pageAiPersistSessions(...args);
const pageAiEnsureHermesSession = (...args) => pageAiSessionRuntime.pageAiEnsureHermesSession(...args);
const pageAiRestoreHermesSession = (...args) => pageAiSessionRuntime.pageAiRestoreHermesSession(...args);
const pageAiCurrentSession = (...args) => pageAiSessionRuntime.pageAiCurrentSession(...args);
const pageAiSyncCurrentSessionMessages = (...args) => pageAiSessionRuntime.pageAiSyncCurrentSessionMessages(...args);
const pageAiSetActiveSession = (...args) => pageAiSessionRuntime.pageAiSetActiveSession(...args);
const pageAiStartNewSession = (...args) => pageAiSessionRuntime.pageAiStartNewSession(...args);
const pageAiRenameBackendSession = (...args) => pageAiSessionRuntime.pageAiRenameBackendSession(...args);
const pageAiExportBackendSession = (...args) => pageAiSessionRuntime.pageAiExportBackendSession(...args);
const pageAiDeleteBackendSession = (...args) => pageAiSessionRuntime.pageAiDeleteBackendSession(...args);
const pageAiDeleteSelectedBackendSessions = (...args) => pageAiSessionRuntime.pageAiDeleteSelectedBackendSessions(...args);
const pageAiResumeBackendSession = (...args) => pageAiSessionRuntime.pageAiResumeBackendSession(...args);
const pageAiSessionSelected = (...args) => pageAiSessionRuntime.pageAiSessionSelected(...args);
const pageAiToggleSessionSelection = (...args) => pageAiSessionRuntime.pageAiToggleSessionSelection(...args);
const pageAiClearSessionSelection = (...args) => pageAiSessionRuntime.pageAiClearSessionSelection(...args);
const pageAiSelectedSessionCount = (...args) => pageAiSessionRuntime.pageAiSelectedSessionCount(...args);
const pageAiCheckActiveRun = (...args) => pageAiSessionRuntime.pageAiCheckActiveRun(...args);
const pageAiSkillRuntime = createSidebarPageAiSkillRuntime({
pageAiCurrentAgentId,
pageAiCurrentProfile,
pageAiLoadSkills,
pageAiNormalizeArray,
pageAiPersistAiPreference,
pageAiPersistRawAiPreference,
pageAiProfileValue,
pageUiState,
renderPageAiControls,
});
const pageAiSkillSourceOptions = (...args) => pageAiSkillRuntime.pageAiSkillSourceOptions(...args);
const pageAiDefaultSkillSource = (...args) => pageAiSkillRuntime.pageAiDefaultSkillSource(...args);
const pageAiNormalizeSkillSource = (...args) => pageAiSkillRuntime.pageAiNormalizeSkillSource(...args);
const pageAiCurrentSkillSource = (...args) => pageAiSkillRuntime.pageAiCurrentSkillSource(...args);
const pageAiSetSkillSource = (...args) => pageAiSkillRuntime.pageAiSetSkillSource(...args);
const pageAiSkillSourceParts = (...args) => pageAiSkillRuntime.pageAiSkillSourceParts(...args);
const pageAiCurrentSkillSourceLabel = (...args) => pageAiSkillRuntime.pageAiCurrentSkillSourceLabel(...args);
const pageAiSkillOriginLabel = (...args) => pageAiSkillRuntime.pageAiSkillOriginLabel(...args);
const pageAiSkillPreferenceKey = (...args) => pageAiSkillRuntime.pageAiSkillPreferenceKey(...args);
const pageAiSkillPreferenceTable = (...args) => pageAiSkillRuntime.pageAiSkillPreferenceTable(...args);
const pageAiHermesHideBuiltinPreferenceKey = (...args) => pageAiSkillRuntime.pageAiHermesHideBuiltinPreferenceKey(...args);
const pageAiHideHermesBuiltinSkills = (...args) => pageAiSkillRuntime.pageAiHideHermesBuiltinSkills(...args);
const pageAiReasonixMemoryEnabled = (...args) => pageAiSkillRuntime.pageAiReasonixMemoryEnabled(...args);
const pageAiSetReasonixMemoryEnabled = (...args) => pageAiSkillRuntime.pageAiSetReasonixMemoryEnabled(...args);
const pageAiSetHideHermesBuiltinSkills = (...args) => pageAiSkillRuntime.pageAiSetHideHermesBuiltinSkills(...args);
const pageAiSkillIsBuiltin = (...args) => pageAiSkillRuntime.pageAiSkillIsBuiltin(...args);
const pageAiToggleableSkillEntries = (...args) => pageAiSkillRuntime.pageAiToggleableSkillEntries(...args);
const pageAiAllSkillEntries = (...args) => pageAiSkillRuntime.pageAiAllSkillEntries(...args);
const pageAiSkillGroupCollapsed = (...args) => pageAiSkillRuntime.pageAiSkillGroupCollapsed(...args);
const pageAiToggleSkillGroup = (...args) => pageAiSkillRuntime.pageAiToggleSkillGroup(...args);
const pageAiSetSkillPreference = (...args) => pageAiSkillRuntime.pageAiSetSkillPreference(...args);
const pageAiSkillEnabled = (...args) => pageAiSkillRuntime.pageAiSkillEnabled(...args);
function pageAiEnsureContextRefState() {
if (!pageUiState.pageAiSelectedContextRefs || typeof pageUiState.pageAiSelectedContextRefs !== 'object') {
pageUiState.pageAiSelectedContextRefs = {
current_page: true,
selection: false,
active_editor: true,
file: false,
folder: false,
changed_files: false
};
}
return pageUiState.pageAiSelectedContextRefs;
}
const pageAiTargetRuntime = createSidebarPageAiTargetRuntime({
currentDocumentId,
currentPageOptions,
currentRootUri,
currentSourceKind,
documentRef: document,
escapeHtml,
pageAiEnsureContextRefState,
pageAiNormalizeArray,
pageUiState,
resolveWorkspaceId,
searchText,
});
const currentPageAiOpenEditorsSnapshot = (...args) => pageAiTargetRuntime.currentPageAiOpenEditorsSnapshot(...args);
const currentPageAiEditorTarget = (...args) => pageAiTargetRuntime.currentPageAiEditorTarget(...args);
const currentPageAiPageEditorTarget = (...args) => pageAiTargetRuntime.currentPageAiPageEditorTarget(...args);
const currentPageAiScopedEditorTarget = (...args) => pageAiTargetRuntime.currentPageAiScopedEditorTarget(...args);
const pageAiCloneJson = (...args) => pageAiTargetRuntime.pageAiCloneJson(...args);
const pageAiEditorTargetCandidates = (...args) => pageAiTargetRuntime.pageAiEditorTargetCandidates(...args);
const pageAiFallbackEditorTarget = (...args) => pageAiTargetRuntime.pageAiFallbackEditorTarget(...args);
const pageAiResourceKindForTarget = (...args) => pageAiTargetRuntime.pageAiResourceKindForTarget(...args);
const pageAiTargetFromOpenEditor = (...args) => pageAiTargetRuntime.pageAiTargetFromOpenEditor(...args);
const pageAiTargetId = (...args) => pageAiTargetRuntime.pageAiTargetId(...args);
const localMarkdownRelativePathFromPageAiDocumentId = (...args) => pageAiTargetRuntime.localMarkdownRelativePathFromPageAiDocumentId(...args);
const localMarkdownDocumentIdFromPageAiRelativePath = (...args) => pageAiTargetRuntime.localMarkdownDocumentIdFromPageAiRelativePath(...args);
const pageAiWorkspacePathForDocument = (...args) => pageAiTargetRuntime.pageAiWorkspacePathForDocument(...args);
const pageAiWorkspacePathForTarget = (...args) => pageAiTargetRuntime.pageAiWorkspacePathForTarget(...args);
const pageAiBuildAllowedRoots = (...args) => pageAiTargetRuntime.pageAiBuildAllowedRoots(...args);
const pageAiBuildContextRefs = (...args) => pageAiTargetRuntime.pageAiBuildContextRefs(...args);
const pageAiBuildRunTargetSnapshot = (...args) => pageAiTargetRuntime.pageAiBuildRunTargetSnapshot(...args);
const pageAiPageContextForRefs = (...args) => pageAiTargetRuntime.pageAiPageContextForRefs(...args);
const pageAiSetRunTargetSnapshot = (...args) => pageAiTargetRuntime.pageAiSetRunTargetSnapshot(...args);
const assertPageAiTargetInCurrentWorkspace = (...args) => pageAiTargetRuntime.assertPageAiTargetInCurrentWorkspace(...args);
const pageAiBuildAgentTargetPackage = (...args) => pageAiTargetRuntime.pageAiBuildAgentTargetPackage(...args);
const pageAiBlockingDirtyState = (...args) => pageAiTargetRuntime.pageAiBlockingDirtyState(...args);
const fetchPageAiTargetBufferState = (...args) => pageAiTargetRuntime.fetchPageAiTargetBufferState(...args);
const assertPageAiTargetWritable = (...args) => pageAiTargetRuntime.assertPageAiTargetWritable(...args);
const currentPageAiSelectedText = (...args) => pageAiTargetRuntime.currentPageAiSelectedText(...args);
const pageAiProjectionBlocks = (...args) => pageAiTargetRuntime.pageAiProjectionBlocks(...args);
const pageAiBlockText = (...args) => pageAiTargetRuntime.pageAiBlockText(...args);
const pageAiSelectedBlockIdsFromSelection = (...args) => pageAiTargetRuntime.pageAiSelectedBlockIdsFromSelection(...args);
const pageAiBlocksToPageXml = (...args) => pageAiTargetRuntime.pageAiBlocksToPageXml(...args);
const buildPageAiContext = (...args) => pageAiTargetRuntime.buildPageAiContext(...args);
const pageAiScopedPageContext = (...args) => pageAiTargetRuntime.pageAiScopedPageContext(...args);
pageAiRenderRuntime = createSidebarPageAiRenderRuntime({
contextRefRegistry: PAGE_AI_CONTEXT_REF_REGISTRY,
cssEscape,
currentDocumentId,
currentPageAiEditorTarget,
currentPageAiSelectedText,
documentRef: document,
escapeHtml,
localMarkdownRelativePathFromPageAiDocumentId,
pageAiAgentDescriptor,
pageAiAgentRecord,
pageAiAllSkillEntries,
pageAiBuildAllowedRoots,
pageAiChatOnlyProfileEntries,
pageAiChatOnlyProfileSpec,
pageAiCurrentAgentId,
pageAiCurrentProfile,
pageAiCurrentProfileRecord,
pageAiCurrentSession,
pageAiCurrentSkillSource,
pageAiCurrentSkillSourceLabel,
pageAiDefaultChatOnlyProfileSpec,
pageAiDescriptorFieldOptions,
pageAiDescriptorFieldValue,
pageAiEditorTargetCandidates,
pageAiEnsureContextRefState,
pageAiFilteredHistoryRows,
pageAiHermesProfileEntries,
pageAiHermesSettingsUrl,
pageAiHideHermesBuiltinSkills,
pageAiMnoteToolModel,
pageAiNormalizeAcpRuntimes,
pageAiNormalizeArray,
pageAiNormalizeSkillSource,
pageAiProfileDisplayLabel,
pageAiProfileValue,
pageAiProviderLabel,
pageAiReasonixMemoryEnabled,
pageAiRunProfile,
pageAiSessionAgentFilterOptions,
pageAiSessionAgentFilterValue,
pageAiSessionAgentLabel,
pageAiSessionPreviewText,
pageAiSessionStorageLabel,
pageAiSessionSelected,
pageAiSelectedSessionCount,
pageAiSkillEnabled,
pageAiSkillGroupCollapsed,
pageAiSkillListEntries,
pageAiSkillOriginLabel,
pageAiSkillSourceOptions,
pageAiSkillSourceParts,
pageAiToggleableSkillEntries,
pageAiUsageSummary,
pageUiState,
renderPageAiMarkdown,
searchText,
});
function pageAiSetAgentId(agentId) {
var next = pageAiNormalizeAgentId(agentId);
var record = pageAiAgentRecord(next);
pageUiState.pageAiAgentId = next;
pageUiState.pageAiAcpRuntime = record.acpRuntime || 'reasonix';
if (record.tools) pageUiState.pageAiTools = record.tools;
pageUiState.pageAiAgentPopoverOpen = next === 'hermes';
if (next === 'hermes') pageAiSetActiveProfile(pageAiCurrentProfile());
if (next === 'chat_only') pageAiSetActiveProfile(pageAiNormalizeChatOnlyProfileId(pageAiCurrentProfile()));
document.documentElement.setAttribute('data-mnote-page-ai-agent-id', next);
pageAiPersistAiPreference('default_agent_id', next);
void pageAiLoadSkills();
renderPageAiProviderButtons();
renderPageAiControls();
}
function pageAiToggleContextRef(kind) {
var normalized = String(kind || '').trim();
if (!PAGE_AI_CONTEXT_REF_REGISTRY.some(function(ref) { return ref.id === normalized; })) return;
var selected = pageAiEnsureContextRefState();
selected[normalized] = !selected[normalized];
if (!Object.keys(selected).some(function(key) { return selected[key]; })) selected.current_page = true;
pageAiPersistAiPreference('context_refs.default_selected', selected);
renderPageAiControls();
}
function pageAiSetContextPopoverOpen(open) {
pageUiState.pageAiContextPopoverOpen = Boolean(open);
if (open) {
pageUiState.pageAiAgentPopoverOpen = false;
pageUiState.pageAiTargetPopoverOpen = false;
}
renderPageAiControls();
}
function pageAiSetAgentPopoverOpen(open) {
pageUiState.pageAiAgentPopoverOpen = Boolean(open);
if (open) {
pageUiState.pageAiContextPopoverOpen = false;
pageUiState.pageAiTargetPopoverOpen = false;
}
renderPageAiControls();
}
function pageAiSetTargetPopoverOpen(open) {
pageUiState.pageAiTargetPopoverOpen = Boolean(open);
if (open) {
pageUiState.pageAiAgentPopoverOpen = false;
pageUiState.pageAiContextPopoverOpen = false;
}
renderPageAiControls();
}
function pageAiSelectTarget(targetId) {
var normalized = String(targetId || '').trim();
var candidates = pageAiEditorTargetCandidates();
var target = candidates.find(function(candidate) { return candidate.targetId === normalized; }) || null;
if (!target) return;
pageUiState.pageAiSelectedTargetId = target.targetId;
pageUiState.pageAiTargetPopoverOpen = false;
renderPageAiControls();
}
function pageAiPersistAiPreference(key, value) {
pageAiPersistRawAiPreference('ai.common.' + key, value);
}
function pageAiPersistRawAiPreference(key, value) {
try {
var workspaceId = resolveWorkspaceId(document.body);
var body = {
workspaceId: workspaceId,
sourceKind: currentSourceKind(),
rootUri: currentRootUri(),
documentId: currentDocumentId(),
updates: {}
};
body.updates[key] = value;
void fetch('/api/ui/preferences', {
method: 'PUT',
headers: { 'content-type': 'application/json', accept: 'application/json' },
body: JSON.stringify(body)
}).catch(function() {});
} catch (_) {}
}
function pageAiDescriptorPreferenceValues() {
return pageUiState.pageAiSkillPreferences && typeof pageUiState.pageAiSkillPreferences === 'object'
? pageUiState.pageAiSkillPreferences
: {};
}
function pageAiDescriptorFieldValue(field) {
var key = String(field && field.key || '').trim();
var preferences = pageAiDescriptorPreferenceValues();
if (key && Object.prototype.hasOwnProperty.call(preferences, key)) return preferences[key];
return field && Object.prototype.hasOwnProperty.call(field, 'default') ? field.default : '';
}
function pageAiDescriptorFieldOptions(field) {
var source = String(field && field.optionsSource || '').trim();
if (source === 'hermes_profiles') {
return pageAiHermesProfileEntries().map(function(profile) {
var value = pageAiProfileValue(profile);
return {
value: value,
label: pageAiProfileDisplayLabel(profile, value)
};
}).filter(function(option) { return option.value; });
}
if (source === 'chat_only_profiles') {
return pageAiChatOnlyProfileEntries().map(function(profile) {
var value = pageAiProfileValue(profile);
return {
value: value,
label: profile.menuLabel || pageAiProfileDisplayLabel(profile, value)
};
}).filter(function(option) { return option.value; });
}
return pageAiNormalizeArray(field && field.options).map(function(option) {
if (option && typeof option === 'object') {
var value = String(option.value || option.id || option.key || '').trim();
return {
value: value,
label: String(option.label || option.title || value).trim() || value
};
}
var value = String(option || '').trim();
return { value: value, label: value };
}).filter(function(option) { return option.value; });
}
function pageAiSetDescriptorFieldValue(key, value) {
var normalizedKey = String(key || '').trim();
if (!normalizedKey) return;
pageUiState.pageAiSkillPreferences = Object.assign({}, pageAiDescriptorPreferenceValues(), {
[normalizedKey]: value
});
pageAiPersistRawAiPreference(normalizedKey, value);
if (normalizedKey === 'ai.agent.hermes.profile_id') {
pageAiSetActiveProfile(value);
void pageAiLoadAgentDescriptors();
void pageAiLoadSkills();
void pageAiLoadTools();
}
if (normalizedKey === 'ai.agent.chat_only.model_id' && pageAiCurrentAgentId() === 'chat_only') {
pageAiSetActiveProfile(pageAiNormalizeChatOnlyProfileId(value));
}
renderPageAiControls();
}
function pageAiApplyAgentDescriptorsPayload(payload) {
var descriptors = pageAiNormalizeArray(payload && payload.descriptors)
.map(pageAiNormalizeAgentDescriptor)
.filter(function(descriptor) { return descriptor.schema === PAGE_AI_DESCRIPTOR_SCHEMA; });
if (!descriptors.length) return false;
pageUiState.pageAiAgentDescriptors = descriptors;
pageUiState.pageAiAgentDescriptorsLoaded = true;
pageUiState.pageAiAgentDescriptorError = '';
if (payload && payload.preferenceValues && typeof payload.preferenceValues === 'object') {
pageUiState.pageAiSkillPreferences = Object.assign(
{},
pageAiDescriptorPreferenceValues(),
payload.preferenceValues
);
}
var current = pageAiCurrentAgentId();
var record = pageAiAgentRecord(current);
pageUiState.pageAiAgentId = record.id;
pageUiState.pageAiAcpRuntime = record.acpRuntime || pageUiState.pageAiAcpRuntime || 'reasonix';
if (record.tools) pageUiState.pageAiTools = record.tools;
return true;
}
async function pageAiLoadAgentDescriptors() {
try {
var url = new URL('/api/page-ai/agents/descriptors', window.location.origin);
url.searchParams.set('profile', pageAiCurrentProfile());
var response = await fetch(url.toString(), {
headers: { accept: 'application/json' },
cache: 'no-store'
});
var payload = await response.json().catch(function() { return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'agent_descriptors_failed_' + response.status));
if (!pageAiApplyAgentDescriptorsPayload(payload)) throw new Error('agent_descriptors_empty');
} catch (error) {
pageUiState.pageAiAgentDescriptorError = error instanceof Error ? error.message : String(error);
pageUiState.pageAiAgentDescriptorsLoaded = false;
}
renderPageAiProviderButtons();
renderPageAiControls();
return pageUiState.pageAiAgentDescriptors;
}
async function pageAiLoadAiPreferences() {
try {
var url = new URL('/api/ui/preferences/effective', window.location.origin);
url.searchParams.set('workspaceId', resolveWorkspaceId(document.body));
url.searchParams.set('sourceKind', currentSourceKind());
url.searchParams.set('rootUri', currentRootUri());
url.searchParams.set('documentId', currentDocumentId());
var response = await fetch(url.toString(), { headers: { accept: 'application/json' }, cache: 'no-store' });
var payload = await response.json().catch(function() { return null; });
if (!response.ok || !payload || !payload.result) return;
var preferences = payload.result.aiPreferences && typeof payload.result.aiPreferences === 'object'
? payload.result.aiPreferences
: {};
pageUiState.pageAiSkillPreferences = Object.assign({}, preferences);
var defaultAgent = String(preferences['ai.common.default_agent_id'] || '').trim();
if (defaultAgent) {
var agent = pageAiAgentRecord(defaultAgent);
pageUiState.pageAiAgentId = agent.id;
pageUiState.pageAiAcpRuntime = agent.acpRuntime || pageUiState.pageAiAcpRuntime || 'reasonix';
if (agent.tools) pageUiState.pageAiTools = agent.tools;
}
var hermesProfile = String(preferences['ai.agent.hermes.profile_id'] || '').trim();
if (hermesProfile) pageAiSetActiveProfile(hermesProfile);
var skillSource = String(preferences['ai.common.skills.active_source'] || '').trim();
if (skillSource) pageUiState.pageAiActiveSkillSource = skillSource;
var selected = preferences['ai.common.context_refs.default_selected'];
if (selected && typeof selected === 'object' && !Array.isArray(selected)) {
pageUiState.pageAiSelectedContextRefs = Object.assign({}, pageAiEnsureContextRefState(), selected);
}
var collapsedSkillGroups = preferences['ai.common.skills.groups.collapsed'];
if (collapsedSkillGroups && typeof collapsedSkillGroups === 'object' && !Array.isArray(collapsedSkillGroups)) {
pageUiState.pageAiCollapsedSkillGroups = Object.assign({}, collapsedSkillGroups);
}
} catch (_) {}
renderPageAiControls();
}
function pageAiNormalizeAccessGrant(grant) {
if (!grant || typeof grant !== 'object') return null;
var rootUri = String(grant.rootUri || grant.root_uri || '').trim();
if (!rootUri) return null;
var permission = String(grant.permission || grant.access || '').trim() || 'read';
return {
id: String(grant.id || '').trim(),
rootUri: rootUri,
rootPath: String(grant.rootPath || grant.root_path || '').trim(),
permission: permission === 'read_write' ? 'write' : permission,
recursive: grant.recursive !== false,
source: String(grant.source || 'sqlite_directory_grant').trim() || 'sqlite_directory_grant',
status: String(grant.status || 'active').trim() || 'active'
};
}
async function pageAiLoadAllowedRoots() {
if (currentSourceKind() !== 'local_folder') {
pageUiState.pageAiAllowedRoots = [];
renderPageAiControls();
return [];
}
try {
var response = await fetch('/api/user/access-policy', {
headers: { accept: 'application/json' },
cache: 'no-store'
});
var payload = await response.json().catch(function() { return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'access_policy_failed_' + response.status));
var grants = pageAiNormalizeArray(payload && (payload.grants || payload.policy && payload.policy.grants));
var currentRoot = String(currentRootUri() || '').trim();
pageUiState.pageAiAllowedRoots = grants.map(pageAiNormalizeAccessGrant).filter(Boolean).filter(function(grant) {
return grant.status === 'active' && (!currentRoot || grant.rootUri === currentRoot);
});
pageUiState.pageAiAllowedRootsError = '';
} catch (error) {
pageUiState.pageAiAllowedRoots = [];
pageUiState.pageAiAllowedRootsError = error instanceof Error ? error.message : String(error);
}
renderPageAiControls();
return pageUiState.pageAiAllowedRoots;
}
function updatePageAiTriggerState() {
var trigger = document.querySelector('[data-testid="wolai-floating-ai"]');
if (!(trigger instanceof HTMLElement)) return;
trigger.setAttribute('data-state', pageUiState.pageAiOpen ? 'open' : 'closed');
trigger.setAttribute('aria-expanded', pageUiState.pageAiOpen ? 'true' : 'false');
}
function pageAiOpenLocation(loc) {
var path = String(loc || '').trim();
if (!path) return;
openLocalResourceInActiveTab({ path: path }).then(function(opened) {
if (!opened) {
var href = buildLocalFileOpenUrl(path, false);
if (href) window.open(href, '_blank', 'noopener,noreferrer');
}
});
}
function pageAiEvidenceRangeFromParam(value) {
var text = String(value || '').trim();
if (!text) return null;
var match = text.match(/^(\d+)[-:,](\d+)$/);
if (!match) return text;
return { start: Number(match[1]), end: Number(match[2]) };
}
function pageAiEvidenceBboxFromParam(value) {
var text = String(value || '').trim();
if (!text) return null;
var parts = text.split(',').map(function(part) { return Number(part.trim()); });
if (parts.length < 4 || parts.slice(0, 4).some(function(part) { return !Number.isFinite(part); })) return text;
return { x0: parts[0], y0: parts[1], x1: parts[2], y1: parts[3] };
}
function pageAiDocumentIdFromUrl(url) {
var prefix = '/documents/';
if (!url.pathname.startsWith(prefix)) return '';
try {
var raw = url.pathname.slice(prefix.length).split('/')[0] || '';
var decoded = decodeURIComponent(raw);
if (decoded.indexOf('%') >= 0 || decoded.indexOf('\uFFFD') >= 0) return '';
return decoded;
} catch (_error) {
return '';
}
}
function pageAiCitationResourcePath(url, rootUri) {
var explicitPath = String(url.searchParams.get('resourcePath') || '').trim();
if (explicitPath) return explicitPath;
var raw = String(url.searchParams.get('resourceTab') || '').trim();
if (!raw) {
try {
var decodedHash = decodeURIComponent(String(url.hash || ''));
var marker = '#resource-tab-';
var markerIndex = decodedHash.indexOf(marker);
if (markerIndex >= 0) raw = decodedHash.slice(markerIndex + marker.length).replace(/^#+/, '').trim();
} catch (_error) {}
}
if (raw.indexOf('::') >= 0) raw = raw.slice(raw.indexOf('::') + 2);
if (!raw.startsWith('resource:file:')) return '';
var rest = raw.slice('resource:file:'.length);
var prefix = String(rootUri || '').trim() + ':';
if (!prefix.trim() || !rest.startsWith(prefix)) return '';
return rest.slice(prefix.length).replace(/^\/+/, '');
}
function pageAiSameMnoteOrigin(url) {
try {
var current = new URL(window.location.origin);
if (url.origin === current.origin) return true;
if (url.hostname === 'mnote.local') return true;
var localNames = ['localhost', '127.0.0.1', '::1', 'mnote.local'];
function defaultPort(protocol) {
return protocol === 'https:' ? '443' : protocol === 'http:' ? '80' : '';
}
return localNames.indexOf(url.hostname) >= 0 &&
localNames.indexOf(current.hostname) >= 0 &&
String(url.port || defaultPort(url.protocol)) === String(current.port || defaultPort(current.protocol));
} catch (_error) {
return false;
}
}
function pageAiPortableCitationUrl(url) {
try {
if (url.pathname === '/api/local-folder/files/open') {
return Boolean(String(url.searchParams.get('rootUri') || '').trim()) &&
Boolean(String(url.searchParams.get('path') || '').trim());
}
if (!url.pathname.startsWith('/documents/')) return false;
var resourceTab = String(url.searchParams.get('resourceTab') || '').trim();
return String(url.searchParams.get('sourceKind') || '').trim() === 'local_folder' ||
Boolean(String(url.searchParams.get('rootUri') || '').trim()) ||
Boolean(String(url.searchParams.get('resourcePath') || '').trim()) ||
resourceTab.startsWith('resource:file:');
} catch (_error) {
return false;
}
}
function pageAiOpenCitationUrl(href) {
var url;
try {
url = new URL(String(href || ''), window.location.origin);
} catch (_error) {
return false;
}
var unwrappedHref = pageAiUnwrapSearchCitationUrl(url);
if (unwrappedHref) return pageAiOpenCitationUrl(unwrappedHref);
if (!pageAiSameMnoteOrigin(url) && !pageAiPortableCitationUrl(url)) return false;
if (url.pathname === '/api/local-folder/files/open') {
var fileRootUri = String(url.searchParams.get('rootUri') || currentRootUri() || '').trim();
var filePath = String(url.searchParams.get('path') || '').trim();
if (!filePath) return false;
void openLocalResourceInActiveTab({
path: filePath,
rootUri: fileRootUri,
documentId: currentDocumentId() || '',
workspaceId: resolveWorkspaceId(document.body) || '',
sourceKind: currentSourceKind() || 'local_folder',
page: url.searchParams.get('page') || undefined,
bbox: pageAiEvidenceBboxFromParam(url.searchParams.get('bbox')),
sourceMapPath: String(url.searchParams.get('sourceMapPath') || '').trim(),
blockId: String(url.searchParams.get('blockId') || '').trim(),
evidenceText: String(url.searchParams.get('evidenceText') || '').trim(),
lineRange: pageAiEvidenceRangeFromParam(url.searchParams.get('lineRange')),
charRange: pageAiEvidenceRangeFromParam(url.searchParams.get('charRange')),
openTarget: 'active-tab',
paneRole: 'primary'
}).then(function(opened) {
if (!opened) window.open(url.toString(), '_blank', 'noopener,noreferrer');
});
return true;
}
if (!url.pathname.startsWith('/documents/')) return false;
var rootUri = String(url.searchParams.get('rootUri') || currentRootUri() || '').trim();
var resourcePath = pageAiCitationResourcePath(url, rootUri);
var documentId = pageAiDocumentIdFromUrl(url) || currentDocumentId() || '';
var workspaceId = String(url.searchParams.get('workspaceId') || resolveWorkspaceId(document.body) || '').trim();
if (resourcePath) {
void openLocalResourceInActiveTab({
path: resourcePath,
rootUri: rootUri,
documentId: documentId,
workspaceId: workspaceId,
sourceKind: String(url.searchParams.get('sourceKind') || currentSourceKind() || 'local_folder').trim(),
page: url.searchParams.get('page') || undefined,
bbox: pageAiEvidenceBboxFromParam(url.searchParams.get('bbox')),
sourceMapPath: String(url.searchParams.get('sourceMapPath') || '').trim(),
blockId: String(url.searchParams.get('blockId') || '').trim(),
evidenceText: String(url.searchParams.get('evidenceText') || '').trim(),
lineRange: pageAiEvidenceRangeFromParam(url.searchParams.get('lineRange')),
charRange: pageAiEvidenceRangeFromParam(url.searchParams.get('charRange')),
openTarget: 'active-tab',
paneRole: 'primary'
}).then(function(opened) {
if (!opened) window.location.assign(url.pathname + url.search + url.hash);
});
return true;
}
if (typeof window.__mnoteDocumentPaneRuntime?.openPrimaryDocument === 'function') {
void window.__mnoteDocumentPaneRuntime.openPrimaryDocument({
documentId: documentId,
workspaceId: workspaceId,
sourceKind: String(url.searchParams.get('sourceKind') || currentSourceKind() || '').trim(),
rootUri: rootUri,
url: url
});
return true;
}
return false;
}
function pageAiChatOnlyProfileEntries() {
var profiles = pageAiNormalizeArray(pageUiState.pageAiProfiles);
return PAGE_AI_CHAT_ONLY_PROFILE_REGISTRY.map(function(spec) {
var profile = profiles.find(function(candidate) {
var candidateSpec = pageAiChatOnlyProfileSpec(candidate);
return candidateSpec && candidateSpec.profileId === spec.profileId;
});
return Object.assign({}, profile || {
profileId: spec.profileId,
name: spec.profileId,
alias: spec.label,
kind: 'shared',
baseProfile: spec.baseProfile,
providerKind: spec.providerKind || '',
readonly: true
}, { menuLabel: spec.label });
});
}
function pageAiHermesProfileEntries() {
var profiles = pageAiNormalizeArray(pageUiState.pageAiProfiles).filter(function(profile) {
return !pageAiChatOnlyProfileSpec(profile);
});
if (profiles.length) return profiles;
return [{ profileId: pageAiCurrentProfile(), name: pageAiCurrentProfile(), alias: pageAiCurrentProfile(), kind: 'personal' }];
}
function pageAiNormalizeProfiles(payload) {
var upstream = pageAiUnwrapUpstream(payload);
var profiles = pageAiNormalizeArray(upstream && upstream.profiles ? upstream.profiles : upstream);
return profiles.map(function(profile) {
var profileId = String(profile && (profile.profileId || profile.id || profile.name) || '').trim();
var kind = String(profile && profile.kind || profile && profile.profileKind || '').trim();
var canManageSkills = profile && profile.canManageSkills !== false;
return {
profileId: profileId || pageAiProfileValue(profile) || 'default',
name: profileId || pageAiProfileValue(profile) || 'default',
active: Boolean(profile && profile.active),
model: String(profile && profile.model || '').trim(),
gateway: String(profile && profile.gateway || '').trim(),
alias: String(profile && (profile.displayName || profile.alias) || '').trim(),
kind: kind,
ownerUserId: String(profile && profile.ownerUserId || '').trim(),
baseProfile: String(profile && profile.baseProfile || '').trim(),
isolatedProfile: String(profile && profile.isolatedProfile || '').trim(),
providerKind: String(profile && profile.providerKind || profile && profile.provider_kind || '').trim(),
canRun: profile ? profile.canRun !== false : true,
canManageSkills: canManageSkills,
canManageConfig: profile ? profile.canManageConfig !== false : canManageSkills,
readonly: profile ? (profile.readonly === true || !canManageSkills) : false,
grantRole: String(profile && profile.grantRole || '').trim()
};
});
}
function pageAiNormalizeSkills(payload) {
var upstream = pageAiUnwrapUpstream(payload);
var categories = pageAiNormalizeArray(upstream && upstream.categories ? upstream.categories : []);
var archived = pageAiNormalizeArray(upstream && upstream.archived ? upstream.archived : []);
return {
categories: categories.map(function(category) {
var skillRows = pageAiNormalizeArray(category && (category.skills || category.capabilities));
return {
name: String(category && category.name || '').trim() || 'misc',
description: String(category && category.description || '').trim(),
title: String(category && category.title || '').trim(),
capabilities: pageAiNormalizeArray(category && category.capabilities),
skills: skillRows.map(function(skill) {
return {
name: String(skill && skill.name || '').trim(),
id: String(skill && skill.id || skill && skill.name || '').trim(),
title: String(skill && skill.title || skill && skill.name || skill && skill.id || '').trim(),
description: String(skill && skill.description || '').trim(),
enabled: skill && skill.enabled !== false,
toggleable: skill && skill.toggleable !== false,
source: String(skill && skill.source || 'local').trim() || 'local',
origin: String(skill && skill.origin || '').trim(),
createdBy: String(skill && skill.createdBy || '').trim(),
patchCount: Number(skill && skill.patchCount || 0),
modified: Boolean(skill && skill.modified),
builtin: Boolean(skill && skill.builtin),
configurable: skill && skill.configurable !== false,
configScope: String(skill && skill.configScope || '').trim(),
skillKind: String(skill && skill.skillKind || '').trim(),
profileId: String(skill && skill.profileId || '').trim(),
toolNames: pageAiNormalizeArray(skill && skill.toolNames),
tools: pageAiNormalizeArray(skill && skill.tools),
toolCount: Number(skill && skill.toolCount || 0),
disabledToolCount: Number(skill && skill.disabledToolCount || 0),
status: String(skill && skill.status || '').trim(),
capabilityId: String(skill && skill.capabilityId || '').trim(),
capabilityKind: String(skill && skill.capabilityKind || '').trim(),
uiKind: String(skill && skill.uiKind || '').trim(),
requiresContextRefs: pageAiNormalizeArray(skill && skill.requiresContextRefs),
readOnly: Boolean(skill && (skill.readOnly || skill.readonly || skill.configurable === false)),
category: String(skill && skill.category || category && category.name || '').trim(),
categoryTitle: String(skill && skill.categoryTitle || category && category.title || category && category.name || '').trim()
};
})
};
}),
archived: archived.map(function(skill) {
return {
name: String(skill && skill.name || '').trim(),
id: String(skill && skill.id || skill && skill.name || '').trim(),
title: String(skill && skill.title || skill && skill.name || skill && skill.id || '').trim(),
description: String(skill && skill.description || '').trim(),
enabled: skill && skill.enabled !== false,
toggleable: skill && skill.toggleable !== false,
source: String(skill && skill.source || 'local').trim() || 'local',
origin: String(skill && skill.origin || '').trim(),
createdBy: String(skill && skill.createdBy || '').trim(),
patchCount: Number(skill && skill.patchCount || 0),
modified: Boolean(skill && skill.modified),
builtin: Boolean(skill && skill.builtin),
configurable: skill && skill.configurable !== false,
configScope: String(skill && skill.configScope || '').trim(),
skillKind: String(skill && skill.skillKind || '').trim(),
profileId: String(skill && skill.profileId || '').trim(),
toolNames: pageAiNormalizeArray(skill && skill.toolNames),
tools: pageAiNormalizeArray(skill && skill.tools),
toolCount: Number(skill && skill.toolCount || 0),
disabledToolCount: Number(skill && skill.disabledToolCount || 0),
status: String(skill && skill.status || '').trim(),
capabilityId: String(skill && skill.capabilityId || '').trim(),
capabilityKind: String(skill && skill.capabilityKind || '').trim(),
uiKind: String(skill && skill.uiKind || '').trim(),
requiresContextRefs: pageAiNormalizeArray(skill && skill.requiresContextRefs),
categoryTitle: String(skill && skill.categoryTitle || '').trim(),
readOnly: Boolean(skill && (skill.readOnly || skill.readonly || skill.configurable === false))
};
})
};
}
function pageAiSkillListEntries() {
var result = [];
pageAiNormalizeArray(pageUiState.pageAiSkills.categories).forEach(function(category) {
pageAiNormalizeArray(category.skills).forEach(function(skill) {
result.push({
category: category.name,
name: skill.name,
id: skill.id || skill.name,
title: skill.title || skill.name,
description: skill.description,
enabled: skill.enabled !== false,
toggleable: skill.toggleable !== false,
source: skill.source || 'local',
origin: skill.origin || '',
createdBy: skill.createdBy || '',
patchCount: Number(skill.patchCount || 0),
modified: Boolean(skill.modified),
builtin: Boolean(skill.builtin),
configurable: skill.configurable !== false,
configScope: skill.configScope || '',
skillKind: skill.skillKind || '',
profileId: skill.profileId || '',
toolNames: skill.toolNames || [],
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 || '',
requiresContextRefs: skill.requiresContextRefs || [],
categoryTitle: skill.categoryTitle || category.title || category.name || '',
readOnly: Boolean(skill.readOnly || skill.readonly || skill.configurable === false)
});
});
});
return result.concat(pageAiNormalizeArray(pageUiState.pageAiSkills.archived));
}
function pageAiSetActiveProfile(profileName) {
var next = String(profileName || '').trim() || 'mnoteai';
pageUiState.pageAiActiveProfileName = next;
document.documentElement.setAttribute('data-mnote-page-ai-profile', next);
document.documentElement.setAttribute('data-mnote-page-ai-tool-model', pageAiMnoteToolModel());
}
function pageAiSetRunStatus(status, runId) {
pageUiState.pageAiRunStatus = status || 'idle';
pageUiState.pageAiCurrentRunId = runId || pageUiState.pageAiCurrentRunId || '';
document.documentElement.setAttribute('data-mnote-page-ai-run-status', pageUiState.pageAiRunStatus);
if (pageUiState.pageAiCurrentRunId) {
document.documentElement.setAttribute('data-mnote-page-ai-run-id', pageUiState.pageAiCurrentRunId);
}
pageAiUpdateActiveRunSnapshotFromStatus(pageUiState.pageAiRunStatus, pageUiState.pageAiCurrentRunId);
}
function pageAiApplyRuntimeState(runtime) {
if (!runtime || typeof runtime !== 'object') return;
var status = String(runtime.status || '').trim();
var runId = String(runtime.runId || runtime.run_id || '').trim();
if (status) pageAiSetRunStatus(status, runId);
var queueLength = Number(runtime.queueLength || runtime.queue_length || 0);
if (Number.isFinite(queueLength)) pageUiState.pageAiQueueLength = Math.max(0, queueLength);
var toolName = String(runtime.lastToolName || runtime.last_tool_name || '').trim();
if (toolName) {
pageUiState.pageAiLastToolCall = {
event: String(runtime.lastEvent || runtime.last_event || ''),
name: toolName,
runId: runId,
traceId: String(runtime.traceId || runtime.trace_id || ''),
auditId: String(runtime.lastAuditId || runtime.last_audit_id || '')
};
}
}
function pageAiActiveRunSnapshotKey() {
return pageAiStorageKey() + ':active-run';
}
function pageAiReadActiveRunSnapshot() {
try {
var raw = window.localStorage ? window.localStorage.getItem(pageAiActiveRunSnapshotKey()) : '';
return raw ? JSON.parse(raw) : null;
} catch (_) {
return null;
}
}
function pageAiWriteActiveRunSnapshot(snapshot) {
if (!snapshot || !snapshot.hostRunId) return;
try {
window.localStorage.setItem(pageAiActiveRunSnapshotKey(), JSON.stringify(Object.assign({
schema: 'mnote.page_ai_active_run_snapshot.v1',
createdAt: Date.now()
}, snapshot, {
updatedAt: Date.now()
})));
document.documentElement.setAttribute('data-mnote-page-ai-active-run-snapshot', 'true');
} catch (_) {}
}
function pageAiClearActiveRunSnapshot(runId) {
var existing = pageAiReadActiveRunSnapshot();
if (runId && existing && existing.hostRunId && existing.hostRunId !== runId) return;
try {
if (window.localStorage) window.localStorage.removeItem(pageAiActiveRunSnapshotKey());
document.documentElement.removeAttribute('data-mnote-page-ai-active-run-snapshot');
} catch (_) {}
}
function pageAiRunStatusIsTerminal(status) {
return ['completed', 'failed', 'aborted', 'cancelled', 'canceled'].indexOf(String(status || '').trim()) >= 0;
}
function pageAiUpdateActiveRunSnapshotFromStatus(status, runId) {
var id = String(runId || '').trim();
if (!id) return;
if (pageAiRunStatusIsTerminal(status)) {
pageAiClearActiveRunSnapshot(id);
return;
}
if (['running', 'tool_calling', 'queued', 'pending', 'interrupted', 'acp_pending'].indexOf(String(status || '').trim()) < 0) return;
var previous = pageAiReadActiveRunSnapshot();
var lastSeq = previous && previous.hostRunId === id ? String(previous.lastSeq || '000000000000000000') : '000000000000000000';
pageAiWriteActiveRunSnapshot({
hostRunId: id,
sessionId: pageUiState.pageAiActiveSessionId || '',
lastSeq: lastSeq,
status: status || 'running'
});
}
async function pageAiCheckAndResumeActiveRun() {
var snapshot = pageAiReadActiveRunSnapshot();
var sessionId = snapshot && snapshot.sessionId ? String(snapshot.sessionId || '').trim() : '';
var run = await pageAiCheckActiveRun(sessionId || undefined);
if (run && sessionId && pageUiState.pageAiActiveSessionId !== sessionId) {
pageAiSetActiveSession(sessionId);
}
if (run) await pageAiResumeActiveRunJournal(run);
if (!run && snapshot && snapshot.hostRunId) {
pageAiStopStreamingAssistantMessage(snapshot.hostRunId);
pageAiClearActiveRunSnapshot(snapshot.hostRunId);
pageUiState.pageAiBusy = false;
pageAiSetRunStatus('idle', snapshot.hostRunId);
}
return run;
}
function pageAiApplyQueuedRun(payload) {
if (!payload || payload.queued !== true) return false;
var queueId = String(payload.queueId || payload.queue_id || '').trim();
var queueLength = Number(payload.queueLength || payload.queue_length || 0);
pageUiState.pageAiQueueLength = Number.isFinite(queueLength) ? Math.max(0, queueLength) : 1;
if (queueId) {
pageUiState.pageAiQueuedItems = pageUiState.pageAiQueuedItems.filter(function(item) {
return item.queueId !== queueId;
}).concat([{
queueId: queueId,
sessionId: String(payload.sessionId || payload.session_id || pageUiState.pageAiActiveSessionId || ''),
traceId: String(payload.traceId || payload.trace_id || ''),
queuedAt: Number(payload.queuedAt || payload.queued_at || Date.now())
}]);
}
pageAiSetRunStatus('queued', pageUiState.pageAiCurrentRunId);
return true;
}
function pageAiUnwrapSearchCitationUrl(url) {
try {
var raw = '';
['wd', 'q', 'query'].some(function(key) {
raw = String(url.searchParams.get(key) || '').trim();
return Boolean(raw);
});
if (!raw) return '';
if (/^documents\//i.test(raw)) raw = '/' + raw;
if (!/^\/documents\//i.test(raw) && !/^https?:\/\/[^/]+\/documents\//i.test(raw) && !/^mnote:\/\/open/i.test(raw)) return '';
if (/^mnote:\/\/open/i.test(raw)) return raw;
var nested = new URL(raw, window.location.origin);
if (!nested.pathname.startsWith('/documents/')) return '';
['sourceKind', 'rootUri', 'workspaceId', 'resourceTab', 'resourcePath', 'page', 'bbox', 'sourceMapPath', 'blockId', 'evidenceText', 'lineRange', 'charRange'].forEach(function(key) {
if (nested.searchParams.get(key)) return;
var value = String(url.searchParams.get(key) || '').trim();
if (value) nested.searchParams.set(key, value);
});
return nested.pathname + nested.search;
} catch (_error) {
return '';
}
}
function pageAiPreviewValue(value) {
if (value == null || value === '') return '';
if (typeof value === 'string') return value.length > 120 ? value.slice(0, 120) + '…' : value;
try {
var text = JSON.stringify(value);
return text.length > 120 ? text.slice(0, 120) + '…' : text;
} catch (_) {
return String(value);
}
}
function pageAiNormalizeToolName(name) {
return String(name || '').trim().replace(/_/g, '.');
}
function pageAiParentRelativePath(path) {
var normalized = String(path || '').trim().replace(/\\/g, '/').replace(/^\/+/, '');
if (!normalized || normalized.indexOf('/') < 0) return '';
return normalized.split('/').slice(0, -1).join('/');
}
function pageAiChangedFileRelativePath(file) {
return String(file && (file.path || file.relativePath || file.relative_path || file.filePath || file.file_path || '') || '').trim();
}
function pageAiDispatchReceiptRefresh(receipt, changedFiles, fallbackAudit, runId, traceId) {
var refresh = receipt && typeof receipt === 'object' && receipt.refresh && typeof receipt.refresh === 'object'
? receipt.refresh
: {};
var files = pageAiNormalizeArray(
receipt && typeof receipt === 'object' && receipt.changedFiles !== undefined
? receipt.changedFiles
: changedFiles
);
if (files.length) {
var changedPaths = files.map(function(file) {
var relativePath = pageAiChangedFileRelativePath(file);
return {
relativePath: relativePath,
changeType: String(file && (file.changeType || file.change_type || 'modified') || 'modified')
};
}).filter(function(item) { return item.relativePath; });
var affectedParents = changedPaths.map(function(item) {
return { relativePath: pageAiParentRelativePath(item.relativePath), reason: 'agent-run-receipt' };
}).filter(function(item, index, list) {
return index === list.findIndex(function(candidate) { return candidate.relativePath === item.relativePath; });
});
if (changedPaths.length) {
var rootUri = String((receipt && receipt.rootUri) || (fallbackAudit && fallbackAudit.rootUri) || currentRootUri() || '');
var syntheticPayload = {
schema: 'mnote.local_folder.watch_batch.v1',
source: 'agent_run_receipt',
runId: runId,
rootUri: rootUri,
changedPaths: changedPaths,
affectedParents: affectedParents
};
document.documentElement.setAttribute('data-mnote-page-ai-receipt-filetree-refresh', 'true');
if (window.__mnoteLocalFolderEventBus && typeof window.__mnoteLocalFolderEventBus.emitSyntheticWatchBatch === 'function') {
window.__mnoteLocalFolderEventBus.emitSyntheticWatchBatch({
source: 'synthetic_page_ai_receipt',
reason: 'agent_run_receipt',
rootUri: rootUri,
workspaceId: resolveWorkspaceId(document.body),
payload: syntheticPayload
});
} else {
window.dispatchEvent(new CustomEvent('tree:local-folder-watch-batch', {
detail: { payload: syntheticPayload }
}));
}
}
}
if (refresh.touchesCurrentFile === true) {
var documentId = String(refresh.currentDocumentId || receipt && receipt.documentId || currentDocumentId() || '').trim();
document.documentElement.setAttribute('data-mnote-page-ai-receipt-current-refresh', 'true');
window.dispatchEvent(new CustomEvent('mnote:page-ai-tool-write-completed', {
detail: {
toolName: 'agent.run_receipt',
normalizedToolName: 'agent.run_receipt',
documentId: documentId,
workspaceId: String(receipt && receipt.workspaceId || resolveWorkspaceId(document.body) || ''),
rootUri: String(receipt && receipt.rootUri || fallbackAudit && fallbackAudit.rootUri || currentRootUri() || ''),
changedFiles: files,
receipt: receipt || null,
runId: runId,
traceId: traceId,
toolCallId: runId + ':agent.run_receipt'
}
}));
}
}
function pageAiToolEventDeepFindString(value, keys, depth) {
if (!value || typeof value !== 'object' || depth > 5) return '';
for (var index = 0; index < keys.length; index += 1) {
var key = keys[index];
if (Object.prototype.hasOwnProperty.call(value, key) && typeof value[key] === 'string' && value[key].trim()) {
return value[key].trim();
}
}
if (Array.isArray(value)) {
for (var arrayIndex = 0; arrayIndex < value.length; arrayIndex += 1) {
var fromArray = pageAiToolEventDeepFindString(value[arrayIndex], keys, depth + 1);
if (fromArray) return fromArray;
}
return '';
}
var preferred = ['audit', 'args', 'arguments', 'input', 'result', 'summary', 'output', 'upstream'];
for (var prefIndex = 0; prefIndex < preferred.length; prefIndex += 1) {
var child = value[preferred[prefIndex]];
var fromPreferred = pageAiToolEventDeepFindString(child, keys, depth + 1);
if (fromPreferred) return fromPreferred;
}
var objectKeys = Object.keys(value);
for (var objectIndex = 0; objectIndex < objectKeys.length; objectIndex += 1) {
var fromObject = pageAiToolEventDeepFindString(value[objectKeys[objectIndex]], keys, depth + 1);
if (fromObject) return fromObject;
}
return '';
}
function pageAiNotifyToolWriteCompleted(toolName, toolEvent, runId, runTraceId) {
var normalizedTool = pageAiNormalizeToolName(toolName);
var writesCurrentPage = [
'mnote.page.save',
'mnote.page.update.title',
'mnote.page.update.options',
'mnote.doc.apply.block.ops',
'mnote.block.replace',
'mnote.block.insert.after',
'mnote.block.delete',
'mnote.block.move.after'
].indexOf(normalizedTool) >= 0 || [
'mnote.page.update_title',
'mnote.page.update_options',
'mnote.doc.apply_block_ops',
'mnote.block.replace',
'mnote.block.insert_after',
'mnote.block.delete',
'mnote.block.move_after'
].indexOf(String(toolName || '').trim()) >= 0;
if (!writesCurrentPage) return;
var documentId = pageAiToolEventDeepFindString(toolEvent, ['documentId', 'document_id'], 0) || currentDocumentId();
var workspaceId = pageAiToolEventDeepFindString(toolEvent, ['workspaceId', 'workspace_id'], 0) || resolveWorkspaceId(document.body);
try {
window.dispatchEvent(new CustomEvent('mnote:page-ai-tool-write-completed', {
detail: {
toolName: toolName,
normalizedToolName: normalizedTool,
documentId: documentId,
workspaceId: workspaceId,
runId: String(toolEvent && (toolEvent.run_id || toolEvent.runId) || runId || ''),
traceId: String(toolEvent && (toolEvent.trace_id || toolEvent.traceId) || runTraceId || ''),
toolCallId: String(toolEvent && (toolEvent.tool_call_id || toolEvent.toolCallId || toolEvent.id) || '')
}
}));
} catch (error) {
console.warn('mnote 页面 AI 写入刷新事件派发失败', error);
}
}
function pageAiApplyToolEvent(eventName, payloadText, runId, runTraceId) {
var toolEvent = null;
try {
toolEvent = JSON.parse(payloadText || 'null');
} catch (_) {
toolEvent = {};
}
var rawToolName = toolEvent && (toolEvent.name || toolEvent.tool || toolEvent.toolName || '');
var toolName = String(rawToolName || eventName);
var toolCallId = String(toolEvent && (toolEvent.tool_call_id || toolEvent.toolCallId || toolEvent.id) || (runId + ':' + toolName));
var eventStatus = String(toolEvent && toolEvent.status || '').trim();
var status = eventName === 'tool.completed'
? (toolEvent && toolEvent.error ? 'failed' : 'completed')
: (eventName === 'tool.failed' ? 'failed' : (eventStatus || 'running'));
if (status === 'in_progress' || status === 'pending') status = 'running';
var traceId = String(toolEvent && (toolEvent.trace_id || toolEvent.traceId) || runTraceId || '');
var auditId = String(toolEvent && (toolEvent.audit_id || toolEvent.auditId) || '');
var argsSummary = pageAiPreviewValue(toolEvent && (toolEvent.arguments || toolEvent.args || toolEvent.input));
var resultSource = toolEvent && (toolEvent.summary || toolEvent.result || toolEvent.output);
if (!resultSource && status === 'failed') {
resultSource = [toolEvent && toolEvent.code, toolEvent && toolEvent.error].filter(Boolean).join(' ');
}
var resultSummary = pageAiPreviewValue(resultSource);
pageUiState.pageAiLastToolCall = {
event: eventName,
name: toolName,
runId: String(toolEvent && (toolEvent.run_id || toolEvent.runId) || runId),
traceId: traceId,
auditId: auditId
};
var rawLocations = toolEvent && toolEvent.locations;
var locations = Array.isArray(rawLocations) ? rawLocations.filter(function(l) { return typeof l === 'string' || (typeof l === 'object' && l && l.path); }).map(function(l) { return typeof l === 'string' ? l : l.path; }) : [];
var existing = pageUiState.pageAiMessages.find(function(item) {
return item.role === 'tool' && item.toolCallId === toolCallId;
});
if (!rawToolName && existing && existing.toolName) toolName = existing.toolName;
if (!existing) {
existing = {
role: 'tool',
content: toolName,
toolCallId: toolCallId,
toolName: toolName,
toolKind: String(toolEvent && toolEvent.kind || ''),
status: status,
argsSummary: '',
resultSummary: '',
locations: locations,
traceId: traceId,
auditId: auditId
};
pageUiState.pageAiMessages.push(existing);
}
existing.content = toolName;
existing.toolName = toolName;
existing.toolKind = String(toolEvent && toolEvent.kind || existing.toolKind || '');
existing.status = status;
existing.traceId = traceId || existing.traceId || '';
existing.auditId = auditId || existing.auditId || '';
if (argsSummary) existing.argsSummary = argsSummary;
if (resultSummary) existing.resultSummary = resultSummary;
if (locations.length) existing.locations = locations;
existing.rawOutput = toolEvent && toolEvent.output;
existing.rawResult = resultSource;
if (status === 'completed') {
pageAiNotifyToolWriteCompleted(toolName, toolEvent, runId, runTraceId);
}
return existing;
}
async function pageAiCancelQueuedRun(queueId) {
queueId = String(queueId || '').trim();
if (!queueId) return;
var item = pageUiState.pageAiQueuedItems.find(function(entry) {
return entry.queueId === queueId;
});
var sessionId = String(item && item.sessionId || pageUiState.pageAiActiveSessionId || '').trim();
if (!sessionId) return;
try {
var response = await fetch('/api/hermes/client/sessions/' + encodeURIComponent(sessionId) + '/queue/' + encodeURIComponent(queueId), {
method: 'DELETE',
headers: { 'accept': 'application/json' }
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'queue_cancel_failed_' + response.status));
pageUiState.pageAiQueuedItems = pageUiState.pageAiQueuedItems.filter(function(entry) {
return entry.queueId !== queueId;
});
var queueLength = Number(payload && (payload.queueLength || payload.queue_length || 0));
pageUiState.pageAiQueueLength = Number.isFinite(queueLength) ? Math.max(0, queueLength) : pageUiState.pageAiQueuedItems.length;
pageUiState.pageAiMessages.push({ role: 'assistant', content: '已取消一条 AI 队列项。' });
} catch (error) {
pageUiState.pageAiMessages.push({
role: 'assistant',
content: '取消 AI 队列项失败:' + (error instanceof Error ? error.message : String(error))
});
}
renderPageAiConversation();
renderPageAiControls();
}
function pageAiSetContextScope(scope) {
var next = String(scope || '').trim() || 'page';
pageUiState.pageAiContextScope = next;
document.documentElement.setAttribute('data-mnote-page-ai-context-scope', next);
}
function pageAiHermesSettingsUrl() {
var configured = String(window.__mnoteHermesSettingsUrl || '').trim();
return configured || '';
}
function pageAiOpenHermesSettings() {
var url = pageAiHermesSettingsUrl();
if (url) {
window.open(url, '_blank', 'noopener,noreferrer');
return;
}
pageUiState.pageAiProfileError = '未配置 Hermes 设置入口:请设置 MNOTE_WEB_HERMES_UPSTREAM_URL。';
renderPageAiControls();
}
function pageAiNormalizeTools(payload) {
var upstream = pageAiUnwrapUpstream(payload) || {};
var tools = pageAiNormalizeArray(upstream.tools || upstream);
return tools.map(function(tool) {
var name = String(tool && (tool.name || tool.toolName || tool.tool) || '').trim();
if (!name) return null;
return {
name: name,
description: String(tool && tool.description || '').trim(),
scope: String(tool && (tool.scope || tool.requiredScope || '') || '').trim(),
kind: String(tool && (tool.kind || tool.mode || '') || '').trim(),
status: String(tool && (tool.status || tool.permission || 'available') || '').trim(),
enabled: tool && tool.enabled !== false,
unavailableReason: String(tool && (tool.unavailableReason || tool.reason || '') || '').trim()
};
}).filter(Boolean);
}
function pageAiErrorMessage(payload, fallback) {
if (!payload || typeof payload !== 'object') return fallback;
return String(payload.message || payload.error || payload.code || fallback || '').trim() || fallback;
}
function pageAiNormalizeGatewayHealth(payload) {
var upstream = pageAiUnwrapUpstream(payload) || payload || {};
return {
ok: Boolean(upstream.ok),
profile: upstream.profile || null,
gateway: upstream.gateway || null,
suggestions: pageAiNormalizeArray(upstream.suggestions).map(function(item) {
return String(item || '').trim();
}).filter(Boolean)
};
}
function pageAiSetDraftForSection(section, value) {
pageUiState.pageAiProfileMemoryDrafts[section] = String(value == null ? '' : value);
}
function pageAiApplyProfileMemory(payload) {
var upstream = pageAiUnwrapUpstream(payload) || {};
pageUiState.pageAiProfileMemory = {
memory: String(upstream.memory || ''),
user: String(upstream.user || ''),
soul: String(upstream.soul || '')
};
pageUiState.pageAiProfileMemoryDrafts = {
memory: pageUiState.pageAiProfileMemory.memory,
user: pageUiState.pageAiProfileMemory.user,
soul: pageUiState.pageAiProfileMemory.soul
};
}
async function pageAiLoadTools() {
try {
var descriptor = pageAiAgentDescriptor(pageAiCurrentAgentId());
if (descriptor && pageUiState.pageAiAgentDescriptorsLoaded) {
pageUiState.pageAiTools = pageAiNormalizeArray(descriptor.tools);
pageUiState.pageAiToolsError = '';
renderPageAiControls();
return;
}
var response = await fetch('/api/hermes/client/tools?scope=mnote&profile=' + encodeURIComponent(pageAiCurrentProfile()), {
headers: { 'accept': 'application/json' }
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'tools_failed_' + response.status));
pageUiState.pageAiTools = pageAiNormalizeTools(payload);
pageUiState.pageAiToolsError = '';
} catch (error) {
pageUiState.pageAiToolsError = error instanceof Error ? error.message : String(error);
}
renderPageAiControls();
}
async function pageAiLoadGatewayHealth() {
try {
var response = await fetch('/api/hermes/client/gateway/health?profile=' + encodeURIComponent(pageAiCurrentProfile()), {
headers: { 'accept': 'application/json' }
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'gateway_health_failed_' + response.status));
pageUiState.pageAiGatewayHealth = pageAiNormalizeGatewayHealth(payload);
pageUiState.pageAiGatewayHealthError = '';
} catch (error) {
pageUiState.pageAiGatewayHealthError = error instanceof Error ? error.message : String(error);
}
renderPageAiControls();
}
async function pageAiStopRun() {
var runId = String(pageUiState.pageAiCurrentRunId || '').trim();
if (!runId || pageUiState.pageAiRunStatus === 'idle' || pageUiState.pageAiRunStatus === 'completed') return;
pageUiState.pageAiStoppedRunIds[runId] = true;
try {
var response = await fetch('/api/hermes/client/runs/' + encodeURIComponent(runId) + '/abort', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
sessionId: pageUiState.pageAiActiveSessionId,
profile: pageAiRunProfile(),
acpRuntime: pageUiState.pageAiAcpRuntime || 'reasonix',
reason: 'page_ai_user_stop'
})
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'run_abort_failed_' + response.status));
pageAiApplyRuntimeState(payload && payload.runtime);
pageAiSetRunStatus('aborted', runId);
pageUiState.pageAiMessages.push({ role: 'assistant', content: '已请求停止当前 AI run。' });
} catch (error) {
pageAiSetRunStatus('failed', runId);
pageUiState.pageAiMessages.push({
role: 'assistant',
content: '停止 AI run 失败:' + (error instanceof Error ? error.message : String(error))
});
}
renderPageAiControls();
renderPageAiConversation();
}
function pageAiLoadSkillCatalog(runtime, profile) {
var params = new URLSearchParams();
params.set('runtime', runtime);
var endpoint = '/api/hermes/client/skills';
if (runtime === 'mnote') {
endpoint = '/api/hermes/client/capabilities';
params.set('agentId', 'reasonix');
if (profile) params.set('profile', profile);
} else if (runtime === 'reasonix') {
params.set('runtime', 'reasonix');
} else if (runtime === 'hermes' && profile) {
params.set('profileId', profile);
}
return fetch(endpoint + '?' + params.toString(), {
headers: { 'accept': 'application/json' }
}).then(function(response) {
return response.json().catch(function(){ return null; }).then(function(payload) {
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'capabilities_failed_' + response.status));
return pageAiNormalizeSkills(payload);
});
});
}
async function pageAiLoadProfiles() {
try {
var response = await fetch('/api/ai/agent-profiles?agentId=hermes', {
headers: { 'accept': 'application/json' }
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'profiles_failed_' + response.status));
var profiles = pageAiNormalizeProfiles(payload);
pageUiState.pageAiProfiles = profiles.length ? profiles : [{ profileId: 'shared_lite', name: 'shared_lite', alias: 'Lite', kind: 'shared', readonly: true, canManageSkills: false }];
try {
var runtimeResponse = await fetch('/api/hermes/client/profiles', { headers: { 'accept': 'application/json' } });
var runtimePayload = await runtimeResponse.json().catch(function(){ return null; });
var acpRuntimes = Array.isArray(runtimePayload && runtimePayload.acpRuntimes) ? runtimePayload.acpRuntimes : [];
pageUiState.pageAiAcpRuntimes = pageAiNormalizeAcpRuntimes(acpRuntimes);
} catch (_) {
pageUiState.pageAiAcpRuntimes = pageAiNormalizeAcpRuntimes(pageUiState.pageAiAcpRuntimes);
}
var current = pageAiCurrentProfile();
var hasCurrent = pageUiState.pageAiProfiles.some(function(profile) { return pageAiProfileValue(profile) === current; });
var personal = pageUiState.pageAiProfiles.find(function(profile) { return profile.kind === 'personal'; });
var active = pageAiProfileValue(pageUiState.pageAiProfiles.find(function(profile) { return profile.active; }));
pageAiSetActiveProfile(hasCurrent && current !== 'default' ? current : (active || pageAiProfileValue(personal) || pageAiProfileValue(pageUiState.pageAiProfiles[0]) || current));
pageUiState.pageAiProfileError = '';
void pageAiLoadAgentDescriptors();
void pageAiLoadGatewayHealth();
} catch (error) {
pageUiState.pageAiProfileError = error instanceof Error ? error.message : String(error);
if (!pageUiState.pageAiProfiles.length) pageUiState.pageAiProfiles = [{ profileId: 'shared_lite', name: 'shared_lite', alias: 'Lite', kind: 'shared', readonly: true, canManageSkills: false }];
pageUiState.pageAiAcpRuntimes = pageAiNormalizeAcpRuntimes(pageUiState.pageAiAcpRuntimes);
pageAiSetActiveProfile(pageAiCurrentProfile());
void pageAiLoadAgentDescriptors();
}
renderPageAiProviderButtons();
renderPageAiControls();
}
async function pageAiSwitchProfile(profileName) {
var next = String(profileName || '').trim();
if (!next) return;
var previousSkillSource = pageAiCurrentSkillSource();
pageAiSetActiveProfile(next);
pageAiPersistRawAiPreference('ai.agent.hermes.profile_id', next);
if (previousSkillSource.indexOf('hermes:') === 0) {
pageUiState.pageAiActiveSkillSource = 'hermes:' + next;
pageAiPersistAiPreference('skills.active_source', pageUiState.pageAiActiveSkillSource);
}
pageUiState.pageAiSkills = { categories: [], archived: [] };
pageUiState.pageAiSkillCatalogs = Object.assign({}, pageUiState.pageAiSkillCatalogs || {}, {
hermes: { categories: [], archived: [] }
});
pageUiState.pageAiSkillError = '';
renderPageAiProviderButtons();
renderPageAiControls();
try {
pageUiState.pageAiSessions = pageUiState.pageAiSessions.filter(function(session) {
return session && session.profile === next;
});
pageUiState.pageAiActiveSessionId = '';
pageUiState.pageAiMessages = [];
pageAiPersistSessions();
await pageAiEnsureHermesSession(true);
await pageAiLoadProfileMemory();
await pageAiLoadAgentDescriptors();
await pageAiLoadSkills();
await pageAiLoadTools();
await pageAiLoadGatewayHealth();
renderPageAiControls();
} catch (error) {
pageUiState.pageAiProfileError = error instanceof Error ? error.message : String(error);
}
renderPageAiConversation();
}
async function pageAiLoadProfileMemory() {
try {
var response = await fetch('/api/hermes/client/profile-memory?profileId=' + encodeURIComponent(pageAiCurrentProfile()), {
headers: { 'accept': 'application/json' }
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'profile_memory_failed_' + response.status));
pageAiApplyProfileMemory(payload);
pageUiState.pageAiProfileMemoryError = '';
} catch (error) {
pageUiState.pageAiProfileMemoryError = error instanceof Error ? error.message : String(error);
}
renderPageAiControls();
renderPageAiConversation();
}
async function pageAiSaveProfileMemory(section) {
var normalized = String(section || '').trim();
if (['memory', 'user', 'soul'].indexOf(normalized) < 0) return;
var content = String(pageUiState.pageAiProfileMemoryDrafts[normalized] || '');
try {
var response = await fetch('/api/hermes/client/profile-memory', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
profileId: pageAiCurrentProfile(),
section: normalized,
content: content
})
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'profile_memory_save_failed_' + response.status));
pageUiState.pageAiProfileMemory[normalized] = content;
pageUiState.pageAiProfileMemoryError = '';
document.documentElement.setAttribute('data-mnote-page-ai-memory-saved', normalized);
} catch (error) {
pageUiState.pageAiProfileMemoryError = error instanceof Error ? error.message : String(error);
}
renderPageAiControls();
renderPageAiConversation();
}
async function pageAiLoadSkills() {
var requestedSource = pageAiCurrentSkillSource();
var sourceParts = pageAiSkillSourceParts(requestedSource);
var loadSeq = (Number(pageUiState.pageAiSkillLoadSeq || 0) || 0) + 1;
pageUiState.pageAiSkillLoadSeq = loadSeq;
try {
var catalog = await pageAiLoadSkillCatalog(sourceParts.group, sourceParts.profile || pageAiCurrentProfile());
if (pageUiState.pageAiSkillLoadSeq !== loadSeq
|| pageAiCurrentSkillSource() !== requestedSource) return;
pageUiState.pageAiSkillCatalogs = Object.assign({}, pageUiState.pageAiSkillCatalogs || {}, {
[sourceParts.group]: catalog,
[requestedSource]: catalog
});
pageUiState.pageAiSkills = catalog;
pageUiState.pageAiSkillError = '';
} catch (error) {
if (pageUiState.pageAiSkillLoadSeq !== loadSeq
|| pageAiCurrentSkillSource() !== requestedSource) return;
pageUiState.pageAiSkillError = error instanceof Error ? error.message : String(error);
pageUiState.pageAiSkills = { categories: [], archived: [] };
pageUiState.pageAiSkillCatalogs = pageUiState.pageAiSkillCatalogs || { mnote: { categories: [], archived: [] }, reasonix: { categories: [], archived: [] }, hermes: { categories: [], archived: [] } };
}
renderPageAiControls();
renderPageAiConversation();
}
async function pageAiToggleSkill(skillName, enabled, group, profile) {
var name = String(skillName || '').trim();
if (!name) return;
var skillGroup = String(group || 'hermes').trim() || 'hermes';
var skillProfile = String(profile || pageAiCurrentProfile() || '').trim();
if (skillGroup === 'reasonix') {
pageAiSetSkillPreference(skillGroup, name, Boolean(enabled), skillProfile);
document.documentElement.setAttribute('data-mnote-page-ai-skill-toggled', skillGroup + ':' + name);
renderPageAiControls();
return;
}
if (skillGroup === 'mnote') {
try {
var mnoteResponse = await fetch('/api/hermes/client/capabilities/toggle', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
runtime: 'mnote',
profile: skillProfile || pageAiCurrentProfile(),
id: name,
enabled: Boolean(enabled)
})
});
var mnotePayload = await mnoteResponse.json().catch(function(){ return null; });
if (!mnoteResponse.ok) throw new Error(pageAiErrorMessage(mnotePayload, 'mnote_capability_toggle_failed_' + mnoteResponse.status));
pageAiSetSkillPreference(skillGroup, name, Boolean(enabled), skillProfile);
pageAiNormalizeArray(pageUiState.pageAiSkillCatalogs && pageUiState.pageAiSkillCatalogs.mnote && pageUiState.pageAiSkillCatalogs.mnote.categories).forEach(function(category) {
pageAiNormalizeArray(category.skills).forEach(function(skill) {
if (skill.id === name || skill.name === name) {
skill.enabled = Boolean(enabled);
skill.status = enabled ? 'available' : 'disabled';
pageAiNormalizeArray(skill.tools).forEach(function(tool) {
tool.enabled = Boolean(enabled);
tool.status = enabled ? 'available' : 'disabled';
});
skill.disabledToolCount = enabled ? 0 : Number(skill.toolCount || pageAiNormalizeArray(skill.tools).length || 0);
}
});
});
document.documentElement.setAttribute('data-mnote-page-ai-skill-toggled', skillGroup + ':' + name);
} catch (error) {
pageUiState.pageAiSkillError = error instanceof Error ? error.message : String(error);
}
renderPageAiControls();
return;
}
var previous = null;
pageAiToggleableSkillEntries('hermes', skillProfile || pageAiCurrentProfile()).forEach(function(skill) {
if (skill.id === name || skill.name === name) previous = skill.enabled !== false;
});
try {
var response = await fetch('/api/hermes/client/skills/toggle', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
profile: skillProfile || pageAiCurrentProfile(),
profileId: skillProfile || pageAiCurrentProfile(),
skillKind: 'hermes_profile',
name: name,
enabled: Boolean(enabled)
})
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'skill_toggle_failed_' + response.status));
var hermesCatalog = pageUiState.pageAiSkillCatalogs && pageUiState.pageAiSkillCatalogs.hermes
? pageUiState.pageAiSkillCatalogs.hermes
: pageUiState.pageAiSkills;
pageAiNormalizeArray(hermesCatalog.categories).forEach(function(category) {
pageAiNormalizeArray(category.skills).forEach(function(skill) {
if (skill.name === name || skill.id === name) skill.enabled = Boolean(enabled);
});
});
pageUiState.pageAiSkills = hermesCatalog;
pageAiSetSkillPreference('hermes', name, Boolean(enabled), skillProfile || pageAiCurrentProfile());
document.documentElement.setAttribute('data-mnote-page-ai-skill-toggled', name);
pageUiState.pageAiSkillError = '';
} catch (error) {
pageUiState.pageAiSkillError = error instanceof Error ? error.message : String(error);
if (previous != null) {
var rollbackCatalog = pageUiState.pageAiSkillCatalogs && pageUiState.pageAiSkillCatalogs.hermes
? pageUiState.pageAiSkillCatalogs.hermes
: pageUiState.pageAiSkills;
pageAiNormalizeArray(rollbackCatalog.categories).forEach(function(category) {
pageAiNormalizeArray(category.skills).forEach(function(skill) {
if (skill.name === name || skill.id === name) skill.enabled = previous;
});
});
}
}
renderPageAiControls();
renderPageAiConversation();
}
async function pageAiToggleTool(toolName, enabled) {
var name = String(toolName || '').trim();
if (!name) return;
var previous = null;
pageAiNormalizeArray(pageUiState.pageAiTools).forEach(function(tool) {
if (tool.name === name && previous == null) previous = tool.enabled !== false;
});
try {
var response = await fetch('/api/hermes/client/tools/toggle', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
profile: pageAiCurrentProfile(),
name: name,
enabled: Boolean(enabled)
})
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok) throw new Error(pageAiErrorMessage(payload, 'tool_toggle_failed_' + response.status));
pageAiNormalizeArray(pageUiState.pageAiTools).forEach(function(tool) {
if (tool.name === name) {
tool.enabled = Boolean(enabled);
tool.status = Boolean(enabled) ? 'available' : 'disabled';
tool.unavailableReason = Boolean(enabled) ? '' : '当前 Hermes profile 已关闭该 mnote tool';
}
});
document.documentElement.setAttribute('data-mnote-page-ai-tool-toggled', name);
pageUiState.pageAiToolsError = '';
} catch (error) {
pageUiState.pageAiToolsError = error instanceof Error ? error.message : String(error);
if (previous != null) {
pageAiNormalizeArray(pageUiState.pageAiTools).forEach(function(tool) {
if (tool.name === name) tool.enabled = previous;
});
}
}
renderPageAiControls();
}
function openPageAiDrawer() {
pageUiState.pageAiAgentId = pageAiCurrentAgentId();
pageAiEnsureContextRefState();
pageAiLoadSessions();
renderPageAiSuggestions();
renderPageAiConversation();
renderPageAiProviderButtons();
renderPageAiControls();
var drawer = ensurePageAiDrawer();
pageAiApplyDrawerWidth(drawer);
drawer.hidden = false;
pageUiState.pageAiOpen = true;
updatePageAiTriggerState();
void pageAiCheckAndResumeActiveRun().catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
void pageAiLoadBackendSessions().then(function() {
return pageAiCheckAndResumeActiveRun();
}).catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
Promise.all([
pageAiLoadProfiles(),
pageAiLoadProfileMemory(),
pageAiLoadAgentDescriptors(),
pageAiLoadSkills(),
pageAiLoadTools(),
pageAiLoadGatewayHealth(),
pageAiLoadAiPreferences(),
pageAiLoadAllowedRoots(),
pageAiLoadBackendSessions()
]).then(function() {
renderPageAiControls();
}).then(function() {
return pageAiCheckAndResumeActiveRun().catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
return null;
});
}).then(function() {
return pageAiRestoreHermesSession();
}).then(function() {
renderPageAiControls();
}).catch(function(error) {
pageUiState.pageAiMessages.push({
role: 'assistant',
content: '当前 AI 不可用:' + (error instanceof Error ? error.message : String(error))
});
renderPageAiConversation();
renderPageAiControls();
});
}
function closePageAiDrawer() {
var drawer = document.querySelector('[data-testid="wolai-page-ai-drawer"]');
if (drawer instanceof HTMLElement) drawer.hidden = true;
pageUiState.pageAiOpen = false;
updatePageAiTriggerState();
}
function isPageAiDrawerOpen() {
var drawer = document.querySelector('[data-testid="wolai-page-ai-drawer"]');
return drawer instanceof HTMLElement && !drawer.hidden;
}
async function streamPageAiResponse(response, onEvent) {
if (!response.body || typeof response.body.getReader !== 'function') return;
var reader = response.body.getReader();
var decoder = new TextDecoder();
var buffer = '';
while (true) {
var chunk = await reader.read();
if (chunk.done) break;
buffer += decoder.decode(chunk.value, { stream: true });
var frames = buffer.split('\n\n');
buffer = frames.pop() || '';
frames.forEach(function(frame) {
var eventName = '';
var dataLines = [];
frame.split('\n').forEach(function(line) {
if (line.startsWith('event:')) eventName = line.slice(6).trim();
if (line.startsWith('data:')) dataLines.push(line.slice(5).trim());
});
var payloadText = dataLines.join('\n');
if (!eventName && payloadText) {
try {
var parsed = JSON.parse(payloadText);
eventName = parsed && parsed.event ? String(parsed.event) : '';
} catch (_) {}
}
if (eventName) onEvent(eventName, payloadText);
});
}
}
function pageAiDecodeDeltaText(payloadText) {
try {
var payload = JSON.parse(payloadText || 'null');
return String((payload && (payload.text || payload.delta)) || '');
} catch (_) {
return String(payloadText || '');
}
}
function pageAiEventSeqFromPayloadText(payloadText) {
try {
var payload = JSON.parse(payloadText || 'null');
return String((payload && payload.seq) || '').trim();
} catch (_) {
return '';
}
}
function pageAiTrackStreamingRunEvent(runId, eventName, payloadText) {
var seq = pageAiEventSeqFromPayloadText(payloadText);
if (!seq) return;
pageAiWriteActiveRunSnapshot({
hostRunId: runId,
sessionId: pageUiState.pageAiActiveSessionId || '',
lastSeq: seq,
status: pageAiRunStatusIsTerminal(eventName) ? pageUiState.pageAiRunStatus : (pageUiState.pageAiRunStatus || 'running')
});
document.documentElement.setAttribute('data-mnote-page-ai-active-run-last-seq', seq);
}
function pageAiEnsureStreamingAssistantMessage(runId) {
var id = String(runId || pageUiState.pageAiCurrentRunId || '');
var existing = pageUiState.pageAiMessages.find(function(item) {
return item.role === 'assistant' && item.streaming === true && item.runId === id;
});
if (existing) return existing;
existing = {
role: 'assistant',
content: '',
runId: id,
streaming: true
};
pageUiState.pageAiMessages.push(existing);
return existing;
}
function pageAiAppendStreamingAssistantDelta(runId, deltaText) {
var delta = String(deltaText || '');
if (!delta) return '';
var message = pageAiEnsureStreamingAssistantMessage(runId);
message.content = String(message.content || '') + delta;
pageAiSyncCurrentSessionMessages();
renderPageAiConversation();
return message.content;
}
function pageAiAppendCitationSection(content, citations) {
var text = String(content || '');
var unique = [];
pageAiNormalizeArray(citations).forEach(function(value) {
var citation = String(value || '').trim();
if (!citation || unique.indexOf(citation) >= 0) return;
unique.push(citation);
});
var missing = unique.filter(function(citation) {
return text.indexOf(citation) < 0;
});
if (!missing.length) return text;
return text.replace(/\s+$/g, '') + '\n\n**引用**\n' + missing.map(function(citation) {
return '- ' + citation;
}).join('\n');
}
function pageAiPromptNeedsKnowledgeRagCitations(prompt) {
var text = searchText(prompt);
if (!text) return false;
var asksCitation = ['链接', '引用', '来源', '出处', '证据', '定位', 'link', 'citation', 'source'].some(function(word) {
return text.indexOf(word) >= 0;
});
if (!asksCitation) return false;
return ['lightrag', '资料库', '知识库', 'rag', '文献', '论文', '保护基'].some(function(word) {
return text.indexOf(word) >= 0;
});
}
function pageAiKnowledgeRagFallbackQuery(prompt) {
var text = searchText(prompt);
if (!text) return '';
var afterColon = text.split(/[:]/).slice(1).join('').trim();
var candidate = afterColon || text;
candidate = candidate
.replace(/^(请|请用|帮我|帮忙|用)?(资料库|知识库|lightrag|rag)?(搜索|检索|查找|查询|回答|说明|解释|总结)?/i, '')
.replace(/(请)?(给出|给我|附上|提供)?(链接|引用|来源|出处|证据|定位).*$/i, '')
.trim();
var stopIndex = candidate.search(/(在|的|是|有哪些|有什么|如何|怎么|用于|用途|作用|资料|文献|论文)/);
if (stopIndex > 0) candidate = candidate.slice(0, stopIndex).trim();
var cjkMatch = candidate.match(/[A-Za-z0-9\u4e00-\u9fff·α-ωΑ-Ω\-]{2,24}/);
if (cjkMatch && cjkMatch[0]) return cjkMatch[0];
return text;
}
function pageAiCleanDegradedCitationNotes(content) {
return String(content || '')
.split('\n')
.filter(function(line) {
var text = String(line || '');
return text.indexOf('来源定位降级') < 0 && text.toLowerCase().indexOf('locator degraded') < 0;
})
.join('\n')
.replace(/\n{3,}/g, '\n\n')
.trim();
}
function pageAiCitationPrecisionLabel(value) {
var precision = searchText(value || '').toLowerCase();
if (precision === 'bbox') return '精确定位';
if (precision === 'paragraph') return '段落级';
if (precision === 'file') return '文件级';
return '';
}
function pageAiCitationSourceTitle(citation) {
if (!citation || typeof citation !== 'object') return '';
var path = searchText(citation.sourceRootRelativePath || citation.sourcePath || citation.filePath || citation.lightRagFilePath || '');
if (path) {
var parts = path.split('/').filter(Boolean);
return parts[parts.length - 1] || path;
}
var markdown = searchText(citation.citationMarkdown || '');
var labelMatch = markdown.match(/^\[([^\]]+)\]/);
return labelMatch ? labelMatch[1] : '';
}
function pageAiCitationDisplayMarkdown(value) {
if (typeof value === 'string') return value.trim();
if (!value || typeof value !== 'object') return '';
var markdown = searchText(value.citationMarkdown || '');
var citationId = searchText(value.citationLabel || (value.citationId ? '[' + value.citationId + ']' : ''));
var title = pageAiCitationSourceTitle(value);
var headingPath = pageAiNormalizeArray(value.headingPath).map(function(item) {
return searchText(item);
}).filter(Boolean).join(' > ');
var precisionLabel = pageAiCitationPrecisionLabel(value.locatorPrecision);
var quote = searchText(value.displayQuote || value.quote || '');
if (quote.length > 120) quote = quote.slice(0, 117) + '...';
var head = markdown || title;
if (citationId && head.indexOf(citationId) < 0) head = citationId + ' ' + head;
var details = [];
if (precisionLabel) details.push(precisionLabel);
if (headingPath) details.push(headingPath);
if (quote) details.push(quote);
return [head].concat(details).filter(Boolean).join(' · ').trim();
}
function pageAiFilterCitationCards(values) {
var cards = pageAiNormalizeArray(values);
var hasPreciseCitation = cards.some(function(value) {
if (typeof value === 'string') return value.indexOf('来源定位降级') < 0;
return value && typeof value === 'object' && searchText(value.citationMarkdown || '') && value.locatorDegraded !== true;
});
var seen = {};
return cards.map(pageAiCitationDisplayMarkdown).filter(function(card, index) {
var source = cards[index];
if (!card || seen[card]) return false;
if (hasPreciseCitation) {
if (typeof source === 'string' && source.indexOf('来源定位降级') >= 0) return false;
if (source && typeof source === 'object' && source.locatorDegraded === true) return false;
}
seen[card] = true;
return true;
}).slice(0, 5);
}
function pageAiCollectKnowledgeRagApiCitations(payload) {
var structuredCitations = pageAiNormalizeArray(payload && payload.citations);
if (structuredCitations.length) {
return pageAiFilterCitationCards(structuredCitations);
}
var references = pageAiNormalizeArray(payload && payload.references);
return pageAiFilterCitationCards(references);
}
async function pageAiAppendKnowledgeRagFallbackCitations(runId, promptText) {
if (!pageAiPromptNeedsKnowledgeRagCitations(promptText)) return;
var rootUri = currentRootUri();
if (!rootUri) return;
var fallbackQuery = pageAiKnowledgeRagFallbackQuery(promptText);
if (!fallbackQuery) return;
try {
var response = await fetch('/api/knowledge-rag/search', {
method: 'POST',
headers: { 'content-type': 'application/json', 'accept': 'application/json' },
body: JSON.stringify({
workspaceId: resolveWorkspaceId(document.body) || undefined,
rootUri: rootUri,
query: fallbackQuery,
mode: 'mix',
topK: 12,
chunkTopK: 24,
includeChunkContent: true
})
});
var payload = await response.json().catch(function() { return null; });
if (!response.ok) return;
var citations = pageAiCollectKnowledgeRagApiCitations(payload);
if (!citations.length) return;
var message = pageUiState.pageAiMessages.find(function(item) {
return item.role === 'assistant' && item.runId === runId;
}) || pageUiState.pageAiMessages.filter(function(item) { return item.role === 'assistant'; }).slice(-1)[0];
if (!message) return;
var hasPrecise = citations.some(function(citation) { return citation.indexOf('来源定位降级') < 0; });
var baseContent = hasPrecise ? pageAiCleanDegradedCitationNotes(message.content) : String(message.content || '');
message.content = pageAiAppendCitationSection(baseContent, citations);
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
renderPageAiConversation();
} catch (error) {
console.warn('MNote Page AI 自动追加 LightRAG 引用失败', error);
}
}
function pageAiFinishStreamingAssistantMessage(runId, finalText, promptText, citations) {
var id = String(runId || pageUiState.pageAiCurrentRunId || '');
var message = pageUiState.pageAiMessages.find(function(item) {
return item.role === 'assistant' && item.streaming === true && item.runId === id;
});
var text = String(finalText || (message && message.content) || '');
var hasPreciseCitation = pageAiNormalizeArray(citations).some(function(citation) {
return String(citation || '').indexOf('来源定位降级') < 0;
});
var contentBase = humanizePageAiResponse(text, promptText);
if (hasPreciseCitation) contentBase = pageAiCleanDegradedCitationNotes(contentBase);
var content = pageAiAppendCitationSection(contentBase, citations);
if (message) {
message.content = content;
message.streaming = false;
} else if (content) {
pageUiState.pageAiMessages.push({
role: 'assistant',
content: content,
runId: id
});
}
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
void pageAiAppendKnowledgeRagFallbackCitations(id, promptText);
}
function pageAiStopStreamingAssistantMessage(runId) {
var id = String(runId || pageUiState.pageAiCurrentRunId || '');
var changed = false;
pageUiState.pageAiMessages.forEach(function(message) {
if (message && message.role === 'assistant' && message.streaming === true && (!id || message.runId === id)) {
message.streaming = false;
changed = true;
}
});
if (!changed) return;
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
renderPageAiConversation();
}
function pageAiToolOutputText(value) {
var parts = [];
function visit(node) {
if (node == null) return;
if (typeof node === 'string') {
parts.push(node);
return;
}
if (typeof node === 'number' || typeof node === 'boolean') return;
if (Array.isArray(node)) {
node.forEach(visit);
return;
}
if (typeof node !== 'object') return;
if (typeof node.text === 'string') parts.push(node.text);
if (typeof node.content === 'string') parts.push(node.content);
if (node.content && typeof node.content === 'object') visit(node.content);
if (node.output && typeof node.output === 'object') visit(node.output);
if (node.result && typeof node.result === 'object') visit(node.result);
}
visit(value);
return parts.join('\n');
}
function pageAiParseJsonMaybe(value) {
if (value && typeof value === 'object') return value;
var text = String(value || '').trim();
if (!text || (text[0] !== '{' && text[0] !== '[')) return null;
try {
return JSON.parse(text);
} catch (_error) {
var firstLine = text.split('\n')[0].trim();
if (firstLine && firstLine !== text && (firstLine[0] === '{' || firstLine[0] === '[')) {
try {
return JSON.parse(firstLine);
} catch (_lineError) {}
}
return null;
}
}
function pageAiCollectCitationMarkdowns(value) {
var citations = [];
var seen = {};
function add(value) {
var citation = String(value || '').trim();
if (!citation || seen[citation]) return;
seen[citation] = true;
citations.push(citation);
}
function visit(node) {
if (node == null) return;
if (typeof node === 'string') {
var parsed = pageAiParseJsonMaybe(node);
if (parsed) visit(parsed);
return;
}
if (Array.isArray(node)) {
node.forEach(visit);
return;
}
if (typeof node !== 'object') return;
if (typeof node.citationMarkdown === 'string') add(pageAiCitationDisplayMarkdown(node));
if (Array.isArray(node.citationMarkdowns)) {
node.citationMarkdowns.forEach(function(value) {
if (typeof value === 'string') add(value);
else if (value && typeof value === 'object') add(pageAiCitationDisplayMarkdown(value));
else visit(value);
});
}
Object.keys(node).forEach(function(key) {
visit(node[key]);
});
}
visit(value);
return citations;
}
function pageAiCollectKnowledgeRagCitations(toolItem, toolEvent) {
var toolName = String((toolItem && toolItem.toolName) || (toolEvent && (toolEvent.name || toolEvent.tool || toolEvent.toolName)) || '');
var sources = [
toolEvent,
toolItem,
toolEvent && toolEvent.output,
toolEvent && toolEvent.result,
toolEvent && toolEvent.summary,
toolItem && toolItem.rawOutput,
toolItem && toolItem.rawResult,
toolItem && toolItem.resultSummary
];
var citations = [];
var outputText = '';
sources.forEach(function(source) {
citations = citations.concat(pageAiCollectCitationMarkdowns(source));
var sourceText = pageAiToolOutputText(source);
if (sourceText) outputText += '\n' + sourceText;
var parsed = pageAiParseJsonMaybe(sourceText);
if (parsed) citations = citations.concat(pageAiCollectCitationMarkdowns(parsed));
});
var looksLikeKnowledgeRag = toolName.indexOf('knowledge_rag') >= 0 ||
toolName.indexOf('knowledge.rag') >= 0 ||
outputText.indexOf('mnote.knowledge_rag') >= 0 ||
outputText.indexOf('uiCitations') >= 0;
if (!looksLikeKnowledgeRag && citations.length === 0) return [];
var hasPreciseCitation = citations.some(function(value) {
return String(value || '').indexOf('来源定位降级') < 0;
});
var seen = {};
return citations.filter(function(value) {
var citation = String(value || '').trim();
if (!citation || seen[citation]) return false;
if (hasPreciseCitation && citation.indexOf('来源定位降级') >= 0) return false;
seen[citation] = true;
return true;
});
}
function pageAiJournalPayloadText(event) {
try {
return JSON.stringify(event && event.payload && typeof event.payload === 'object' ? event.payload : {});
} catch (_) {
return '{}';
}
}
function pageAiLastUserPrompt() {
var messages = pageAiNormalizeArray(pageUiState.pageAiMessages);
for (var index = messages.length - 1; index >= 0; index -= 1) {
if (messages[index] && messages[index].role === 'user') return String(messages[index].content || '');
}
return '';
}
function pageAiApplyRunJournalEvent(event, runId, runTraceId) {
if (!event || typeof event !== 'object') return;
var eventName = String(event.kind || event.eventType || event.event || '').trim();
var payload = event.payload && typeof event.payload === 'object' ? event.payload : {};
if (payload.source === 'adapter_replay' || payload.replay === true) {
document.documentElement.setAttribute('data-mnote-page-ai-adapter-replay-seen', 'true');
return;
}
var payloadText = pageAiJournalPayloadText(event);
var prompt = pageAiLastUserPrompt();
if (eventName === 'message.delta') {
pageAiAppendStreamingAssistantDelta(runId, pageAiDecodeDeltaText(payloadText));
} else if (eventName === 'run.completed') {
pageAiFinishStreamingAssistantMessage(runId, String(payload.output || ''), prompt, []);
pageAiSetRunStatus('completed', runId);
} else if (eventName === 'run.failed') {
pageAiFinishStreamingAssistantMessage(runId, String(payload.message || payload.code || payload.error || 'AI run failed'), prompt, []);
pageAiSetRunStatus('failed', runId);
} else if (eventName === 'run.aborted' || eventName === 'run.cancelled' || eventName === 'run.canceled') {
pageUiState.pageAiStoppedRunIds[runId] = true;
pageAiStopStreamingAssistantMessage(runId);
pageAiSetRunStatus('aborted', runId);
} else if (eventName === 'tool.started' || eventName === 'tool.completed' || eventName === 'tool.failed') {
var toolItem = pageAiApplyToolEvent(eventName, payloadText, runId, runTraceId);
if (eventName === 'tool.completed') {
var citations = pageAiCollectKnowledgeRagCitations(toolItem, payload);
if (citations.length) pageAiFinishStreamingAssistantMessage(runId, '', prompt, citations);
}
pageAiSetRunStatus('tool_calling', runId);
} else if (eventName === 'plan.updated') {
var planEntries = Array.isArray(payload.entries) ? payload.entries : [];
if (planEntries.length) {
pageUiState.pageAiMessages.push({ role: 'system', kind: 'plan', entries: planEntries, createdAt: Date.now(), updatedAt: Date.now() });
}
}
var seq = String(event.seq || '').trim();
if (seq) {
pageAiWriteActiveRunSnapshot({
hostRunId: runId,
sessionId: pageUiState.pageAiActiveSessionId || String(event.sessionId || ''),
lastSeq: seq,
status: pageUiState.pageAiRunStatus || 'running'
});
document.documentElement.setAttribute('data-mnote-page-ai-active-run-last-seq', seq);
}
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
renderPageAiConversation();
renderPageAiControls();
}
async function pageAiResumeActiveRunJournal(run) {
if (!run || typeof run !== 'object') return;
var runId = String(run.hostRunId || run.runId || '').trim();
if (!runId) return;
var snapshot = pageAiReadActiveRunSnapshot();
var afterSeq = snapshot && snapshot.hostRunId === runId ? String(snapshot.lastSeq || '000000000000000000') : '000000000000000000';
var response = await fetch('/api/page-ai/runs/' + encodeURIComponent(runId) + '/events?afterSeq=' + encodeURIComponent(afterSeq), {
headers: { 'accept': 'application/json' }
});
var payload = await response.json().catch(function(){ return null; });
if (!response.ok || !payload || payload.ok !== true) {
throw new Error(pageAiErrorMessage(payload, 'run_journal_failed_' + response.status));
}
var runTraceId = String((payload.run && payload.run.traceId) || (run && run.traceId) || '');
pageAiNormalizeArray(payload.events).forEach(function(event) {
pageAiApplyRunJournalEvent(event, runId, runTraceId);
});
var status = String((payload.run && payload.run.status) || run.status || '').trim();
if (pageAiRunStatusIsTerminal(status)) pageAiClearActiveRunSnapshot(runId);
document.documentElement.setAttribute('data-mnote-page-ai-run-journal-resumed', runId);
}
function pageAiLooksLikeBlockEdit(prompt) {
var text = searchText(prompt);
return ['新增', '添加', '插入', '删除', '删掉', '修改', '替换', '改成', '移动', '移到', 'move', 'replace', 'delete', 'insert'].some(function(word) {
return text.indexOf(word) >= 0;
});
}
function assertPageAiLocalWritePermission(prompt, targetPackage) {
if (currentSourceKind() !== 'local_folder') return;
if (!pageAiLooksLikeBlockEdit(prompt)) return;
var target = pageAiNormalizeArray(targetPackage && targetPackage.targets)[0] || null;
var permission = String(target && target.policy && target.policy.permission || '').trim();
if (permission === 'read_write') return;
var error = new Error('当前本地工作区只读授权,不能让 AI 写入目标文件。请切换到有写权限的工作区或调整授权后重试。');
error.code = 'page_ai_target_readonly';
throw error;
}
async function pageAiTryBlockEditWorkflow(prompt, scopedContext, runTargetSnapshot) {
if (currentSourceKind() === 'local_folder') return false;
if (!pageAiLooksLikeBlockEdit(prompt)) return false;
var runId = 'page-ai-fast-' + Date.now().toString(36);
var traceId = 'page-ai-fast-' + Date.now().toString(36);
pageAiSetRunStatus('running', runId);
renderPageAiControls();
var started = Date.now();
var response = await fetch('/api/page-ai/block-edit-workflow', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
workspaceId: resolveWorkspaceId(document.body),
documentId: currentDocumentId(),
sourceKind: currentSourceKind(),
rootUri: currentRootUri(),
sessionId: pageUiState.pageAiActiveSessionId,
runId: runId,
profile: pageAiCurrentProfile(),
model: pageAiMnoteToolModel(),
message: prompt,
pageContext: scopedContext.pageContext,
editorTarget: scopedContext.editorTarget,
runTargetSnapshot: runTargetSnapshot || null,
selectedBlockId: scopedContext.selectedBlockId,
selectedText: scopedContext.selectedText,
traceId: traceId
})
});
var payload = await response.json().catch(function() { return null; });
if (!response.ok || !payload || payload.ok !== true) {
var code = payload && payload.code ? String(payload.code) : '';
if (code === 'page_ai_workflow_not_block_edit') return false;
pageUiState.pageAiMessages.push({
role: 'tool',
toolName: 'mnote.page_ai.block_edit_workflow',
status: 'failed',
toolCallId: runId,
resultSummary: pageAiErrorMessage(payload, 'fast_path_failed_' + response.status)
});
renderPageAiConversation();
pageAiSetRunStatus('failed', runId);
renderPageAiControls();
return true;
}
pageUiState.pageAiMessages.push({
role: 'tool',
toolName: 'mnote.page_ai.block_edit_workflow',
status: 'completed',
toolCallId: runId,
resultSummary: 'operations=' + String(Array.isArray(payload.operations) ? payload.operations.length : 0) + ' · ' + String(Date.now() - started) + 'ms'
});
pageUiState.pageAiMessages.push({
role: 'assistant',
content: payload.message || '已通过页面块编辑快路径完成写入。'
});
pageAiSetRunStatus('completed', runId);
try {
window.dispatchEvent(new CustomEvent('mnote:page-ai-tool-write-completed', {
detail: {
toolName: 'mnote.doc.apply_block_ops',
normalizedToolName: 'mnote.doc.apply.block.ops',
documentId: currentDocumentId(),
workspaceId: resolveWorkspaceId(document.body),
runId: runId,
traceId: traceId,
toolCallId: runId
}
}));
} catch (_) {}
var currentSession = pageAiCurrentSession();
if (currentSession) {
currentSession.messages = pageUiState.pageAiMessages.slice();
currentSession.updatedAt = Date.now();
}
pageAiPersistSessions();
renderPageAiConversation();
renderPageAiControls();
return true;
}
async function sendPageAiMessage(text) {
var allowQueue = ['running', 'tool_calling'].indexOf(pageUiState.pageAiRunStatus) >= 0;
if (pageUiState.pageAiBusy && !allowQueue) return;
var prompt = searchText(text);
if (!prompt) return;
if (!allowQueue) pageUiState.pageAiBusy = true;
var currentSession = null;
try {
await pageAiEnsureHermesSession();
if (!allowQueue) pageAiSetRunStatus('queued');
renderPageAiControls();
var contextSnapshot = currentPageAiContextSnapshot();
var scopedContext = pageAiScopedPageContext(contextSnapshot);
scopedContext.editorTarget = currentPageAiScopedEditorTarget();
assertPageAiTargetInCurrentWorkspace(scopedContext.editorTarget);
if (currentSourceKind() === 'local_folder' && !pageAiNormalizeArray(pageUiState.pageAiAllowedRoots).length) {
await pageAiLoadAllowedRoots();
}
await assertPageAiTargetWritable(scopedContext.editorTarget);
var runTargetSnapshot = pageAiBuildRunTargetSnapshot(scopedContext, prompt);
var contextRefs = pageAiBuildContextRefs(scopedContext, runTargetSnapshot);
var allowedRoots = pageAiBuildAllowedRoots();
var agentTargetPackage = pageAiBuildAgentTargetPackage(scopedContext, runTargetSnapshot);
assertPageAiLocalWritePermission(prompt, agentTargetPackage);
if (scopedContext.pageContext && scopedContext.pageContext.aiContext) {
scopedContext.pageContext.aiContext.runTargetSnapshot = runTargetSnapshot;
scopedContext.pageContext.aiContext.agentTargetPackage = agentTargetPackage;
}
var requestPageContext = pageAiPageContextForRefs(scopedContext.pageContext, contextRefs);
pageUiState.pageAiMessages.push({ role: 'user', content: prompt });
currentSession = pageAiCurrentSession();
var runProfile = pageAiRunProfile();
if (currentSession) {
if (currentSession.title === '新会话') {
currentSession.title = prompt.length > 18 ? prompt.slice(0, 18) + '…' : prompt;
}
currentSession.messages = pageUiState.pageAiMessages.slice();
currentSession.updatedAt = Date.now();
}
pageAiPersistSessions();
renderPageAiConversation();
if (!allowQueue && await pageAiTryBlockEditWorkflow(prompt, scopedContext, runTargetSnapshot)) {
return;
}
var response = await fetch('/api/hermes/client/runs', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
workspaceId: resolveWorkspaceId(document.body),
documentId: currentDocumentId(),
sourceKind: currentSourceKind(),
rootUri: currentRootUri(),
agentId: pageAiCurrentAgentId(),
sessionId: pageUiState.pageAiActiveSessionId,
acpSessionId: currentSession && currentSession.acpSessionId ? currentSession.acpSessionId : '',
profile: runProfile,
profileId: pageUiState.pageAiAcpRuntime === 'hermes' ? runProfile : '',
acpRuntime: pageUiState.pageAiAcpRuntime || 'reasonix',
contextScope: pageUiState.pageAiContextScope,
contextRefs: contextRefs,
allowedRoots: allowedRoots,
skillPreferences: {
mnote: pageAiSkillPreferenceTable('mnote', ''),
reasonix: pageAiSkillPreferenceTable('reasonix', ''),
hermes: pageAiSkillPreferenceTable('hermes', runProfile)
},
message: prompt,
model: pageAiMnoteToolModel(),
pageContext: requestPageContext,
editorTarget: scopedContext.editorTarget,
runTargetSnapshot: runTargetSnapshot,
targetPackage: agentTargetPackage,
selectedBlockId: scopedContext.selectedBlockId,
selectedText: scopedContext.selectedText || '',
traceId: 'page-ai-run-' + Date.now().toString(36)
})
});
if (!response.ok) {
var errorPayload = await response.json().catch(function(){ return null; });
throw new Error(pageAiErrorMessage(errorPayload, 'page_ai_failed_' + response.status));
}
var runPayload = await response.json().catch(function(){ return null; });
if (pageAiApplyQueuedRun(runPayload)) {
pageUiState.pageAiMessages.push({
role: 'assistant',
content: '已加入 AI 队列,前一条 run 完成后继续处理。'
});
if (currentSession) {
currentSession.messages = pageUiState.pageAiMessages.slice();
currentSession.updatedAt = Date.now();
}
pageAiPersistSessions();
renderPageAiConversation();
renderPageAiControls();
return;
}
if (allowQueue) {
throw new Error('hermes_queue_expected_queued_response');
}
var upstream = runPayload && runPayload.upstream ? runPayload.upstream : runPayload;
var runId = upstream && (upstream.run_id || upstream.runId);
if (!runId) throw new Error('hermes_run_missing_run_id');
var runTraceId = String((upstream && (upstream.trace_id || upstream.traceId)) || (runPayload && (runPayload.trace_id || runPayload.traceId)) || '');
pageAiSetRunStatus('running', runId);
pageAiSetRunTargetSnapshot(Object.assign({}, runTargetSnapshot, {
runId: runId,
sessionId: pageUiState.pageAiActiveSessionId,
traceId: runTraceId
}));
renderPageAiControls();
var eventResponse = await fetch('/api/hermes/client/events/' + encodeURIComponent(runId), {
headers: { 'accept': 'text/event-stream' }
});
if (!eventResponse.ok) {
var eventError = await eventResponse.json().catch(function(){ return null; });
throw new Error(pageAiErrorMessage(eventError, 'hermes_events_failed_' + eventResponse.status));
}
var assistantText = '';
var autoCitations = [];
await streamPageAiResponse(eventResponse, function(eventName, payloadText) {
pageAiTrackStreamingRunEvent(runId, eventName, payloadText);
var streamPayload = null;
try {
streamPayload = JSON.parse(payloadText || 'null');
} catch (_) {}
if (streamPayload && (streamPayload.source === 'adapter_replay' || streamPayload.replay === true)) {
document.documentElement.setAttribute('data-mnote-page-ai-adapter-replay-seen', 'true');
return;
}
if (eventName === 'message.delta') {
if (pageUiState.pageAiStoppedRunIds[runId]) return;
assistantText = pageAiAppendStreamingAssistantDelta(runId, pageAiDecodeDeltaText(payloadText));
}
if (eventName === 'thought.delta') {
try {
var thoughtPayload = JSON.parse(payloadText || 'null');
var thoughtText = String((thoughtPayload && (thoughtPayload.delta || thoughtPayload.text)) || '');
if (thoughtText) {
var msgs = pageUiState.pageAiMessages;
var lastThought = msgs.length > 0 && msgs[msgs.length - 1].kind === 'thought' ? msgs[msgs.length - 1] : null;
if (lastThought) {
lastThought.content += thoughtText;
} else {
msgs.push({ role: 'assistant', kind: 'thought', content: thoughtText });
}
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
renderPageAiConversation();
}
} catch (_) {}
}
if (eventName === 'usage.updated') {
try {
var usagePayload = JSON.parse(payloadText || 'null') || {};
var sessionForUsage = pageAiCurrentSession();
if (sessionForUsage) {
sessionForUsage.usage = {
source: 'usage_update',
used: Number(usagePayload.used ?? usagePayload.contextUsed ?? 0),
size: Number(usagePayload.size ?? usagePayload.contextSize ?? 0)
};
pageAiPersistSessions();
}
} catch (_) {}
renderPageAiControls();
}
if (eventName === 'permission.requested' || eventName === 'permission.denied' || eventName === 'permission.allowed') {
pageAiApplyPermissionEvent(eventName, payloadText);
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
renderPageAiConversation();
renderPageAiControls();
}
if (eventName === 'run.completed') {
try {
var completed = JSON.parse(payloadText || 'null');
if (completed && completed.output) assistantText = String(completed.output || '');
if (completed && completed.usage) {
var completedSession = pageAiCurrentSession();
if (completedSession) completedSession.usage = completed.usage;
}
var agentAudit = completed && completed.agentAudit && typeof completed.agentAudit === 'object' ? completed.agentAudit : null;
var agentRunReceipt = agentAudit && agentAudit.agentRunReceipt && typeof agentAudit.agentRunReceipt === 'object'
? agentAudit.agentRunReceipt
: null;
var changedFiles = pageAiNormalizeArray(agentAudit && agentAudit.changedFiles).map(function(file) {
if (!file || typeof file !== 'object') return file;
return Object.assign({
actorId: String(agentAudit && agentAudit.actorId || ''),
actorType: String(agentAudit && agentAudit.actorType || ''),
agentKind: String(agentAudit && agentAudit.agentKind || ''),
runId: runId
}, file);
});
if (changedFiles.length) {
pageUiState.pageAiMessages.push({
role: 'tool',
content: 'agent.changed_files',
toolCallId: runId + ':agent.changed_files',
toolName: 'agent.changed_files',
toolKind: 'audit',
status: 'completed',
argsSummary: [agentAudit.rootUri, agentAudit.actorId, agentAudit.agentKind].map(function(value) {
return String(value || '').trim();
}).filter(Boolean).join(' · '),
resultSummary: String(agentAudit.diffSummary || changedFiles.length + ' changed file(s)'),
changedFiles: changedFiles,
traceId: runTraceId,
auditId: String(agentAudit.eventId || '')
});
}
if (agentRunReceipt || changedFiles.length) {
try {
pageAiDispatchReceiptRefresh(agentRunReceipt, changedFiles, agentAudit, runId, runTraceId);
} catch (_) {}
}
} catch (_) {}
pageAiSetRunStatus('completed', runId);
}
if (eventName === 'run.failed') {
try {
var failed = JSON.parse(payloadText || 'null');
assistantText = String((failed && (failed.message || failed.code || failed.error)) || 'AI run failed');
} catch (_) {}
pageAiSetRunStatus('failed', runId);
}
if (eventName === 'run.aborted' || eventName === 'run.cancelled' || eventName === 'run.canceled') {
pageUiState.pageAiStoppedRunIds[runId] = true;
pageAiStopStreamingAssistantMessage(runId);
pageAiSetRunStatus('aborted', runId);
}
if (eventName === 'session.info.updated') {
try {
var infoPayload = JSON.parse(payloadText || 'null') || {};
var newTitle = String(infoPayload.title || '').trim();
var acpSessionId = String(infoPayload.acpSessionId || infoPayload.acp_session_id || '').trim();
var sessionForInfo = pageAiCurrentSession();
if (acpSessionId && sessionForInfo) {
sessionForInfo.acpSessionId = acpSessionId;
sessionForInfo.updatedAt = Date.now();
pageAiPersistSessions();
}
if (newTitle) {
var sessionForTitle = sessionForInfo || pageAiCurrentSession();
if (sessionForTitle) {
sessionForTitle.title = newTitle;
sessionForTitle.updatedAt = Date.now();
pageAiPersistSessions();
renderPageAiControls();
}
}
} catch (_) {}
}
if (eventName === 'plan.updated') {
try {
var planPayload = JSON.parse(payloadText || 'null') || {};
var planEntries = Array.isArray(planPayload.entries) ? planPayload.entries : [];
if (planEntries.length) {
var planMsgs = pageUiState.pageAiMessages;
var existingPlan = planMsgs.length > 0 && planMsgs[planMsgs.length - 1].kind === 'plan' ? planMsgs[planMsgs.length - 1] : null;
if (existingPlan) {
existingPlan.entries = planEntries;
existingPlan.updatedAt = Date.now();
} else {
planMsgs.push({ role: 'system', kind: 'plan', entries: planEntries, createdAt: Date.now(), updatedAt: Date.now() });
}
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
renderPageAiConversation();
}
} catch (_) {}
}
if (eventName === 'tool.started' || eventName === 'tool.completed' || eventName === 'tool.failed') {
var toolEventPayload = null;
try {
toolEventPayload = JSON.parse(payloadText || 'null');
} catch (_) {}
var toolItem = pageAiApplyToolEvent(eventName, payloadText, runId, runTraceId);
if (eventName === 'tool.completed') {
var completedCitations = pageAiCollectKnowledgeRagCitations(toolItem, toolEventPayload);
if (completedCitations.length) autoCitations = completedCitations;
}
pageAiSyncCurrentSessionMessages();
pageAiPersistSessions();
renderPageAiConversation();
pageAiSetRunStatus('tool_calling', runId);
renderPageAiControls();
}
});
if (!pageUiState.pageAiStoppedRunIds[runId]) {
pageAiFinishStreamingAssistantMessage(runId, assistantText, prompt, autoCitations);
}
currentSession = pageAiCurrentSession();
if (currentSession) {
currentSession.messages = pageUiState.pageAiMessages.slice();
currentSession.updatedAt = Date.now();
}
pageAiPersistSessions();
} catch (error) {
pageAiSetRunStatus('failed');
pageUiState.pageAiMessages.push({
role: 'assistant',
content: 'AI 当前请求失败:' + (error instanceof Error ? error.message : String(error))
});
currentSession = pageAiCurrentSession();
if (currentSession) {
currentSession.messages = pageUiState.pageAiMessages.slice();
currentSession.updatedAt = Date.now();
}
pageAiPersistSessions();
} finally {
if (!allowQueue) pageUiState.pageAiBusy = false;
renderPageAiConversation();
renderPageAiControls();
}
}
function handlePageAiClick(event, helpers) {
var closestAction = helpers && helpers.closestAction;
if (typeof closestAction !== 'function') return false;
var pageAiCitationLink = closestAction(event.target, 'a[data-page-ai-citation-link="true"]');
if (pageAiCitationLink && !(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) {
var href = pageAiCitationLink.getAttribute('href') || '';
if (pageAiOpenCitationUrl(href)) {
event.preventDefault();
return true;
}
}
var pageAiClose = closestAction(event.target, '[data-page-ai-action="close"]');
if (pageAiClose) {
event.preventDefault();
closePageAiDrawer();
return true;
}
var pageAiSettings = closestAction(event.target, '[data-page-ai-action="open-hermes-settings"]');
if (pageAiSettings) {
event.preventDefault();
pageAiOpenHermesSettings();
return true;
}
var pageAiStop = closestAction(event.target, '[data-page-ai-action="stop-run"]');
if (pageAiStop) {
event.preventDefault();
void pageAiStopRun();
return true;
}
var pageAiRotate = closestAction(event.target, '[data-page-ai-action="rotate"]');
if (pageAiRotate) {
event.preventDefault();
pageUiState.pageAiSuggestionIndex += 1;
renderPageAiSuggestions();
return true;
}
var pageAiIntent = closestAction(event.target, '[data-page-ai-intent]');
if (pageAiIntent) {
event.preventDefault();
var intentName = pageAiIntent.getAttribute('data-page-ai-intent') || '';
if (intentName === 'create-summary') void sendPageAiMessage('请通过 Hermes 调用 mnote.artifact.create_summary,为当前页面创建或更新 AI Summary。');
if (intentName === 'create-ai-note') void sendPageAiMessage('请通过 Hermes 调用 mnote.artifact.create_ai_note,基于当前页面创建一篇新的 AI Note。');
return true;
}
var pageAiTab = closestAction(event.target, '[data-page-ai-tab]');
if (pageAiTab) {
event.preventDefault();
pageUiState.pageAiPage = pageAiTab.getAttribute('data-page-ai-tab') || 'chat';
if (pageUiState.pageAiPage === 'runtime') void pageAiLoadGatewayHealth();
if (pageUiState.pageAiPage === 'skills') void pageAiLoadSkills();
renderPageAiControls();
renderPageAiConversation();
return true;
}
var pageAiProvider = closestAction(event.target, '[data-page-ai-provider]');
if (pageAiProvider) {
event.preventDefault();
pageUiState.pageAiProvider = pageAiProvider.getAttribute('data-page-ai-provider') || 'hermes';
renderPageAiProviderButtons();
return true;
}
var pageAiAgent = closestAction(event.target, '[data-page-ai-agent-id]');
if (pageAiAgent) {
event.preventDefault();
var nextAgentId = pageAiAgent.getAttribute('data-page-ai-agent-id') || 'reasonix';
var nextProfileId = pageAiAgent.getAttribute('data-page-ai-profile-id') || '';
pageAiSetAgentId(nextAgentId);
if (nextProfileId) {
pageUiState.pageAiAgentPopoverOpen = false;
void pageAiSwitchProfile(nextProfileId);
renderPageAiControls();
}
return true;
}
var pageAiAgentButton = closestAction(event.target, '[data-page-ai-agent-button]');
if (pageAiAgentButton) {
event.preventDefault();
pageAiSetAgentPopoverOpen(pageAiAgentButton.getAttribute('aria-expanded') !== 'true');
return true;
}
var pageAiContextButton = closestAction(event.target, '[data-page-ai-context-button]');
if (pageAiContextButton) {
event.preventDefault();
pageAiSetContextPopoverOpen(pageAiContextButton.getAttribute('aria-expanded') !== 'true');
return true;
}
var pageAiTargetButton = closestAction(event.target, '[data-page-ai-target-button]');
if (pageAiTargetButton) {
event.preventDefault();
pageAiSetTargetPopoverOpen(pageAiTargetButton.getAttribute('aria-expanded') !== 'true');
return true;
}
var pageAiAction = closestAction(event.target, '[data-page-ai-action]');
if (pageAiAction) {
event.preventDefault();
var action = pageAiAction.getAttribute('data-page-ai-action') || '';
if (action === 'close-agent-popover') pageAiSetAgentPopoverOpen(false);
if (action === 'close-context-popover') pageAiSetContextPopoverOpen(false);
if (action === 'close-target-popover') pageAiSetTargetPopoverOpen(false);
if (action === 'new-session') {
pageUiState.pageAiPage = 'chat';
pageAiStartNewSession();
}
if (action === 'history') {
pageAiLoadSessions();
pageUiState.pageAiPage = pageUiState.pageAiPage === 'history' ? 'chat' : 'history';
renderPageAiControls();
renderPageAiConversation();
if (pageUiState.pageAiPage === 'history') {
void pageAiLoadBackendSessions().catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
}
}
if (action === 'send') {
var input = ensurePageAiDrawer().querySelector('[data-page-ai-input]');
if (input instanceof HTMLTextAreaElement) {
var message = input.value;
input.value = '';
void sendPageAiMessage(message);
}
}
if (action === 'cancel-queued-run') {
void pageAiCancelQueuedRun(pageAiAction.getAttribute('data-page-ai-queue-id'));
}
return true;
}
var pageAiTargetOption = closestAction(event.target, '[data-page-ai-target-option]');
if (pageAiTargetOption) {
event.preventDefault();
pageAiSelectTarget(pageAiTargetOption.getAttribute('data-page-ai-target-option') || '');
return true;
}
var pageAiContextRef = closestAction(event.target, '[data-page-ai-context-ref]');
if (pageAiContextRef) {
event.preventDefault();
pageAiToggleContextRef(pageAiContextRef.getAttribute('data-page-ai-context-ref') || '');
return true;
}
var pageAiMemorySave = closestAction(event.target, '[data-page-ai-memory-save]');
if (pageAiMemorySave) {
event.preventDefault();
void pageAiSaveProfileMemory(pageAiMemorySave.getAttribute('data-page-ai-memory-save') || '');
return true;
}
var pageAiSkillToggle = closestAction(event.target, '[data-page-ai-skill-toggle]');
if (pageAiSkillToggle) {
event.preventDefault();
void pageAiToggleSkill(
pageAiSkillToggle.getAttribute('data-page-ai-skill-toggle') || '',
pageAiSkillToggle.getAttribute('aria-pressed') !== 'true',
pageAiSkillToggle.getAttribute('data-page-ai-skill-group') || '',
pageAiSkillToggle.getAttribute('data-page-ai-skill-profile') || ''
);
return true;
}
var pageAiSkillGroupToggle = closestAction(event.target, '[data-page-ai-skill-group-toggle]');
if (pageAiSkillGroupToggle) {
event.preventDefault();
pageAiToggleSkillGroup(pageAiSkillGroupToggle.getAttribute('data-page-ai-skill-group-toggle') || '');
return true;
}
var pageAiToolToggle = closestAction(event.target, '[data-page-ai-tool-toggle]');
if (pageAiToolToggle) {
event.preventDefault();
void pageAiToggleTool(pageAiToolToggle.getAttribute('data-page-ai-tool-toggle') || '', pageAiToolToggle.getAttribute('aria-pressed') !== 'true');
return true;
}
var pageAiSessionSelect = closestAction(event.target, '[data-page-ai-session-select]');
if (pageAiSessionSelect) {
event.preventDefault();
pageAiToggleSessionSelection(
pageAiSessionSelect.getAttribute('data-page-ai-session-select') || '',
pageAiSessionSelect.getAttribute('aria-checked') !== 'true'
);
return true;
}
var pageAiClearSelectedSessions = closestAction(event.target, '[data-page-ai-session-clear-selection]');
if (pageAiClearSelectedSessions) {
event.preventDefault();
pageAiClearSessionSelection();
return true;
}
var pageAiDeleteSelectedSessions = closestAction(event.target, '[data-page-ai-session-delete-selected]');
if (pageAiDeleteSelectedSessions) {
event.preventDefault();
void pageAiDeleteSelectedBackendSessions().catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
return true;
}
var pageAiSessionResume = closestAction(event.target, '[data-page-ai-session-resume]');
if (pageAiSessionResume) {
event.preventDefault();
void pageAiResumeBackendSession(pageAiSessionResume.getAttribute('data-page-ai-session-resume') || '').catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
return true;
}
var pageAiSessionRename = closestAction(event.target, '[data-page-ai-session-rename]');
if (pageAiSessionRename) {
event.preventDefault();
void pageAiRenameBackendSession(pageAiSessionRename.getAttribute('data-page-ai-session-rename') || '').catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
return true;
}
var pageAiSessionExport = closestAction(event.target, '[data-page-ai-session-export]');
if (pageAiSessionExport) {
event.preventDefault();
void pageAiExportBackendSession(pageAiSessionExport.getAttribute('data-page-ai-session-export') || '').catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
return true;
}
var pageAiSessionDelete = closestAction(event.target, '[data-page-ai-session-delete]');
if (pageAiSessionDelete) {
event.preventDefault();
void pageAiDeleteBackendSession(pageAiSessionDelete.getAttribute('data-page-ai-session-delete') || '').catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
return true;
}
var pageAiPermissionAction = closestAction(event.target, '[data-page-ai-permission-action]');
if (pageAiPermissionAction) {
event.preventDefault();
pageAiResolvePermission(pageAiPermissionAction.getAttribute('data-page-ai-permission-id') || '', pageAiPermissionAction.getAttribute('data-page-ai-permission-action') || 'deny');
return true;
}
var pageAiOpenLocationAction = closestAction(event.target, '[data-page-ai-open-location]');
if (pageAiOpenLocationAction) {
event.preventDefault();
var loc = String(pageAiOpenLocationAction.getAttribute('data-page-ai-open-location') || '').trim();
if (loc) pageAiOpenLocation(loc);
return true;
}
var pageAiSession = closestAction(event.target, '[data-page-ai-session]');
if (pageAiSession) {
event.preventDefault();
pageAiSetActiveSession(pageAiSession.getAttribute('data-page-ai-session') || '');
return true;
}
var pageAiSuggestion = closestAction(event.target, '[data-page-ai-suggestion]');
if (pageAiSuggestion) {
event.preventDefault();
var text = pageAiSuggestion.getAttribute('data-page-ai-suggestion') || '';
var inputNode = ensurePageAiDrawer().querySelector('[data-page-ai-input]');
if (inputNode instanceof HTMLTextAreaElement) {
inputNode.value = text;
inputNode.focus();
}
return true;
}
return false;
}
function handlePageAiKeyDown(event, helpers) {
var closestAction = helpers && helpers.closestAction;
if (typeof closestAction !== 'function') return false;
if (event.key === 'Enter' && !event.shiftKey) {
var aiInput = closestAction(event.target, '[data-page-ai-input]');
if (aiInput instanceof HTMLTextAreaElement) {
event.preventDefault();
var text = aiInput.value;
aiInput.value = '';
void sendPageAiMessage(text);
return true;
}
}
return false;
}
function handlePageAiInput(event, helpers) {
var closestAction = helpers && helpers.closestAction;
if (typeof closestAction !== 'function') return false;
var skillSearch = closestAction(event.target, '[data-page-ai-skill-search]');
if (skillSearch instanceof HTMLInputElement) {
pageUiState.pageAiSkillQuery = skillSearch.value;
renderPageAiControls();
return true;
}
var sessionSearch = closestAction(event.target, '[data-page-ai-session-search]');
if (sessionSearch instanceof HTMLInputElement) {
var sessionQuery = sessionSearch.value;
window.clearTimeout(pageUiState.pageAiSessionSearchTimer || 0);
pageUiState.pageAiSessionSearchTimer = window.setTimeout(function() {
void pageAiSearchBackendSessions(sessionQuery).catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
}, 200);
return true;
}
var memoryEditor = closestAction(event.target, '[data-page-ai-memory-editor]');
if (memoryEditor instanceof HTMLTextAreaElement) {
var section = memoryEditor.getAttribute('data-page-ai-memory-editor') || '';
if (['memory', 'user', 'soul'].indexOf(section) >= 0) pageUiState.pageAiProfileMemoryDrafts[section] = memoryEditor.value;
return true;
}
return false;
}
function handlePageAiChange(event, helpers) {
var closestAction = helpers && helpers.closestAction;
if (typeof closestAction !== 'function') return false;
var pageAiDescriptorField = closestAction(event.target, '[data-page-ai-descriptor-field]');
if (pageAiDescriptorField instanceof HTMLInputElement || pageAiDescriptorField instanceof HTMLSelectElement) {
var key = pageAiDescriptorField.getAttribute('data-page-ai-descriptor-field') || '';
var kind = pageAiDescriptorField.getAttribute('data-page-ai-descriptor-kind') || '';
var value = kind === 'boolean' && pageAiDescriptorField instanceof HTMLInputElement
? pageAiDescriptorField.checked
: pageAiDescriptorField.value;
pageAiSetDescriptorFieldValue(key, value);
return true;
}
var pageAiAcpRuntimeSelect = closestAction(event.target, '[data-page-ai-acp-runtime]');
if (pageAiAcpRuntimeSelect instanceof HTMLSelectElement) {
var next = String(pageAiAcpRuntimeSelect.value || 'reasonix').trim() || 'reasonix';
pageUiState.pageAiAcpRuntime = next;
pageUiState.pageAiSkills = { categories: [], archived: [] };
pageUiState.pageAiSkillError = '';
pageAiPersistSessions();
void pageAiLoadProfiles();
if (next !== 'reasonix') void pageAiLoadProfileMemory();
void pageAiLoadSkills();
void pageAiLoadBackendSessions().catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
});
renderPageAiControls();
renderPageAiProviderButtons();
return true;
}
var pageAiProfileSelect = closestAction(event.target, '[data-page-ai-profile-select]');
if (pageAiProfileSelect instanceof HTMLSelectElement) {
void pageAiSwitchProfile(pageAiProfileSelect.value);
return true;
}
var pageAiSkillSourceSelect = closestAction(event.target, '[data-page-ai-skill-source-select]');
if (pageAiSkillSourceSelect instanceof HTMLSelectElement) {
pageAiSetSkillSource(pageAiSkillSourceSelect.value);
return true;
}
var pageAiSessionAgentFilter = closestAction(event.target, '[data-page-ai-session-agent-filter]');
if (pageAiSessionAgentFilter instanceof HTMLSelectElement) {
pageUiState.pageAiSessionAgentFilter = String(pageAiSessionAgentFilter.value || 'all').trim() || 'all';
renderPageAiControls();
renderPageAiConversation();
return true;
}
var pageAiHideHermesBuiltin = closestAction(event.target, '[data-page-ai-hide-hermes-builtin]');
if (pageAiHideHermesBuiltin instanceof HTMLInputElement) {
pageAiSetHideHermesBuiltinSkills(pageAiHideHermesBuiltin.checked);
return true;
}
var pageAiReasonixMemory = closestAction(event.target, '[data-page-ai-reasonix-memory]');
if (pageAiReasonixMemory instanceof HTMLInputElement) {
pageAiSetReasonixMemoryEnabled(pageAiReasonixMemory.checked);
return true;
}
var pageAiContextSelect = closestAction(event.target, '[data-page-ai-context-scope]');
if (pageAiContextSelect instanceof HTMLSelectElement) {
pageAiSetContextScope(pageAiContextSelect.value);
renderPageAiControls();
return true;
}
return false;
}
function installPageAiDelegates() {
if (pageAiDelegatesInstalled) return;
pageAiDelegatesInstalled = true;
var helpers = { closestAction: closestAction };
document.addEventListener('click', function(event) {
handlePageAiClick(event, helpers);
});
document.addEventListener('pointerdown', function(event) {
handlePageAiPointerDown(event, helpers);
});
document.addEventListener('keydown', function(event) {
handlePageAiKeyDown(event, helpers);
});
document.addEventListener('input', function(event) {
handlePageAiInput(event, helpers);
});
document.addEventListener('change', function(event) {
handlePageAiChange(event, helpers);
});
document.addEventListener('visibilitychange', function() {
if (document.visibilityState !== 'visible' || !pageUiState.pageAiOpen) return;
void pageAiCheckAndResumeActiveRun().catch(function(error) {
pageUiState.pageAiSessionError = error instanceof Error ? error.message : String(error);
renderPageAiControls();
});
});
}
return {
ensurePageAiStateFacade: (...args) => ensurePageAiStateFacade(...args),
installPageAiDelegates: (...args) => installPageAiDelegates(...args),
handlePageAiClick: (...args) => handlePageAiClick(...args),
handlePageAiKeyDown: (...args) => handlePageAiKeyDown(...args),
handlePageAiInput: (...args) => handlePageAiInput(...args),
handlePageAiChange: (...args) => handlePageAiChange(...args),
openPageAiDrawer: (...args) => openPageAiDrawer(...args),
closePageAiDrawer: (...args) => closePageAiDrawer(...args),
isPageAiDrawerOpen: (...args) => isPageAiDrawerOpen(...args),
ensurePageAiDrawer: (...args) => ensurePageAiDrawer(...args),
sendPageAiMessage: (...args) => sendPageAiMessage(...args),
pageAiOpenHermesSettings: (...args) => pageAiOpenHermesSettings(...args),
pageAiStopRun: (...args) => pageAiStopRun(...args),
pageAiLoadGatewayHealth: (...args) => pageAiLoadGatewayHealth(...args),
renderPageAiControls: (...args) => renderPageAiControls(...args),
renderPageAiConversation: (...args) => renderPageAiConversation(...args),
renderPageAiProviderButtons: (...args) => renderPageAiProviderButtons(...args),
renderPageAiSuggestions: (...args) => renderPageAiSuggestions(...args),
pageAiSaveProfileMemory: (...args) => pageAiSaveProfileMemory(...args),
pageAiToggleSkill: (...args) => pageAiToggleSkill(...args),
pageAiToggleTool: (...args) => pageAiToggleTool(...args),
pageAiResumeBackendSession: (...args) => pageAiResumeBackendSession(...args),
pageAiRenameBackendSession: (...args) => pageAiRenameBackendSession(...args),
pageAiExportBackendSession: (...args) => pageAiExportBackendSession(...args),
pageAiDeleteBackendSession: (...args) => pageAiDeleteBackendSession(...args),
pageAiResolvePermission: (...args) => pageAiResolvePermission(...args),
pageAiOpenLocation: (...args) => pageAiOpenLocation(...args),
pageAiSetActiveSession: (...args) => pageAiSetActiveSession(...args),
pageAiStartNewSession: (...args) => pageAiStartNewSession(...args),
pageAiLoadSessions: (...args) => pageAiLoadSessions(...args),
pageAiLoadBackendSessions: (...args) => pageAiLoadBackendSessions(...args),
pageAiCancelQueuedRun: (...args) => pageAiCancelQueuedRun(...args),
pageAiSearchBackendSessions: (...args) => pageAiSearchBackendSessions(...args),
pageAiSetTargetPopoverOpen: (...args) => pageAiSetTargetPopoverOpen(...args),
pageAiSelectTarget: (...args) => pageAiSelectTarget(...args),
pageAiPersistSessions: (...args) => pageAiPersistSessions(...args),
pageAiLoadProfiles: (...args) => pageAiLoadProfiles(...args),
pageAiLoadProfileMemory: (...args) => pageAiLoadProfileMemory(...args),
pageAiLoadSkills: (...args) => pageAiLoadSkills(...args),
pageAiSwitchProfile: (...args) => pageAiSwitchProfile(...args),
pageAiToggleSkillGroup: (...args) => pageAiToggleSkillGroup(...args),
pageAiSetReasonixMemoryEnabled: (...args) => pageAiSetReasonixMemoryEnabled(...args),
pageAiSetHideHermesBuiltinSkills: (...args) => pageAiSetHideHermesBuiltinSkills(...args),
pageAiSetSkillSource: (...args) => pageAiSetSkillSource(...args),
pageAiSetContextScope: (...args) => pageAiSetContextScope(...args),
pageAiSetAgentId: (...args) => pageAiSetAgentId(...args),
pageAiToggleContextRef: (...args) => pageAiToggleContextRef(...args),
pageAiSetContextPopoverOpen: (...args) => pageAiSetContextPopoverOpen(...args),
pageAiSetAgentPopoverOpen: (...args) => pageAiSetAgentPopoverOpen(...args),
pageAiLoadAllowedRoots: (...args) => pageAiLoadAllowedRoots(...args),
updatePageAiTriggerState: (...args) => updatePageAiTriggerState(...args)
};
}