feat: Page AI Reasonix desktop session alignment, settings IA cleanup, knowledge RAG hardening
- ACP client/session manager: Reasonix desktop live session context - Hermes tools: knowledge_rag tool manifest and skill updates - Browser runtime: sidebar page AI permission/profile/render/session/tree modules - Routes: hermes_client, hermes_tools, knowledge_rag, web_shell - Scripts: reasonix ACP wrapper, LightRAG MCP, smoke tasks 159/558/559/561/562 - Skills: mnote-knowledge-rag and mnote-lightrag-bridge SKILL.md updates
This commit is contained in:
@@ -39,6 +39,9 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
pageAiSessionAgentFilterOptions,
|
||||
pageAiSessionAgentLabel,
|
||||
pageAiSessionAgentFilterValue,
|
||||
pageAiSessionStatusFilterOptions,
|
||||
pageAiSessionStatusFilterValue,
|
||||
pageAiSessionStatusLabel,
|
||||
pageAiSessionPreviewText,
|
||||
pageAiSessionStorageLabel,
|
||||
pageAiSessionSelected,
|
||||
@@ -192,6 +195,50 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'</label>';
|
||||
}
|
||||
|
||||
function pageAiReasonixQuickControlLabel(key, fallback) {
|
||||
if (key === 'ai.agent.reasonix.model_id') return '模型';
|
||||
if (key === 'ai.agent.reasonix.approval_mode') return '审批';
|
||||
if (key === 'ai.agent.reasonix.plan_mode') return 'Plan';
|
||||
return fallback || key;
|
||||
}
|
||||
|
||||
function pageAiRenderReasonixQuickControl(field) {
|
||||
var key = String(field && field.key || '').trim();
|
||||
if (!key || field.secret === true) return '';
|
||||
var value = pageAiDescriptorFieldValue(field);
|
||||
var options = pageAiDescriptorFieldOptions(field);
|
||||
if (!options.length) return '';
|
||||
return '' +
|
||||
'<label class="wolai-page-ai-reasonix-control" data-page-ai-reasonix-control-row="' + escapeHtml(key) + '">' +
|
||||
'<span>' + escapeHtml(pageAiReasonixQuickControlLabel(key, field.label)) + '</span>' +
|
||||
'<select data-page-ai-descriptor-field="' + escapeHtml(key) + '" data-page-ai-descriptor-kind="select" data-page-ai-reasonix-quick-control="' + escapeHtml(key) + '">' +
|
||||
options.map(function(option) {
|
||||
return '<option value="' + escapeHtml(option.value) + '"' + (String(value) === String(option.value) ? ' selected' : '') + '>' + escapeHtml(option.label) + '</option>';
|
||||
}).join('') +
|
||||
'</select>' +
|
||||
'</label>';
|
||||
}
|
||||
|
||||
function pageAiReasonixQuickControlsHtml() {
|
||||
if (pageAiCurrentAgentId() !== 'reasonix') return '';
|
||||
var descriptor = pageAiAgentDescriptor('reasonix') || pageAiAgentRecord('reasonix');
|
||||
var wanted = {
|
||||
'ai.agent.reasonix.model_id': true,
|
||||
'ai.agent.reasonix.approval_mode': true,
|
||||
'ai.agent.reasonix.plan_mode': true
|
||||
};
|
||||
var fields = pageAiNormalizeArray(descriptor && descriptor.fields)
|
||||
.filter(function(field) { return wanted[String(field && field.key || '').trim()] === true; })
|
||||
.map(pageAiRenderReasonixQuickControl)
|
||||
.filter(Boolean)
|
||||
.join('');
|
||||
if (!fields) return '';
|
||||
return '' +
|
||||
'<div class="wolai-page-ai-reasonix-controls" data-page-ai-reasonix-quick-controls>' +
|
||||
fields +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function pageAiRenderAgentDescriptorCard(agentId, fallbackTitle) {
|
||||
var descriptor = pageAiAgentDescriptor(agentId) || pageAiAgentRecord(agentId);
|
||||
var title = String(descriptor && (descriptor.displayName || descriptor.label) || fallbackTitle || agentId).trim();
|
||||
@@ -210,11 +257,27 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
|
||||
function pageAiCurrentModelLabel() {
|
||||
var profile = pageAiCurrentProfileRecord();
|
||||
var prefs = pageUiState.pageAiSkillPreferences || {};
|
||||
var toolModel = pageAiMnoteToolModel();
|
||||
var reasonixModel = String(prefs['ai.agent.reasonix.model_id'] || '').trim();
|
||||
var approvalMode = String(prefs['ai.agent.reasonix.approval_mode'] || 'ask').trim() || 'ask';
|
||||
var planMode = String(prefs['ai.agent.reasonix.plan_mode'] || 'manual').trim() || 'manual';
|
||||
var approvalLabel = {
|
||||
ask: '审批:询问',
|
||||
allow: '审批:自动允许',
|
||||
deny: '审批:自动拒绝'
|
||||
}[approvalMode] || ('审批:' + approvalMode);
|
||||
var planLabel = {
|
||||
manual: '计划:手动',
|
||||
auto: '计划:自动'
|
||||
}[planMode] || ('计划:' + planMode);
|
||||
if (!profile) return 'tool: ' + toolModel;
|
||||
var model = String(profile.model || '').trim();
|
||||
var gateway = String(profile.gateway || '').trim();
|
||||
var profileLabel = [model, gateway].filter(Boolean).join(' · ') || '由 Hermes 决定';
|
||||
if (pageAiCurrentAgentId() === 'reasonix') {
|
||||
return ['Reasonix', reasonixModel || toolModel, approvalLabel, planLabel].filter(Boolean).join(' · ');
|
||||
}
|
||||
return 'tool: ' + toolModel + ' · profile: ' + profileLabel;
|
||||
}
|
||||
|
||||
@@ -283,6 +346,88 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
});
|
||||
}
|
||||
|
||||
function pageAiRuntimeStatusValue(path, fallback) {
|
||||
var node = pageUiState.pageAiRuntimeStatus || {};
|
||||
String(path || '').split('.').forEach(function(part) {
|
||||
if (!part || node == null || typeof node !== 'object') return;
|
||||
node = node[part];
|
||||
});
|
||||
if (node == null || node === '') return fallback || '';
|
||||
return String(node);
|
||||
}
|
||||
|
||||
function pageAiRuntimeStatusLabel() {
|
||||
var status = pageUiState.pageAiRuntimeStatus || {};
|
||||
var runtime = String(status.runtime || pageUiState.pageAiAcpRuntime || 'reasonix');
|
||||
var mode = String(status.mode || 'new_session');
|
||||
if (runtime === 'reasonix') return pageAiCurrentModelLabel() + ' · ' + mode.replace(/_/g, '-');
|
||||
return runtime + ' · ' + mode.replace(/_/g, '-');
|
||||
}
|
||||
|
||||
function pageAiRuntimeDetailHtml() {
|
||||
var status = pageUiState.pageAiRuntimeStatus || {};
|
||||
var acp = status.acp && typeof status.acp === 'object' ? status.acp : {};
|
||||
var roots = status.roots && typeof status.roots === 'object' ? status.roots : {};
|
||||
var tools = status.tools && typeof status.tools === 'object' ? status.tools : {};
|
||||
var mcp = status.mcp && typeof status.mcp === 'object' ? status.mcp : {};
|
||||
var queue = status.session && status.session.queue && typeof status.session.queue === 'object' ? status.session.queue : {};
|
||||
var logs = status.logs && Array.isArray(status.logs.items) ? status.logs.items : [];
|
||||
var rows = [
|
||||
['runtime', pageAiRuntimeStatusLabel()],
|
||||
['session', String(status.mnoteSessionId || pageUiState.pageAiActiveSessionId || '无')],
|
||||
['acpSessionId', String(acp.acpSessionId || '无')],
|
||||
['load/replay', String(acp.loadStatus || 'not_applicable') + ' / replay=' + String(acp.replaySeen === true)],
|
||||
['live binding', acp.liveBinding && typeof acp.liveBinding === 'object' ? String(acp.liveBinding.status || 'unknown') : '无'],
|
||||
['roots', 'write=' + String(roots.write || 0) + ' readOnly=' + String(roots.readOnly || 0)],
|
||||
['MCP/tools', String(mcp.status || 'unknown') + ' · enabled=' + String(tools.enabled || 0) + ' disabled=' + String(tools.disabled || 0)],
|
||||
['queue', String(queue.queuedCount || pageUiState.pageAiQueueLength || 0)],
|
||||
['jobs', pageAiRuntimeStatusValue('jobs.running', '0')]
|
||||
];
|
||||
var html = rows.map(function(row) {
|
||||
return '<div class="wolai-page-ai-tool-row"><span class="wolai-page-ai-tool-name">' + escapeHtml(row[0]) + '</span><span class="wolai-page-ai-tool-meta">' + escapeHtml(row[1]) + '</span></div>';
|
||||
}).join('');
|
||||
if (pageUiState.pageAiRuntimeStatusError) {
|
||||
html += '<div class="wolai-page-ai-inline-error">' + escapeHtml(pageUiState.pageAiRuntimeStatusError) + '</div>';
|
||||
}
|
||||
if (logs.length) {
|
||||
html += logs.slice(-4).map(function(item) {
|
||||
return '<div class="wolai-page-ai-tool-row"><span class="wolai-page-ai-tool-name">' + escapeHtml(String(item.kind || 'log')) + '</span><span class="wolai-page-ai-tool-meta">' + escapeHtml(String(item.seq || '')) + '</span></div>';
|
||||
}).join('');
|
||||
}
|
||||
return html || '<div class="wolai-page-ai-empty">Runtime status 尚未加载。</div>';
|
||||
}
|
||||
|
||||
function pageAiUsageDetailHtml() {
|
||||
var status = pageUiState.pageAiRuntimeStatus || {};
|
||||
var usage = status.usage && typeof status.usage === 'object' ? status.usage : {};
|
||||
var rows = [
|
||||
['last run', usage.lastRunTokens || usage.lastRunCost || 'unknown'],
|
||||
['session total', usage.sessionTokens || usage.sessionCost || 'unknown'],
|
||||
['cache', usage.cacheTokens || usage.cacheHit || 'unknown']
|
||||
];
|
||||
return rows.map(function(row) {
|
||||
return '<div class="wolai-page-ai-tool-row"><span class="wolai-page-ai-tool-name">' + escapeHtml(row[0]) + '</span><span class="wolai-page-ai-tool-meta">' + escapeHtml(String(row[1])) + '</span></div>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function pageAiSettingsTabsHtml(activeTab) {
|
||||
return [
|
||||
['agent', 'MNote'],
|
||||
['reasonix-settings', 'Reasonix'],
|
||||
['hermes-settings', 'Hermes']
|
||||
].map(function(tab) {
|
||||
var active = tab[0] === activeTab;
|
||||
return '<button type="button" class="wolai-page-ai-tab' + (active ? ' is-active' : '') + '" data-page-ai-tab="' + escapeHtml(tab[0]) + '" role="tab" aria-selected="' + (active ? 'true' : 'false') + '">' + escapeHtml(tab[1]) + '</button>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function pageAiStatusTabsHtml() {
|
||||
return '' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="chat" role="tab" aria-selected="false">聊天</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab is-active" data-page-ai-tab="status" role="tab" aria-selected="true">状态</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="agent" role="tab" aria-selected="false">设置</button>';
|
||||
}
|
||||
|
||||
function renderPageAiProviderButtons() {
|
||||
var drawer = ensurePageAiDrawer();
|
||||
var isAcp = pageUiState.pageAiAcpRuntime !== '';
|
||||
@@ -303,6 +448,8 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
var isAcp = pageUiState.pageAiAcpRuntime !== '';
|
||||
var activeAgentId = pageAiCurrentAgentId();
|
||||
var activeProfile = pageAiCurrentProfile();
|
||||
if (pageUiState.pageAiPage === 'runtime') pageUiState.pageAiPage = 'status';
|
||||
if (pageUiState.pageAiPage === 'chat-only-settings') pageUiState.pageAiPage = 'agent';
|
||||
drawer.setAttribute('data-page-ai-page', pageUiState.pageAiPage || 'chat');
|
||||
drawer.setAttribute('data-page-ai-active-agent-id', activeAgentId);
|
||||
drawer.setAttribute('data-mnote-acp-runtime', pageUiState.pageAiAcpRuntime || 'reasonix');
|
||||
@@ -478,16 +625,32 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
if (agentPanel instanceof HTMLElement) {
|
||||
agentPanel.innerHTML = '' +
|
||||
(pageUiState.pageAiAgentDescriptorError ? '<div class="wolai-page-ai-inline-error">' + escapeHtml(pageUiState.pageAiAgentDescriptorError) + '</div>' : '') +
|
||||
'<section class="wolai-page-ai-memory-card" data-page-ai-agent-descriptor-card="mnote">' +
|
||||
'<div class="wolai-page-ai-memory-head"><div><div class="wolai-page-ai-memory-title">MNote</div><div class="wolai-page-ai-memory-scope">上下文、权限、工具、会话历史和审计</div></div></div>' +
|
||||
'<div class="wolai-page-ai-tool-meta">这里配置 MNote 发送给 agent 的 envelope,不配置 Reasonix 或 Hermes 原生 runtime。</div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-memory-card">' +
|
||||
'<div class="wolai-page-ai-memory-head"><div class="wolai-page-ai-memory-title">授权区域</div><div class="wolai-page-ai-memory-scope">' + escapeHtml(pageAiBuildAllowedRoots().length ? 'SQLite directory_grants' : '需要授权') + '</div></div>' +
|
||||
'<div class="wolai-page-ai-memory-head"><div class="wolai-page-ai-memory-title">授权区域</div><div class="wolai-page-ai-memory-scope">SQLite directory_grants</div></div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-allowed-roots></div>' +
|
||||
'</section>' +
|
||||
pageAiRenderAgentDescriptorCard(activeAgentId, pageAiCurrentAgentSelectionLabel()) +
|
||||
'<section class="wolai-page-ai-memory-card">' +
|
||||
'<div class="wolai-page-ai-memory-head"><div class="wolai-page-ai-memory-title">默认上下文</div><div class="wolai-page-ai-memory-scope">ContextRefs</div></div>' +
|
||||
'<div class="wolai-page-ai-tool-meta">由 MNote 生成 run envelope,不写入 Reasonix/Hermes native memory。</div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-memory-card">' +
|
||||
'<div class="wolai-page-ai-memory-head"><div class="wolai-page-ai-memory-title">审计</div><div class="wolai-page-ai-memory-scope">changed files 默认摘要</div></div>' +
|
||||
'<div class="wolai-page-ai-memory-head"><div class="wolai-page-ai-memory-title">会话与审计</div><div class="wolai-page-ai-memory-scope">history / export / changed files</div></div>' +
|
||||
'<div class="wolai-page-ai-tool-meta">删除会话只删除 MNote history;外部 Hermes/provider 会话不会默认删除。</div>' +
|
||||
'</section>';
|
||||
var mnoteAllowedRootsNode = agentPanel.querySelector('[data-page-ai-allowed-roots]');
|
||||
if (mnoteAllowedRootsNode instanceof HTMLElement) {
|
||||
var mnoteAllowedRoots = pageAiBuildAllowedRoots();
|
||||
mnoteAllowedRootsNode.innerHTML = mnoteAllowedRoots.length
|
||||
? mnoteAllowedRoots.map(function(root) {
|
||||
var label = root.rootUri.replace(/^file:\/\//, '') || root.rootUri;
|
||||
return '<span class="wolai-page-ai-model-chip is-active" data-page-ai-allowed-root="' + escapeHtml(root.rootUri) + '" data-page-ai-allowed-root-permission="' + escapeHtml(root.permission) + '">' + escapeHtml(root.permission + ' · ' + label) + '</span>';
|
||||
}).join('')
|
||||
: '<span class="wolai-page-ai-tool-meta">' + escapeHtml(String(pageUiState.pageAiAllowedRootsError || '').trim() || '未选择授权区域') + '</span>';
|
||||
}
|
||||
}
|
||||
var profileSummary = drawer.querySelector('[data-page-ai-profile-summary]');
|
||||
if (profileSummary instanceof HTMLElement) profileSummary.textContent = '上下文可选';
|
||||
@@ -512,6 +675,40 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
var queueSuffix = pageUiState.pageAiQueueLength > 0 ? ' · 队列 ' + pageUiState.pageAiQueueLength : '';
|
||||
runStatus.textContent = pageAiRunStatusLabel(pageUiState.pageAiRunStatus) + queueSuffix;
|
||||
}
|
||||
drawer.querySelectorAll('[data-page-ai-runtime-badge]').forEach(function(runtimeBadge) {
|
||||
if (runtimeBadge instanceof HTMLElement) runtimeBadge.textContent = pageAiRuntimeStatusLabel();
|
||||
});
|
||||
var runtimeActive = drawer.querySelector('[data-page-ai-runtime-active-run]');
|
||||
if (runtimeActive instanceof HTMLElement) {
|
||||
var activeRunStatus = pageAiRuntimeStatusValue('activeRun.status', pageUiState.pageAiRunStatus || 'idle');
|
||||
runtimeActive.textContent = pageAiRunStatusLabel(activeRunStatus);
|
||||
}
|
||||
var runtimeAcp = drawer.querySelector('[data-page-ai-runtime-acp]');
|
||||
if (runtimeAcp instanceof HTMLElement) runtimeAcp.textContent = pageAiRuntimeStatusValue('acp.acpSessionId', '无 ACP session');
|
||||
var runtimeDetail = drawer.querySelector('[data-page-ai-runtime-detail]');
|
||||
if (runtimeDetail instanceof HTMLElement) runtimeDetail.innerHTML = pageAiRuntimeDetailHtml();
|
||||
var jobsList = drawer.querySelector('[data-page-ai-jobs-list]');
|
||||
if (jobsList instanceof HTMLElement) {
|
||||
var runtimeStatus = pageUiState.pageAiRuntimeStatus || {};
|
||||
var jobs = runtimeStatus.jobs && Array.isArray(runtimeStatus.jobs.items) ? runtimeStatus.jobs.items : [];
|
||||
jobsList.innerHTML = jobs.length
|
||||
? jobs.map(function(job) {
|
||||
return '<div class="wolai-page-ai-tool-row"><span class="wolai-page-ai-tool-name">' + escapeHtml(String(job.id || job.name || 'job')) + '</span><span class="wolai-page-ai-tool-meta">' + escapeHtml(String(job.status || 'running')) + '</span></div>';
|
||||
}).join('')
|
||||
: '<div class="wolai-page-ai-empty">暂无运行中的 job。</div>';
|
||||
}
|
||||
var logsList = drawer.querySelector('[data-page-ai-logs-list]');
|
||||
if (logsList instanceof HTMLElement) {
|
||||
var logStatus = pageUiState.pageAiRuntimeStatus || {};
|
||||
var logs = logStatus.logs && Array.isArray(logStatus.logs.items) ? logStatus.logs.items : [];
|
||||
logsList.innerHTML = logs.length
|
||||
? logs.slice(-8).map(function(item) {
|
||||
return '<div class="wolai-page-ai-tool-row"><span class="wolai-page-ai-tool-name">' + escapeHtml(String(item.kind || 'log')) + '</span><span class="wolai-page-ai-tool-meta">' + escapeHtml(String(item.seq || '')) + '</span></div>';
|
||||
}).join('')
|
||||
: '<div class="wolai-page-ai-empty">暂无 runtime logs。</div>';
|
||||
}
|
||||
var usageDetail = drawer.querySelector('[data-page-ai-usage-detail]');
|
||||
if (usageDetail instanceof HTMLElement) usageDetail.innerHTML = pageAiUsageDetailHtml();
|
||||
var stopButton = drawer.querySelector('[data-page-ai-action="stop-run"]');
|
||||
if (stopButton instanceof HTMLButtonElement) {
|
||||
var canStop = ['queued', 'running', 'tool_calling'].indexOf(pageUiState.pageAiRunStatus) >= 0 && pageUiState.pageAiCurrentRunId;
|
||||
@@ -530,9 +727,10 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
} else {
|
||||
queueList.innerHTML = pageUiState.pageAiQueuedItems.map(function(item, index) {
|
||||
var label = '队列 ' + (index + 1);
|
||||
var preview = String(item.preview || item.traceId || item.queueId || '').trim();
|
||||
return '' +
|
||||
'<div class="wolai-page-ai-tool-row" data-page-ai-queue-item="' + escapeHtml(item.queueId) + '">' +
|
||||
'<div><strong>' + escapeHtml(label) + '</strong><br /><span>' + escapeHtml(item.queueId) + '</span></div>' +
|
||||
'<div><strong>' + escapeHtml(label) + '</strong><br /><span>' + escapeHtml(preview || item.queueId) + '</span></div>' +
|
||||
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-action="cancel-queued-run" data-page-ai-queue-id="' + escapeHtml(item.queueId) + '">取消</button>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
@@ -547,7 +745,17 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
: '等待 AI session';
|
||||
}
|
||||
var modelNode = drawer.querySelector('[data-page-ai-model-status]');
|
||||
if (modelNode instanceof HTMLElement) modelNode.textContent = pageAiBuildAllowedRoots().length ? '已授权' : '需授权';
|
||||
if (modelNode instanceof HTMLElement) modelNode.textContent = pageAiCurrentModelLabel();
|
||||
var reasonixControls = drawer.querySelector('[data-page-ai-reasonix-quick-controls]');
|
||||
if (reasonixControls instanceof HTMLElement) {
|
||||
if (pageAiCurrentAgentId() === 'reasonix') {
|
||||
reasonixControls.innerHTML = pageAiReasonixQuickControlsHtml().replace(/^<div[^>]*>|<\/div>$/g, '');
|
||||
reasonixControls.hidden = false;
|
||||
} else {
|
||||
reasonixControls.innerHTML = '';
|
||||
reasonixControls.hidden = true;
|
||||
}
|
||||
}
|
||||
var scopeSelect = drawer.querySelector('[data-page-ai-context-scope]');
|
||||
if (scopeSelect instanceof HTMLSelectElement) scopeSelect.value = pageUiState.pageAiContextScope;
|
||||
var scopeLabel = drawer.querySelector('[data-page-ai-context-scope-label]');
|
||||
@@ -630,6 +838,20 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
sessionAgentFilter.value = activeFilter;
|
||||
pageUiState.pageAiSessionAgentFilter = activeFilter;
|
||||
}
|
||||
var sessionStatusFilter = drawer.querySelector('[data-page-ai-session-status-filter]');
|
||||
if (sessionStatusFilter instanceof HTMLSelectElement) {
|
||||
var historyRowsForStatusFilter = pageUiState.pageAiSessionSearchResults.length
|
||||
? pageUiState.pageAiSessionSearchResults
|
||||
: pageUiState.pageAiSessions;
|
||||
var statusOptions = pageAiSessionStatusFilterOptions(historyRowsForStatusFilter);
|
||||
var activeStatusFilter = String(pageUiState.pageAiSessionStatusFilter || 'all').trim() || 'all';
|
||||
if (!statusOptions.some(function(option) { return option.value === activeStatusFilter; })) activeStatusFilter = 'all';
|
||||
sessionStatusFilter.innerHTML = statusOptions.map(function(option) {
|
||||
return '<option value="' + escapeHtml(option.value) + '"' + (option.value === activeStatusFilter ? ' selected' : '') + '>' + escapeHtml(option.label) + '</option>';
|
||||
}).join('');
|
||||
sessionStatusFilter.value = activeStatusFilter;
|
||||
pageUiState.pageAiSessionStatusFilter = activeStatusFilter;
|
||||
}
|
||||
var skillSearch = drawer.querySelector('[data-page-ai-skill-search]');
|
||||
if (skillSearch instanceof HTMLInputElement && documentRef.activeElement !== skillSearch) {
|
||||
skillSearch.value = pageUiState.pageAiSkillQuery;
|
||||
@@ -754,7 +976,7 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
}
|
||||
if (gatewayDetail instanceof HTMLElement) {
|
||||
if (!gatewayHealth) {
|
||||
gatewayDetail.innerHTML = '<div class="wolai-page-ai-empty">打开高级后会检查 agent runtime 与当前 profile。</div>';
|
||||
gatewayDetail.innerHTML = '<div class="wolai-page-ai-empty">打开 Hermes 设置后会检查 gateway 与当前 profile。</div>';
|
||||
} else {
|
||||
var gatewayInfo = gatewayHealth.gateway || {};
|
||||
var profileInfo = gatewayHealth.profile || {};
|
||||
@@ -798,8 +1020,8 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
}
|
||||
var chatOnlyPanel = drawer.querySelector('[data-page-ai-chat-only-panel]');
|
||||
if (chatOnlyPanel instanceof HTMLElement) {
|
||||
chatOnlyPanel.innerHTML = pageAiRenderAgentDescriptorCard('chat_only', 'Chat-only') +
|
||||
'<section class="wolai-page-ai-memory-card"><div class="wolai-page-ai-memory-head"><div class="wolai-page-ai-memory-title">Chat-only</div><div class="wolai-page-ai-memory-scope">默认不申请文件写权限</div></div></section>';
|
||||
chatOnlyPanel.innerHTML = pageAiRenderAgentDescriptorCard('chat_only', 'API Chat / Chat-only profile') +
|
||||
'<section class="wolai-page-ai-memory-card"><div class="wolai-page-ai-memory-head"><div class="wolai-page-ai-memory-title">API Chat / Chat-only profile</div><div class="wolai-page-ai-memory-scope">默认不申请文件写权限,归属 MNote 设置。</div></div></section>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,6 +1081,11 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'<button type="button" class="wolai-page-ai-icon" data-page-ai-action="close" aria-label="关闭页面 AI">×</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="wolai-page-ai-runtime-strip" data-page-ai-runtime-strip data-page-ai-tab="status" aria-label="打开 Page AI 状态">' +
|
||||
'<span data-page-ai-runtime-badge>reasonix · new-session</span>' +
|
||||
'<span data-page-ai-runtime-active-run>空闲</span>' +
|
||||
'<span data-page-ai-runtime-acp>无 ACP session</span>' +
|
||||
'</button>' +
|
||||
'<div class="wolai-page-ai-body">' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="chat">' +
|
||||
'<div class="wolai-page-ai-chat-meta">' +
|
||||
@@ -885,26 +1112,36 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'<div class="wolai-page-ai-settings-head">' +
|
||||
'<button type="button" class="wolai-page-ai-back" data-page-ai-tab="chat">← 聊天</button>' +
|
||||
'<div class="wolai-page-ai-settings-tabs" role="tablist" aria-label="页面 AI 设置">' +
|
||||
'<button type="button" class="wolai-page-ai-tab is-active" data-page-ai-tab="agent" role="tab" aria-selected="true">Common</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="hermes-settings" role="tab" aria-selected="false">Hermes</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="reasonix-settings" role="tab" aria-selected="false">Reasonix</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="chat-only-settings" role="tab" aria-selected="false">Chat-only</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="runtime" role="tab" aria-selected="false">高级</button>' +
|
||||
pageAiSettingsTabsHtml('agent') +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-profile-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-memory-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-memory-grid" data-page-ai-agent-panel></div>' +
|
||||
'<label class="wolai-page-ai-context-select">' +
|
||||
'<span>默认上下文 scope</span>' +
|
||||
'<select data-page-ai-context-scope>' +
|
||||
'<option value="page">当前页</option>' +
|
||||
'<option value="selection">当前选区</option>' +
|
||||
'<option value="block">当前块</option>' +
|
||||
'<option value="options">页面设置</option>' +
|
||||
'</select>' +
|
||||
'</label>' +
|
||||
'<div class="wolai-page-ai-settings-stack" data-page-ai-agent-panel></div>' +
|
||||
'<div class="wolai-page-ai-settings-stack" data-page-ai-chat-only-panel></div>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>MNote 工具</span>' +
|
||||
'<span data-page-ai-last-tool>暂无 tool call</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-tool-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-tool-list></div>' +
|
||||
'</div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="hermes-settings" hidden>' +
|
||||
'<div class="wolai-page-ai-settings-head">' +
|
||||
'<button type="button" class="wolai-page-ai-back" data-page-ai-tab="chat">← 聊天</button>' +
|
||||
'<div class="wolai-page-ai-settings-tabs" role="tablist" aria-label="页面 AI 设置">' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="agent" role="tab" aria-selected="false">Common</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab is-active" data-page-ai-tab="hermes-settings" role="tab" aria-selected="true">Hermes</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="reasonix-settings" role="tab" aria-selected="false">Reasonix</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="chat-only-settings" role="tab" aria-selected="false">Chat-only</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="runtime" role="tab" aria-selected="false">高级</button>' +
|
||||
pageAiSettingsTabsHtml('hermes-settings') +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-settings-grid">' +
|
||||
@@ -914,17 +1151,21 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'</label>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="wolai-page-ai-settings-link" data-page-ai-action="open-hermes-settings">打开 Hermes 设置</button>' +
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-gateway-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>Hermes gateway</span>' +
|
||||
'<span data-page-ai-gateway-status>未检查</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-gateway-detail></div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-memory-grid" data-page-ai-hermes-panel></div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="reasonix-settings" hidden>' +
|
||||
'<div class="wolai-page-ai-settings-head">' +
|
||||
'<button type="button" class="wolai-page-ai-back" data-page-ai-tab="chat">← 聊天</button>' +
|
||||
'<div class="wolai-page-ai-settings-tabs" role="tablist" aria-label="页面 AI 设置">' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="agent" role="tab" aria-selected="false">Common</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="hermes-settings" role="tab" aria-selected="false">Hermes</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab is-active" data-page-ai-tab="reasonix-settings" role="tab" aria-selected="true">Reasonix</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="chat-only-settings" role="tab" aria-selected="false">Chat-only</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="runtime" role="tab" aria-selected="false">高级</button>' +
|
||||
pageAiSettingsTabsHtml('reasonix-settings') +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-settings-grid">' +
|
||||
@@ -935,26 +1176,13 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-memory-grid" data-page-ai-reasonix-panel></div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="chat-only-settings" hidden>' +
|
||||
'<div class="wolai-page-ai-settings-head">' +
|
||||
'<button type="button" class="wolai-page-ai-back" data-page-ai-tab="chat">← 聊天</button>' +
|
||||
'<div class="wolai-page-ai-settings-tabs" role="tablist" aria-label="页面 AI 设置">' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="agent" role="tab" aria-selected="false">Common</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="hermes-settings" role="tab" aria-selected="false">Hermes</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="reasonix-settings" role="tab" aria-selected="false">Reasonix</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab is-active" data-page-ai-tab="chat-only-settings" role="tab" aria-selected="true">Chat-only</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="runtime" role="tab" aria-selected="false">高级</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-memory-grid" data-page-ai-chat-only-panel></div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="skills" hidden>' +
|
||||
'<div class="wolai-page-ai-settings-head">' +
|
||||
'<button type="button" class="wolai-page-ai-back" data-page-ai-tab="chat">← 聊天</button>' +
|
||||
'<div class="wolai-page-ai-settings-tabs" role="tablist" aria-label="页面 AI 设置">' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="agent" role="tab" aria-selected="false">Agent</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="agent" role="tab" aria-selected="false">设置</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab is-active" data-page-ai-tab="skills" role="tab" aria-selected="true">能力</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="runtime" role="tab" aria-selected="false">Runtime</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="status" role="tab" aria-selected="false">状态</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-skills-toolbar">' +
|
||||
@@ -974,47 +1202,51 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-skill-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-skill-list" data-page-ai-skill-list></div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="runtime" hidden>' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="status" hidden>' +
|
||||
'<div class="wolai-page-ai-settings-head">' +
|
||||
'<button type="button" class="wolai-page-ai-back" data-page-ai-tab="chat">← 聊天</button>' +
|
||||
'<div class="wolai-page-ai-settings-tabs" role="tablist" aria-label="页面 AI 设置">' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="agent" role="tab" aria-selected="false">Agent</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab" data-page-ai-tab="skills" role="tab" aria-selected="false">能力</button>' +
|
||||
'<button type="button" class="wolai-page-ai-tab is-active" data-page-ai-tab="runtime" role="tab" aria-selected="true">Runtime</button>' +
|
||||
pageAiStatusTabsHtml() +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="wolai-page-ai-settings-link" data-page-ai-action="open-hermes-settings">打开 Hermes 设置</button>' +
|
||||
'<label class="wolai-page-ai-context-select">' +
|
||||
'<span>兼容上下文 scope</span>' +
|
||||
'<select data-page-ai-context-scope>' +
|
||||
'<option value="page">当前页</option>' +
|
||||
'<option value="selection">当前选区</option>' +
|
||||
'<option value="block">当前块</option>' +
|
||||
'<option value="options">页面设置</option>' +
|
||||
'</select>' +
|
||||
'</label>' +
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-gateway-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>gateway</span>' +
|
||||
'<span data-page-ai-gateway-status>未检查</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-gateway-detail></div>' +
|
||||
'<div class="wolai-page-ai-toolbar">' +
|
||||
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-action="stop-run">Stop turn</button>' +
|
||||
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-action="reset-runtime">Reset current runtime</button>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>queue</span>' +
|
||||
'<span>Current runtime</span>' +
|
||||
'<span data-page-ai-runtime-badge>未加载</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-runtime-detail></div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>Queue</span>' +
|
||||
'<span data-page-ai-queue-status>由 mnote-web 管理</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-queue-list></div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tools-panel" hidden>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>MNote 工具调试</span>' +
|
||||
'<span data-page-ai-last-tool>暂无 tool call</span>' +
|
||||
'<span>Jobs</span>' +
|
||||
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-action="stop-all-jobs">Stop all</button>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-tool-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-tool-list></div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-jobs-list></div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>Logs tail</span>' +
|
||||
'<span>ACP stderr / tool failed / MCP failed</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-logs-list></div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tools-panel">' +
|
||||
'<div class="wolai-page-ai-tools-head">' +
|
||||
'<span>Usage</span>' +
|
||||
'<span>last run / session / cache</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-tool-list" data-page-ai-usage-detail></div>' +
|
||||
'</div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-ai-panel-section" data-page-ai-panel="history" hidden>' +
|
||||
@@ -1034,6 +1266,10 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'<span>按 agent 筛选</span>' +
|
||||
'<select data-page-ai-session-agent-filter><option value="all">全部 agent</option></select>' +
|
||||
'</label>' +
|
||||
'<label class="wolai-page-ai-skill-search">' +
|
||||
'<span>按状态筛选</span>' +
|
||||
'<select data-page-ai-session-status-filter><option value="all">全部状态</option></select>' +
|
||||
'</label>' +
|
||||
'<div class="wolai-page-ai-inline-error" data-page-ai-session-error hidden></div>' +
|
||||
'<div class="wolai-page-ai-conversation" data-page-ai-conversation></div>' +
|
||||
'</section>' +
|
||||
@@ -1041,6 +1277,7 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'<div class="wolai-page-ai-footer">' +
|
||||
'<div class="wolai-page-ai-composer">' +
|
||||
'<textarea class="wolai-page-ai-input" data-page-ai-input rows="3" placeholder="输入消息…"></textarea>' +
|
||||
'<div class="wolai-page-ai-reasonix-controls" data-page-ai-reasonix-quick-controls hidden></div>' +
|
||||
'<div class="wolai-page-ai-composer-bar">' +
|
||||
'<button type="button" class="wolai-page-ai-tool-button" data-page-ai-action="new-session" title="新会话">+</button>' +
|
||||
'<div class="wolai-page-ai-agent-picker">' +
|
||||
@@ -1209,6 +1446,98 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function pageAiLooksLikeReasonixPlanMessage(item) {
|
||||
if (!item || item.role !== 'assistant') return false;
|
||||
var text = String(item.content || '').trim();
|
||||
if (!text || text.length < 40) return false;
|
||||
if (/ACP connection closed|AI 当前请求失败|run failed/i.test(text)) return false;
|
||||
var hasPlanWord = /计划|步骤|执行|修改|写入|新建|验证|plan/i.test(text);
|
||||
var awaitsApproval = /请批准|待批准|批准后|确认后|审批|批准,|开始执行|approve/i.test(text);
|
||||
var hasStepShape = /(^|\n)\s*(?:\d+[\.\、)]|[-*]\s+|\|\s*\d+\s*\|)/.test(text);
|
||||
return hasPlanWord && awaitsApproval && hasStepShape;
|
||||
}
|
||||
|
||||
function pageAiExtractReasonixPlanSteps(text) {
|
||||
var seen = {};
|
||||
var steps = [];
|
||||
String(text || '').replace(/\r\n/g, '\n').split('\n').forEach(function(line) {
|
||||
var trimmed = line.trim();
|
||||
if (!trimmed) return;
|
||||
var step = '';
|
||||
var tableCells = trimmed.indexOf('|') >= 0
|
||||
? trimmed.split('|').map(function(cell) { return cell.trim(); }).filter(Boolean)
|
||||
: [];
|
||||
if (tableCells.length >= 2 && /^\d+$/.test(tableCells[0])) {
|
||||
step = tableCells.slice(1).join(' · ');
|
||||
} else {
|
||||
var numbered = trimmed.match(/^\s*\d+[\.\、)]\s+(.+)$/);
|
||||
var bullet = trimmed.match(/^\s*[-*]\s+(?:\[[ xX~>|-]\]\s*)?(.+)$/);
|
||||
step = numbered ? numbered[1] : (bullet ? bullet[1] : '');
|
||||
}
|
||||
step = String(step || '').replace(/\s+/g, ' ').trim();
|
||||
if (!step || step.length < 3 || /^[-:|]+$/.test(step)) return;
|
||||
if (seen[step]) return;
|
||||
seen[step] = true;
|
||||
var lower = step.toLowerCase();
|
||||
var status = /✅|已完成|done|completed/.test(step) ? 'completed'
|
||||
: (/当前|进行中|执行中|待批准|in progress|running/.test(lower) ? 'inProgress' : 'pending');
|
||||
steps.push({ text: step, status: status });
|
||||
});
|
||||
return steps.slice(0, 8);
|
||||
}
|
||||
|
||||
function pageAiPlanStepIcon(status) {
|
||||
if (status === 'completed') return '✓';
|
||||
if (status === 'inProgress') return '…';
|
||||
return String.fromCharCode(8226);
|
||||
}
|
||||
|
||||
function pageAiRenderReasonixPlanCard(item) {
|
||||
var text = String(item.content || '').trim();
|
||||
var steps = pageAiExtractReasonixPlanSteps(text);
|
||||
var stepHtml = steps.length ? (
|
||||
'<ol class="wolai-page-ai-plan-step-list">' + steps.map(function(step) {
|
||||
return '' +
|
||||
'<li class="wolai-page-ai-plan-step-item" data-status="' + escapeHtml(step.status || 'pending') + '">' +
|
||||
'<span class="wolai-page-ai-plan-step-status" data-status="' + escapeHtml(step.status || 'pending') + '">' + escapeHtml(pageAiPlanStepIcon(step.status)) + '</span>' +
|
||||
'<span class="wolai-page-ai-plan-step-text">' + escapeHtml(step.text || '') + '</span>' +
|
||||
'</li>';
|
||||
}).join('') + '</ol>'
|
||||
) : '';
|
||||
return '' +
|
||||
'<div class="wolai-page-ai-message wolai-page-ai-message--assistant wolai-page-ai-plan-card" data-page-ai-reasonix-plan-card="true">' +
|
||||
'<div class="wolai-page-ai-plan-card-header">' +
|
||||
'<div class="wolai-page-ai-plan-card-title-wrap">' +
|
||||
'<span class="wolai-page-ai-plan-card-kicker">Reasonix</span>' +
|
||||
'<strong class="wolai-page-ai-plan-card-title">执行计划</strong>' +
|
||||
'</div>' +
|
||||
'<span class="wolai-page-ai-plan-card-badge">待批准</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-plan-card-markdown">' + renderPageAiMarkdown(text) + '</div>' +
|
||||
stepHtml +
|
||||
'<div class="wolai-page-ai-plan-card-actions">' +
|
||||
'<button type="button" class="wolai-page-ai-plan-card-button wolai-page-ai-plan-card-button--primary" data-page-ai-plan-action="approve">批准执行</button>' +
|
||||
'<button type="button" class="wolai-page-ai-plan-card-button" data-page-ai-plan-action="revise">要求修改</button>' +
|
||||
'<button type="button" class="wolai-page-ai-plan-card-button wolai-page-ai-plan-card-button--danger" data-page-ai-plan-action="cancel">取消</button>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function pageAiRenderPermissionDetails(item) {
|
||||
var details = item && item.permissionDetails && typeof item.permissionDetails === 'object'
|
||||
? item.permissionDetails
|
||||
: {};
|
||||
var rows = Array.isArray(details.rows) ? details.rows : [];
|
||||
if (!rows.length) {
|
||||
rows = [
|
||||
{ label: '请求', value: item.argsSummary || item.content || '' }
|
||||
];
|
||||
}
|
||||
return '<div class="wolai-page-ai-permission-summary">' + rows.slice(0, 6).map(function(row) {
|
||||
return '<div class="wolai-page-ai-permission-row"><span>' + escapeHtml(row.label || '') + '</span><strong>' + escapeHtml(row.value || '') + '</strong></div>';
|
||||
}).join('') + '</div>';
|
||||
}
|
||||
|
||||
function pageAiRenderNonToolMessage(item) {
|
||||
var roleLabel = item.role === 'user' ? '你' : (item.role === 'tool' ? '工具' : 'AI');
|
||||
if (item.kind === 'thought') {
|
||||
@@ -1224,18 +1553,34 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'</div>';
|
||||
}
|
||||
if (item.kind === 'permission') {
|
||||
var permissionActions = item.resolved ? '' : (
|
||||
var permissionOptions = Array.isArray(item.options) ? item.options : [];
|
||||
var permissionActions = '';
|
||||
if (!item.resolved) {
|
||||
if (permissionOptions.length) {
|
||||
permissionActions = '<div class="wolai-page-ai-message-actions">' + permissionOptions.map(function(option) {
|
||||
var optionText = String(option.optionId || '') + ' ' + String(option.kind || '') + ' ' + String(option.name || '');
|
||||
var denyLike = /reject|deny|cancel|stop|no/.test(optionText.toLowerCase());
|
||||
return '<button type="button" class="wolai-page-ai-ghost' + (denyLike ? ' wolai-page-ai-ghost--danger' : '') + '" data-page-ai-permission-action="' + (denyLike ? 'deny' : 'allow') + '" data-page-ai-permission-option-id="' + escapeHtml(option.optionId || '') + '" data-page-ai-permission-id="' + escapeHtml(item.permissionId || '') + '">' + escapeHtml(option.name || option.optionId || '选择') + '</button>';
|
||||
}).join('') + '</div>';
|
||||
} else {
|
||||
permissionActions = '' +
|
||||
'<div class="wolai-page-ai-message-actions">' +
|
||||
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-permission-action="allow" data-page-ai-permission-id="' + escapeHtml(item.permissionId || '') + '">允许</button>' +
|
||||
'<button type="button" class="wolai-page-ai-ghost" data-page-ai-permission-action="deny" data-page-ai-permission-id="' + escapeHtml(item.permissionId || '') + '">拒绝</button>' +
|
||||
'</div>'
|
||||
);
|
||||
'</div>';
|
||||
}
|
||||
}
|
||||
return '' +
|
||||
'<div class="wolai-page-ai-message wolai-page-ai-message--tool" data-page-ai-permission-request="' + escapeHtml(item.permissionId || '') + '">' +
|
||||
'<div class="wolai-page-ai-message-role">权限</div>' +
|
||||
'<div class="wolai-page-ai-message wolai-page-ai-message--tool wolai-page-ai-permission-card" data-page-ai-permission-request="' + escapeHtml(item.permissionId || '') + '">' +
|
||||
'<div class="wolai-page-ai-permission-card-header">' +
|
||||
'<div class="wolai-page-ai-plan-card-title-wrap">' +
|
||||
'<span class="wolai-page-ai-plan-card-kicker">权限</span>' +
|
||||
'<strong class="wolai-page-ai-plan-card-title">' + escapeHtml(item.toolName || 'session/request_permission') + '</strong>' +
|
||||
'</div>' +
|
||||
'<span class="wolai-page-ai-permission-badge">' + escapeHtml(item.resolved ? (item.decision === 'allow' || item.decision === 'allowed' ? '已允许' : '已处理') : '待确认') + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-ai-message-text">' +
|
||||
'<strong>' + escapeHtml(item.toolName || 'session/request_permission') + '</strong><br />' +
|
||||
'<span>' + escapeHtml(item.argsSummary || item.content || '') + '</span>' +
|
||||
pageAiRenderPermissionDetails(item) +
|
||||
permissionActions +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
@@ -1255,6 +1600,7 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
'</details>' +
|
||||
'</div>';
|
||||
}
|
||||
if (pageAiLooksLikeReasonixPlanMessage(item)) return pageAiRenderReasonixPlanCard(item);
|
||||
var streamingAttr = item.streaming ? ' data-page-ai-streaming="true"' : '';
|
||||
return '' +
|
||||
'<div class="wolai-page-ai-message wolai-page-ai-message--' + escapeHtml(item.role || 'assistant') + '"' + streamingAttr + '>' +
|
||||
@@ -1345,9 +1691,10 @@ export function createSidebarPageAiRenderRuntime(context) {
|
||||
var selected = pageAiSessionSelected(session.id);
|
||||
var usage = pageAiUsageSummary(session.usage);
|
||||
var agentLabel = pageAiSessionAgentLabel(session);
|
||||
var meta = [agentLabel, pageAiSessionStorageLabel(session), session.permissionLevel, session.shareId, session.status, usage].filter(Boolean).join(' · ');
|
||||
var statusValue = pageAiSessionStatusFilterValue(session);
|
||||
var meta = [agentLabel, pageAiSessionStorageLabel(session), session.runtimeMode, session.permissionLevel, session.shareId, pageAiSessionStatusLabel(statusValue), usage].filter(Boolean).join(' · ');
|
||||
return '' +
|
||||
'<div class="wolai-page-ai-message wolai-page-ai-message--history' + (active ? ' is-active' : '') + (selected ? ' is-selected' : '') + '" data-page-ai-session-row="' + escapeHtml(session.id) + '" data-page-ai-session-agent="' + escapeHtml(pageAiSessionAgentFilterValue(session)) + '">' +
|
||||
'<div class="wolai-page-ai-message wolai-page-ai-message--history' + (active ? ' is-active' : '') + (selected ? ' is-selected' : '') + '" data-page-ai-session-row="' + escapeHtml(session.id) + '" data-page-ai-session-agent="' + escapeHtml(pageAiSessionAgentFilterValue(session)) + '" data-page-ai-session-status="' + escapeHtml(statusValue) + '">' +
|
||||
'<button type="button" class="wolai-page-ai-session-check" data-page-ai-session-select="' + escapeHtml(session.id) + '" aria-checked="' + (selected ? 'true' : 'false') + '" aria-label="选择会话 ' + escapeHtml(session.title || session.id) + '">' +
|
||||
'<span>' + (selected ? '✓' : '') + '</span>' +
|
||||
'</button>' +
|
||||
|
||||
Reference in New Issue
Block a user