// == Pi Lab Page AI Runtime ==
// MNote-native adapter for Pi-first Page AI Lab.
// Renders the MNote-owned Pi Rust Page AI surface. OpenHub is kept as a
// compatibility/admin boundary during migration, not as the default chat owner.
// NO setInterval polling.
//
// UI note: @earendil-works/pi-web-ui@0.75.3 was checked as the mature upstream UI.
// It expects browser-side pi-agent-core, IndexedDB storage, API-key dialogs, model
// selection and builtin tools/artifacts. MNote's lab backend owns Pi RPC, access
// scope and tools, so this file keeps a host-owned adapter while matching the
// upstream ChatPanel/AgentInterface layout: message list, streaming composer,
// tool timeline, model/runtime controls and artifacts-style right rail.
//
// Default model: Omniroute/freefirst (consumed from backend status/default fields).
(function () {
'use strict';
var STATE_IDLE = 'idle';
var STATE_STARTING = 'starting';
var STATE_STARTED = 'started';
var STATE_STREAMING = 'streaming';
var STATE_ABORTED = 'aborted';
var STATE_ERROR = 'error';
var API = {
STATUS: '/api/page-ai/pi/status',
START: '/api/page-ai/pi/start',
SEND: '/api/page-ai/pi/send',
ABORT: '/api/page-ai/pi/abort',
UI_RESPONSE: '/api/page-ai/pi/ui-response',
EVENTS: '/api/page-ai/pi/events',
BOOTSTRAP: '/api/page-ai/pi/bootstrap',
SESSIONS: '/api/page-ai/pi/sessions',
EFFECTIVE: '/api/ai-settings/effective',
};
var DEFAULT_MODEL_PROVIDER = 'omniroute';
var DEFAULT_MODEL_ID = 'freefirst';
var DEFAULT_THINKING_LEVEL = 'medium';
var DEFAULT_PERMISSION_MODE = 'confirm';
var piLabInstalled = false;
var piLabPanelEl = null;
var piLabDrawerEl = null;
var piLabLauncherEl = null;
var piLabEventSource = null;
var piLabStartPromise = null;
var piLabState = {
status: STATE_IDLE,
enabled: false,
active: false,
standalone: false,
sessionId: null,
providerSessionId: null,
defaultModelProvider: DEFAULT_MODEL_PROVIDER,
defaultModelId: DEFAULT_MODEL_ID,
defaultThinkingLevel: DEFAULT_THINKING_LEVEL,
modelProvider: null,
modelId: null,
thinkingLevel: DEFAULT_THINKING_LEVEL,
permissionMode: DEFAULT_PERMISSION_MODE,
permissionMenuOpen: false,
pendingPermissionModeApply: false,
applyingPermissionMode: false,
actionMenuOpen: false,
runtimeMode: null,
runtimeImplementation: null,
runtimeBinary: null,
runtimeAvailable: true,
runtimeInstallHint: '',
runtimeError: '',
runtimePid: null,
managedBuiltinTools: [],
piExtensionSources: [],
piExtensionToolNames: [],
session: null,
allowedRootsSummary: '',
selectionSummary: '',
selectionText: '',
changedFiles: [],
messages: [],
diagnostics: '',
receipts: [],
modelOptions: [],
history: [],
pendingQueue: { steering: [], followUp: [] },
viewingHistorySessionId: null,
contextSelection: {
currentPage: false,
currentFolder: false,
selection: false,
lightrag: false,
},
};
var streamingAssistantMsg = null;
var piRunViewModel = createPiRunViewModel();
var activePiUiDialog = null;
var piCustomUiState = {
panel: null,
widgetKey: '',
title: '',
lines: [],
selectedOptionIndex: 0,
keyQueue: [],
submitted: false,
pendingCustomRequest: null,
};
var piToastSeq = 0;
function createPiRunViewModel(seed) {
seed = seed || {};
return {
turns: Array.isArray(seed.turns) ? seed.turns : [],
messages: Array.isArray(seed.messages) ? seed.messages : [],
toolCallsById: seed.toolCallsById || {},
pendingQueue: seed.pendingQueue || { steering: [], followUp: [] },
currentAssistant: seed.currentAssistant || null,
runtimeStatus: seed.runtimeStatus || STATE_IDLE,
abortResponse: seed.abortResponse || null,
lastEventType: seed.lastEventType || '',
lastToolCall: null,
};
}
function normalizeQueueItems(value) {
if (!Array.isArray(value)) return [];
return value.map(function (item) {
if (item == null) return '';
if (typeof item === 'string') return item;
return {
id: item.id || item.messageId || item.queueId || '',
text: item.text || item.message || item.prompt || '',
createdAt: item.createdAt || item.timestamp || '',
};
}).filter(function (item) {
return typeof item === 'string' ? item.trim() : (item.text || item.id);
});
}
function rebuildPiRunToolIndex(vm) {
vm.toolCallsById = {};
(vm.messages || []).forEach(function (msg) {
(msg && Array.isArray(msg.toolCalls) ? msg.toolCalls : []).forEach(function (tc) {
if (!tc) return;
var key = tc.id || tc.name || ('tool-' + Object.keys(vm.toolCallsById).length);
vm.toolCallsById[key] = tc;
});
});
return vm.toolCallsById;
}
function syncPiRunViewModelFromState() {
piRunViewModel.messages = piLabState.messages;
piRunViewModel.pendingQueue = piLabState.pendingQueue || { steering: [], followUp: [] };
piRunViewModel.currentAssistant = streamingAssistantMsg;
piRunViewModel.runtimeStatus = piLabState.status;
rebuildPiRunToolIndex(piRunViewModel);
return piRunViewModel;
}
function syncPiRunViewModelToState() {
piLabState.messages = piRunViewModel.messages;
piLabState.pendingQueue = piRunViewModel.pendingQueue || { steering: [], followUp: [] };
streamingAssistantMsg = piRunViewModel.currentAssistant || null;
return piRunViewModel;
}
function resetPiRunViewModel(options) {
piRunViewModel = createPiRunViewModel({ runtimeStatus: piLabState.status });
if (!options || options.sync !== false) syncPiRunViewModelToState();
return piRunViewModel;
}
function enterHistoryReplayMode(sessionId) {
piLabState.viewingHistorySessionId = sessionId || piLabState.sessionId || null;
if (piLabEventSource) {
piLabEventSource.close();
piLabEventSource = null;
}
}
function exitHistoryReplayMode() {
piLabState.viewingHistorySessionId = null;
}
function ensurePiRunAssistant(vm) {
if (!vm.currentAssistant) {
vm.currentAssistant = { role: 'assistant', text: '', toolCalls: [], citations: [], diffSummary: null, status: 'streaming' };
vm.messages.push(vm.currentAssistant);
}
vm.currentAssistant.status = vm.currentAssistant.status || 'streaming';
vm.runtimeStatus = STATE_STREAMING;
return vm.currentAssistant;
}
function findLastAssistant(vm) {
return (vm.messages || []).slice().reverse().find(function (message) {
return message && message.role === 'assistant';
}) || null;
}
function piRunUpsertToolCall(vm, raw, status, patch) {
var msg = vm.currentAssistant || findLastAssistant(vm) || ensurePiRunAssistant(vm);
var payload = raw || {};
var calls = ensureToolCalls(msg);
var id = normalizeToolCallId(payload);
var name = toolDisplayName(payload);
var found = null;
if (id) found = calls.find(function (item) { return item && item.id === id; });
if (!found && name) {
found = calls.slice().reverse().find(function (item) {
return item && item.name === name && (item.status === 'running' || item.status === 'pending');
});
}
if (!found) {
found = { id: id || ('tool-' + (calls.length + 1)), name: name, args: {}, status: status || 'running' };
calls.push(found);
}
found.id = id || found.id;
found.name = name || found.name;
found.status = status || found.status || 'running';
if (payload.args || payload.input || payload.params) found.args = payload.args || payload.input || payload.params;
if (payload.details) found.details = payload.details;
Object.keys(patch || {}).forEach(function (key) { found[key] = patch[key]; });
vm.lastToolCall = found;
rebuildPiRunToolIndex(vm);
return found;
}
function reducePiRunViewModel(vm, event) {
vm = vm || createPiRunViewModel();
event = event || {};
var payload = event.payload || {};
vm.lastEventType = event.type || '';
if (event.type === 'clear') {
vm.messages = [];
vm.toolCallsById = {};
vm.pendingQueue = { steering: [], followUp: [] };
vm.currentAssistant = null;
vm.abortResponse = null;
return vm;
}
if (event.type === 'queue_update') {
vm.pendingQueue = {
steering: normalizeQueueItems(payload.steering),
followUp: normalizeQueueItems(payload.followUp),
};
return vm;
}
if (event.type === 'user_prompt') {
vm.messages.push({ role: 'user', text: event.text || payload.text || payload.message || '', meta: event.meta || payload.meta || '' });
return vm;
}
if (event.type === 'assistant_begin') {
ensurePiRunAssistant(vm);
return vm;
}
if (event.type === 'assistant_delta') {
var deltaMsg = ensurePiRunAssistant(vm);
if (event.delta || payload.delta) deltaMsg.text += event.delta || payload.delta;
if ((event.text || payload.text) && !(event.delta || payload.delta)) deltaMsg.text = event.text || payload.text;
return vm;
}
if (event.type === 'assistant_text_end') {
var textEndMsg = ensurePiRunAssistant(vm);
textEndMsg.text = event.text || payload.text || payload.content || textEndMsg.text;
return vm;
}
if (event.type === 'assistant_done') {
var doneMsg = ensurePiRunAssistant(vm);
if (event.text || payload.text) doneMsg.text = event.text || payload.text;
if (event.toolCalls || payload.toolCalls) doneMsg.toolCalls = event.toolCalls || payload.toolCalls;
if (event.citations || payload.citations) doneMsg.citations = event.citations || payload.citations;
if (event.diffSummary || payload.diffSummary) doneMsg.diffSummary = event.diffSummary || payload.diffSummary;
doneMsg.status = 'done';
vm.currentAssistant = null;
vm.runtimeStatus = STATE_STARTED;
rebuildPiRunToolIndex(vm);
return vm;
}
if (event.type === 'assistant_abort') {
var abortMsg = vm.currentAssistant || findLastAssistant(vm) || ensurePiRunAssistant(vm);
abortMsg.status = 'aborted';
abortMsg.abortReason = event.reason || payload.reason || payload.stopReason || payload.error || payload.message || '已中止';
abortMsg.abortResponse = payload || { reason: abortMsg.abortReason };
vm.abortResponse = payload || { reason: abortMsg.abortReason };
vm.currentAssistant = null;
vm.runtimeStatus = STATE_ABORTED;
return vm;
}
if (event.type === 'assistant_error') {
var errMsg = ensurePiRunAssistant(vm);
errMsg.text += (errMsg.text ? '\n' : '') + '错误: ' + (event.message || payload.error || payload.message || 'Pi runtime error');
errMsg.status = 'done';
vm.currentAssistant = null;
vm.runtimeStatus = STATE_STARTED;
return vm;
}
if (event.type === 'tool_upsert') {
piRunUpsertToolCall(vm, payload.raw || payload, payload.status || event.status, payload.patch || event.patch || {});
return vm;
}
if (event.type === 'citation') {
var citMsg = ensurePiRunAssistant(vm);
citMsg.citations.push({ source: payload.source || '', title: payload.title || '', url: payload.url || '#' });
return vm;
}
if (event.type === 'diff') {
var diffMsg = ensurePiRunAssistant(vm);
diffMsg.diffSummary = diffMsg.diffSummary || { files: [] };
diffMsg.diffSummary.files = payload.files || [];
return vm;
}
return vm;
}
function applyPiRunEvent(event) {
syncPiRunViewModelFromState();
reducePiRunViewModel(piRunViewModel, event);
syncPiRunViewModelToState();
return piRunViewModel;
}
function injectStyles() {
var styleId = 'pi-lab-runtime-style';
if (document.getElementById(styleId)) return;
var style = document.createElement('style');
style.id = styleId;
style.textContent =
'.wolai-page-ai-pi-lab-launcher{position:fixed;right:26px;bottom:92px;z-index:2600;width:36px;height:36px;border-radius:18px;border:1px solid rgba(37,37,33,.14);background:#fff;color:#252521;box-shadow:0 8px 24px rgba(15,23,42,.16);display:grid;place-items:center;font:600 15px/1 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;cursor:pointer}' +
'.wolai-page-ai-pi-lab-launcher:hover{background:#f7f7f5;box-shadow:0 10px 28px rgba(15,23,42,.20)}' +
'.wolai-page-ai-pi-lab-launcher[data-state="streaming"]::after{content:"";position:absolute;right:4px;top:4px;width:8px;height:8px;border-radius:50%;background:#10a37f;box-shadow:0 0 0 3px rgba(16,163,127,.14)}' +
'.wolai-page-ai-pi-lab-drawer{position:fixed;right:18px;bottom:18px;top:64px;z-index:2590;width:min(760px,calc(100vw - 36px));border:1px solid rgba(35,35,30,.10);border-radius:20px;background:#f5f6fa;box-shadow:0 24px 70px rgba(15,23,42,.22);overflow:hidden;display:flex;flex-direction:column}' +
'.wolai-page-ai-pi-lab-drawer[hidden]{display:none!important}' +
'.wolai-page-ai-pi-lab-drawer[data-minimized="true"]{top:auto;height:54px;width:min(420px,calc(100vw - 36px))}' +
'.wolai-page-ai-pi-lab-drawer[data-minimized="true"] .wolai-page-ai-pi-lab-config,.wolai-page-ai-pi-lab-drawer[data-minimized="true"] .wolai-page-ai-pi-lab-context-strip,.wolai-page-ai-pi-lab-drawer[data-minimized="true"] .wolai-page-ai-pi-lab-body,.wolai-page-ai-pi-lab-drawer[data-minimized="true"] .wolai-page-ai-pi-lab-diagnostics{display:none!important}' +
'.wolai-page-ai-pi-lab-shell{position:relative;display:flex;flex-direction:column;height:100%;min-height:0;background:#f5f6fa;color:#242424;font:13px/1.45 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;overflow:hidden}' +
'.wolai-page-ai-pi-lab-shell[hidden]{display:none!important}' +
'.wolai-page-ai-pi-lab-topbar{height:58px;display:flex;align-items:center;gap:10px;padding:0 18px;background:#f5f6fa;flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-brand{display:flex;align-items:center;gap:8px;min-width:0;flex:1}' +
'.wolai-page-ai-pi-lab-logo{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;background:#1f6feb;color:#fff;font-weight:700}' +
'.wolai-page-ai-pi-lab-title{display:flex;flex-direction:column;gap:1px;min-width:0}' +
'.wolai-page-ai-pi-lab-title strong{font-size:22px;font-weight:760;letter-spacing:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' +
'.wolai-page-ai-pi-lab-title span{font-size:11px;color:#6f6a60;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' +
'.wolai-page-ai-pi-lab-icon-btn{width:30px;height:30px;border:1px solid #e2ded6;border-radius:8px;background:#fff;color:#514f49;display:grid;place-items:center;cursor:pointer}' +
'.wolai-page-ai-pi-lab-icon-btn:hover{background:#f7f6f2}' +
'.wolai-page-ai-pi-lab-commandbar{height:50px;margin:0 14px 12px;padding:0 12px;border:1px solid #e4e7ef;border-radius:14px;background:#fff;display:flex;align-items:center;gap:8px;box-shadow:0 2px 8px rgba(15,23,42,.04);flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-commandbar .wolai-page-ai-pi-lab-tool-icon{width:32px;height:32px;border:0;background:transparent;color:#3c424c;display:grid;place-items:center;cursor:pointer;border-radius:9px}' +
'.wolai-page-ai-pi-lab-commandbar .wolai-page-ai-pi-lab-tool-icon svg,.wolai-page-ai-pi-lab-square svg,.wolai-page-ai-pi-lab-icon-btn svg{width:17px;height:17px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}' +
'.wolai-page-ai-pi-lab-commandbar .wolai-page-ai-pi-lab-tool-icon:hover,.wolai-page-ai-pi-lab-commandbar .wolai-page-ai-pi-lab-tool-icon[data-active="true"]{background:#f3f5f8;color:#111827}' +
'.wolai-page-ai-pi-lab-commandbar .wolai-page-ai-pi-lab-tool-icon[disabled]{opacity:.35;cursor:default}' +
'.wolai-page-ai-pi-lab-commandbar-spacer{flex:1}' +
'.wolai-page-ai-pi-lab-config{display:none;grid-template-columns:minmax(0,1fr) auto;gap:10px;margin:0 14px 12px;padding:10px 12px;border:1px solid #e5e8ef;border-radius:12px;background:#fff;box-shadow:0 4px 14px rgba(15,23,42,.05);flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-drawer[data-config-open="true"] .wolai-page-ai-pi-lab-config{display:grid}' +
'.wolai-page-ai-pi-lab-model-row{display:flex;flex-wrap:wrap;gap:6px;min-width:0}' +
'.wolai-page-ai-pi-lab-settings{border:0;min-width:0}' +
'.wolai-page-ai-pi-lab-settings>summary{display:inline-flex;align-items:center;gap:6px;min-height:28px;cursor:pointer;list-style:none;color:#514f49;font-size:12px}' +
'.wolai-page-ai-pi-lab-settings>summary::-webkit-details-marker{display:none}' +
'.wolai-page-ai-pi-lab-settings>summary::before{content:"▸";font-size:10px;color:#8a8378}' +
'.wolai-page-ai-pi-lab-settings[open]>summary::before{content:"▾"}' +
'.wolai-page-ai-pi-lab-settings-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-top:8px;max-width:560px}' +
'.wolai-page-ai-pi-lab-history-layer{position:absolute;inset:0;z-index:28;display:block;pointer-events:auto}' +
'.wolai-page-ai-pi-lab-history-layer[hidden]{display:none!important}' +
'.wolai-page-ai-pi-lab-history-scrim{position:absolute;inset:0;background:rgba(15,23,42,.22);backdrop-filter:blur(1px);border-radius:18px}' +
'.wolai-page-ai-pi-lab-history-panel{position:absolute;left:0;top:0;bottom:0;width:min(340px,calc(100vw - 34px));border-right:1px solid #dfe4ec;background:#fff;box-shadow:18px 0 42px rgba(15,23,42,.18);display:flex;flex-direction:column;overflow:hidden}' +
'.wolai-page-ai-pi-lab-history-head{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:48px;padding:0 14px;border-bottom:1px solid #edf0f5;background:#fff;color:#1f2937;font-size:14px;font-weight:750}' +
'.wolai-page-ai-pi-lab-history-close{position:relative;width:26px;height:26px;border:1px solid #e1e4eb;border-radius:8px;background:#fff;color:#4a4f58;display:grid;place-items:center;cursor:pointer;font-size:0;line-height:1}' +
'.wolai-page-ai-pi-lab-history-close::before,.wolai-page-ai-pi-lab-history-close::after{content:"";position:absolute;left:7px;right:7px;top:12px;height:1.5px;background:currentColor;border-radius:999px}' +
'.wolai-page-ai-pi-lab-history-close::before{transform:rotate(45deg)}.wolai-page-ai-pi-lab-history-close::after{transform:rotate(-45deg)}' +
'.wolai-page-ai-pi-lab-history-close svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}' +
'.wolai-page-ai-pi-lab-history-toolbar{display:flex;align-items:center;gap:8px;padding:12px 14px 10px;border-bottom:1px solid #f0f2f6;background:#fafbfc}' +
'.wolai-page-ai-pi-lab-history-new{height:32px;flex:1;border:1px solid #1f6feb;border-radius:8px;background:#1f6feb;color:#fff;font:12px/1 inherit;font-weight:700;cursor:pointer}' +
'.wolai-page-ai-pi-lab-history-refresh,.wolai-page-ai-pi-lab-history-clear{height:32px;border:1px solid #d9dee8;border-radius:8px;background:#fff;color:#4b5563;font:12px/1 inherit;padding:0 9px;cursor:pointer}' +
'.wolai-page-ai-pi-lab-history-clear{color:#b42318;border-color:#f2c4bd}' +
'.wolai-page-ai-pi-lab-history-meta{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 14px;color:#6b7280;font-size:11px;border-bottom:1px solid #f0f2f6}' +
'.wolai-page-ai-pi-lab-history-list{min-height:0;overflow:auto;flex:1}' +
'.wolai-page-ai-pi-lab-history-row{border-bottom:1px solid #f0eee9;background:#fff;padding:11px 12px;display:grid;grid-template-columns:10px minmax(0,1fr) auto;gap:10px;align-items:center}' +
'.wolai-page-ai-pi-lab-history-row:hover{background:#f8faff}' +
'.wolai-page-ai-pi-lab-history-dot{width:7px;height:7px;border-radius:999px;background:#1f6feb;opacity:.35}' +
'.wolai-page-ai-pi-lab-history-row[data-active="true"] .wolai-page-ai-pi-lab-history-dot{opacity:1}' +
'.wolai-page-ai-pi-lab-history-row strong{display:block;font-size:12px;color:#1f2937}' +
'.wolai-page-ai-pi-lab-history-row span{font-size:11px;color:#6b7280}' +
'.wolai-page-ai-pi-lab-history-main{min-width:0;border:0;background:transparent;padding:0;text-align:left;cursor:pointer}' +
'.wolai-page-ai-pi-lab-history-main strong,.wolai-page-ai-pi-lab-history-main span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}' +
'.wolai-page-ai-pi-lab-history-actions{display:flex;gap:4px;align-items:center}' +
'.wolai-page-ai-pi-lab-history-action{border:1px solid #d8dee8;border-radius:6px;background:#fff;padding:4px 6px;font-size:11px;color:#4b5563;cursor:pointer;white-space:nowrap}' +
'.wolai-page-ai-pi-lab-history-action:hover{background:#f3f6fb}' +
'.wolai-page-ai-pi-lab-history-danger{color:#b42318;border-color:#f2c4bd}' +
'.wolai-page-ai-pi-lab-history-row[data-active="true"]{background:#f4f7ff}.wolai-page-ai-pi-lab-history-row[data-active="true"] .wolai-page-ai-pi-lab-history-main strong{color:#1f3f8f}' +
'.wolai-page-ai-pi-lab-replay-banner{margin:0 18px 10px;padding:8px 10px;border:1px solid #dbe5ff;border-radius:8px;background:#f6f8ff;color:#36507d;font-size:12px;display:flex;align-items:center;justify-content:space-between;gap:10px}' +
'.wolai-page-ai-pi-lab-replay-banner[hidden]{display:none!important}.wolai-page-ai-pi-lab-replay-banner button{border:1px solid #cfd9f5;border-radius:7px;background:#fff;color:#24406d;height:26px;padding:0 9px;font:12px/1 inherit;cursor:pointer}' +
'.wolai-page-ai-pi-lab-field{display:flex;flex-direction:column;gap:4px;font-size:11px;color:#6f6a60}' +
'.wolai-page-ai-pi-lab-field select,.wolai-page-ai-pi-lab-field input{height:30px;border:1px solid #ddd8cf;border-radius:8px;background:#fff;color:#242424;padding:0 8px;font:12px/1.3 inherit;min-width:0}' +
'.wolai-page-ai-pi-lab-context-strip{display:none;padding:0;margin:-6px 14px 12px;border:1px solid #ebe7de;border-radius:12px;background:#faf9f6;flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-drawer[data-config-open="true"] .wolai-page-ai-pi-lab-context-strip{display:block}' +
'.wolai-page-ai-pi-lab-context-strip>summary{display:flex;align-items:center;gap:8px;min-height:34px;padding:0 12px;cursor:pointer;list-style:none;color:#5d594f;font-size:12px}' +
'.wolai-page-ai-pi-lab-context-strip>summary::-webkit-details-marker{display:none}' +
'.wolai-page-ai-pi-lab-context-strip>summary::before{content:"▸";font-size:10px;color:#8a8378}' +
'.wolai-page-ai-pi-lab-context-strip[open]>summary::before{content:"▾"}' +
'.wolai-page-ai-pi-lab-context-title{font-weight:650;color:#42403a}' +
'.wolai-page-ai-pi-lab-context-current{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#242424;font-weight:650}' +
'.wolai-page-ai-pi-lab-context-count{margin-left:auto;color:#8a8378;font-size:11px}' +
'.wolai-page-ai-pi-lab-context-content{display:flex;align-items:center;gap:6px;padding:0 12px 8px;overflow-x:auto}' +
'.wolai-page-ai-pi-lab-chip{height:24px;display:inline-flex;align-items:center;gap:5px;border:1px solid #e4e0d8;border-radius:999px;background:#f8f7f3;color:#514f49;padding:0 8px;font-size:11px;max-width:100%}' +
'.wolai-page-ai-pi-lab-chip strong{font-weight:650;color:#242424;min-width:0;overflow:hidden;text-overflow:ellipsis}' +
'.wolai-page-ai-pi-lab-context-strip .wolai-page-ai-pi-lab-chip{flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-chip[data-tone="ok"]{background:#eef8f3;border-color:#ccebdc;color:#176b4b}' +
'.wolai-page-ai-pi-lab-chip[data-tone="warn"]{background:#fff6e6;border-color:#f2dfb5;color:#865b13}' +
'.wolai-page-ai-pi-lab-chip[data-tone="danger"]{background:#fff0ee;border-color:#f2c4bd;color:#a73b2f}' +
'.wolai-page-ai-pi-lab-actions{display:flex;align-items:center;gap:6px;justify-content:flex-end}' +
'.wolai-page-ai-pi-lab-btn{height:28px;border:1px solid #d9d4ca;border-radius:7px;background:#fff;color:#383631;font-size:12px;padding:0 10px;cursor:pointer;white-space:nowrap}' +
'.wolai-page-ai-pi-lab-btn:hover{background:#f7f6f2}' +
'.wolai-page-ai-pi-lab-btn:disabled{opacity:.45;cursor:default}' +
'.wolai-page-ai-pi-lab-btn-primary{background:#1f6feb;border-color:#1f6feb;color:#fff}' +
'.wolai-page-ai-pi-lab-btn-primary:hover{background:#1b61cf}' +
'.wolai-page-ai-pi-lab-btn-danger{background:#d93025;border-color:#d93025;color:#fff}' +
'.wolai-page-ai-pi-lab-body{position:relative;display:block;min-height:0;flex:1;background:#f5f6fa;padding:0 14px 12px}' +
'.wolai-page-ai-pi-lab-main{position:relative;display:flex;flex-direction:column;min-width:0;min-height:0;height:100%;overflow:hidden}' +
'.wolai-page-ai-pi-lab-messages{flex:1;min-height:0;overflow-y:auto;padding:22px 18px 20px;display:flex;flex-direction:column;gap:12px;overscroll-behavior:contain;background:#fff;border:1px solid #e4e7ef;border-radius:16px 16px 0 0;box-shadow:0 10px 28px rgba(15,23,42,.07)}' +
'.wolai-page-ai-pi-lab-empty{margin:auto;max-width:460px;text-align:center;color:#8a9099;background:transparent;border:0;border-radius:0;padding:10px 0 4px;box-shadow:none}' +
'.wolai-page-ai-pi-lab-empty-icon{width:76px;height:76px;margin:0 auto 18px;border-radius:50%;background:#f0f2f6;color:#8a93a2;display:grid;place-items:center;font-size:42px;font-weight:400}' +
'.wolai-page-ai-pi-lab-empty strong{display:block;color:#242833;margin-bottom:8px;font-size:25px;font-weight:760;letter-spacing:0}' +
'.wolai-page-ai-pi-lab-empty p{margin:0 0 20px;color:#8a9099;font-size:16px}' +
'.wolai-page-ai-pi-lab-examples{display:flex;flex-direction:column;align-items:center;gap:10px}' +
'.wolai-page-ai-pi-lab-example{height:42px;min-width:min(390px,100%);border:1px solid #e1e4eb;border-radius:12px;background:#fff;color:#4a4f58;font-size:16px;display:flex;align-items:center;justify-content:flex-start;gap:12px;padding:0 18px;box-shadow:0 3px 9px rgba(15,23,42,.05);cursor:pointer}' +
'.wolai-page-ai-pi-lab-example:hover{background:#f8fafc}' +
'.wolai-page-ai-pi-lab-example span{font-size:18px;color:#5c6470}' +
'.wolai-page-ai-pi-lab-message{display:flex;flex-direction:column;gap:6px;max-width:92%}' +
'.wolai-page-ai-pi-lab-message[data-role="user"]{align-self:flex-end;align-items:flex-end}' +
'.wolai-page-ai-pi-lab-message[data-role="assistant"],.wolai-page-ai-pi-lab-message[data-role="system"]{align-self:stretch}' +
'.wolai-page-ai-pi-lab-role{display:flex;align-items:center;gap:6px;color:#777166;font-size:11px;font-weight:650}' +
'.wolai-page-ai-pi-lab-message[data-role="user"] .wolai-page-ai-pi-lab-role{justify-content:flex-end}' +
'.wolai-page-ai-pi-lab-bubble{position:relative;border:1px solid #e6e2da;border-radius:12px;background:#fff;padding:10px 12px;color:#272521;word-break:break-word;box-shadow:0 4px 14px rgba(15,23,42,.035)}' +
'.wolai-page-ai-pi-lab-message[data-role="user"] .wolai-page-ai-pi-lab-bubble{background:#f3f7ff;border-color:#d9e6ff}' +
'.wolai-page-ai-pi-lab-text{white-space:pre-wrap}' +
'.wolai-page-ai-pi-lab-markdown{font-size:14px;line-height:1.62;color:#272521}' +
'.wolai-page-ai-pi-lab-markdown>*:first-child{margin-top:0}' +
'.wolai-page-ai-pi-lab-markdown>*:last-child{margin-bottom:0}' +
'.wolai-page-ai-pi-lab-markdown p{margin:0 0 10px}' +
'.wolai-page-ai-pi-lab-markdown h1,.wolai-page-ai-pi-lab-markdown h2,.wolai-page-ai-pi-lab-markdown h3{margin:14px 0 8px;font-weight:720;letter-spacing:0;line-height:1.28;color:#202124}' +
'.wolai-page-ai-pi-lab-markdown h1{font-size:20px}.wolai-page-ai-pi-lab-markdown h2{font-size:17px}.wolai-page-ai-pi-lab-markdown h3{font-size:15px}' +
'.wolai-page-ai-pi-lab-markdown ul,.wolai-page-ai-pi-lab-markdown ol{margin:0 0 10px 20px;padding:0}' +
'.wolai-page-ai-pi-lab-markdown li{margin:3px 0;padding-left:2px}' +
'.wolai-page-ai-pi-lab-markdown blockquote{margin:0 0 10px;padding:2px 0 2px 12px;border-left:3px solid #d8dce6;color:#5f6368}' +
'.wolai-page-ai-pi-lab-markdown pre{margin:8px 0 12px;padding:10px 12px;border:1px solid #e4e7ef;border-radius:8px;background:#f7f8fb;overflow:auto;white-space:pre;font:12px/1.55 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:#242833}' +
'.wolai-page-ai-pi-lab-markdown code{border:1px solid #e5e7eb;border-radius:5px;background:#f7f8fb;padding:1px 4px;font:12px/1.45 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:#1f2937}' +
'.wolai-page-ai-pi-lab-markdown pre code{border:0;background:transparent;padding:0;font:inherit;color:inherit}' +
'.wolai-page-ai-pi-lab-markdown table{width:100%;border-collapse:collapse;margin:8px 0 12px;font-size:13px}' +
'.wolai-page-ai-pi-lab-markdown th,.wolai-page-ai-pi-lab-markdown td{border:1px solid #e4e7ef;padding:6px 8px;text-align:left;vertical-align:top}' +
'.wolai-page-ai-pi-lab-markdown th{background:#f7f8fb;font-weight:650}' +
'.wolai-page-ai-pi-lab-markdown a{color:#1f6feb;text-decoration:none}.wolai-page-ai-pi-lab-markdown a:hover{text-decoration:underline}' +
'.wolai-page-ai-pi-lab-text.streaming-cursor::after,.wolai-page-ai-pi-lab-markdown.streaming-cursor::after{content:"";display:inline-block;width:7px;height:14px;margin-left:3px;vertical-align:-2px;background:#1f6feb;animation:pi-blink .85s steps(2,start) infinite}' +
'@keyframes pi-blink{50%{opacity:.18}}' +
'.wolai-page-ai-pi-lab-tool-calls,.wolai-page-ai-pi-lab-citations{display:flex;flex-direction:column;gap:6px;margin-top:8px}' +
'.wolai-page-ai-pi-lab-tool-timeline{margin-top:10px;border:1px solid #e4e7ef;border-radius:8px;background:#fafbfc;overflow:hidden}' +
'.wolai-page-ai-pi-lab-tool-timeline>summary{min-height:32px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 10px;cursor:pointer;list-style:none;color:#41464f;font-size:12px;font-weight:650}' +
'.wolai-page-ai-pi-lab-tool-timeline>summary::-webkit-details-marker{display:none}' +
'.wolai-page-ai-pi-lab-tool-timeline>summary::after{content:"▸";font-size:10px;color:#7c8593}' +
'.wolai-page-ai-pi-lab-tool-timeline[open]>summary::after{content:"▾"}' +
'.wolai-page-ai-pi-lab-tool-timeline-body{display:flex;flex-direction:column;gap:6px;padding:8px;border-top:1px solid #e4e7ef}' +
'.wolai-page-ai-pi-lab-tool-call{border:1px solid #e5e0d8;border-radius:9px;background:#fff;overflow:hidden}' +
'.wolai-page-ai-pi-lab-tool-call[data-status="running"]{border-color:#bcd7ff;background:#f7fbff}' +
'.wolai-page-ai-pi-lab-tool-call[data-status="error"]{border-color:#f2c4bd;background:#fff8f7}' +
'.wolai-page-ai-pi-lab-tool-call-header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 9px;font-size:12px;font-weight:650;color:#42403a}' +
'.wolai-page-ai-pi-lab-tool-call-header span{font-size:11px;color:#777166;font-weight:500}' +
'.wolai-page-ai-pi-lab-tool-call-summary-line{padding:0 9px 7px;color:#6f6a60;font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' +
'.wolai-page-ai-pi-lab-tool-call-details{border-top:1px solid #ebe7de;background:#fff}' +
'.wolai-page-ai-pi-lab-tool-call-details>summary{min-height:28px;display:flex;align-items:center;gap:6px;padding:0 9px;cursor:pointer;list-style:none;color:#5d594f;font-size:11px}' +
'.wolai-page-ai-pi-lab-tool-call-details>summary::-webkit-details-marker{display:none}' +
'.wolai-page-ai-pi-lab-tool-call-details>summary::before{content:"▸";font-size:10px;color:#8a8378}.wolai-page-ai-pi-lab-tool-call-details[open]>summary::before{content:"▾"}' +
'.wolai-page-ai-pi-lab-tool-call pre{margin:0;border-top:1px solid #ebe7de;background:#fff;padding:8px;max-height:140px;overflow:auto;font:11px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace;color:#42403a;white-space:pre-wrap}' +
'.wolai-page-ai-pi-lab-tool-policy{display:inline-flex;align-items:center;border-radius:999px;border:1px solid #ded7ca;background:#fff;padding:1px 6px;font-size:10px;color:#6f6557;margin-left:6px}' +
'.wolai-page-ai-pi-lab-tool-policy[data-policy="ask"]{border-color:#e1b870;background:#fff8e8;color:#8a5c13}' +
'.wolai-page-ai-pi-lab-tool-policy[data-approved="true"]{border-color:#83b99a;background:#eef9f1;color:#27613b}' +
'.wolai-page-ai-pi-lab-tool-policy[data-approved="false"]{border-color:#e0a39a;background:#fff0ee;color:#9f352c}' +
'.wolai-page-ai-pi-lab-abort-note{margin-top:8px;border:1px solid #f2c4bd;border-radius:8px;background:#fff8f7;color:#9f352c;padding:7px 9px;font-size:12px}' +
'.wolai-page-ai-pi-lab-message-actions{position:absolute;right:8px;top:8px;display:flex;gap:6px;opacity:0;pointer-events:none;transition:opacity .12s ease}' +
'.wolai-page-ai-pi-lab-bubble:hover .wolai-page-ai-pi-lab-message-actions,.wolai-page-ai-pi-lab-bubble:focus-within .wolai-page-ai-pi-lab-message-actions{opacity:1;pointer-events:auto}' +
'.wolai-page-ai-pi-lab-message-actions button{width:28px;height:28px;border:1px solid #e1e4eb;border-radius:8px;background:#fff;color:#4a4f58;padding:0;display:grid;place-items:center;cursor:pointer;box-shadow:0 4px 14px rgba(15,23,42,.08)}' +
'.wolai-page-ai-pi-lab-message-actions button:hover{background:#f8fafc}' +
'.wolai-page-ai-pi-lab-message-actions svg{width:15px;height:15px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}' +
'.wolai-page-ai-pi-lab-citation{display:inline-flex;align-items:center;gap:6px;width:max-content;max-width:100%;border:1px solid #d9e6ff;border-radius:999px;background:#f3f7ff;color:#2456a6;text-decoration:none;padding:4px 8px;font-size:11px}' +
'.wolai-page-ai-pi-lab-diff{display:inline-flex;align-items:center;width:max-content;max-width:100%;margin-top:8px;border:1px solid #f0dcb7;border-radius:999px;background:#fff7e8;color:#865b13;padding:4px 8px;font-size:11px}' +
'.wolai-page-ai-pi-lab-composer{position:relative;flex:0 0 auto;border:1px solid #e4e7ef;border-top:0;border-radius:0 0 16px 16px;background:#fff;box-shadow:0 14px 34px rgba(15,23,42,.09);overflow:visible}' +
'.wolai-page-ai-pi-lab-input-wrap{position:relative;background:#f7f8fb}' +
'.wolai-page-ai-pi-lab-input{width:100%;min-height:98px;max-height:190px;box-sizing:border-box;border:0;resize:none;padding:18px 62px 12px 22px;font:18px/1.45 inherit;color:#242424;background:transparent;outline:none}' +
'.wolai-page-ai-pi-lab-input::placeholder{color:#b6bbc5}' +
'.wolai-page-ai-pi-lab-quick{height:24px;border:1px solid #e5e0d8;border-radius:999px;background:#f8f7f3;color:#5d594f;font-size:11px;padding:0 8px;cursor:pointer}' +
'.wolai-page-ai-pi-lab-modebar{min-height:46px;display:flex;align-items:center;gap:8px;padding:6px 12px;border-top:1px solid #eef0f5;background:#fff;box-sizing:border-box}' +
'.wolai-page-ai-pi-lab-square{width:34px;height:34px;flex:0 0 34px;border:1px solid #e1e4eb;border-radius:9px;background:#fff;color:#242833;display:grid;place-items:center;cursor:pointer}' +
'.wolai-page-ai-pi-lab-square:hover{background:#f8fafc}' +
'.wolai-page-ai-pi-lab-square[data-active="true"],.wolai-page-ai-pi-lab-chip-button[data-active="true"]{border-color:#9ec5fe;background:#eef6ff;color:#1558a6}' +
'.wolai-page-ai-pi-lab-chip-button{height:34px;display:inline-flex;align-items:center;gap:6px;border:1px solid #e1e4eb;border-radius:10px;background:#fff;color:#4a4f58;padding:0 10px;font:12px/1 inherit;white-space:nowrap;cursor:pointer}' +
'.wolai-page-ai-pi-lab-chip-button svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}' +
'.wolai-page-ai-pi-lab-chip-button[data-tone="warn"]{border-color:#f0d8aa;background:#fff9ed;color:#865b13}.wolai-page-ai-pi-lab-chip-button[data-tone="danger"]{border-color:#f2c4bd;background:#fff8f7;color:#9f352c}.wolai-page-ai-pi-lab-chip-button[data-tone="ok"]{border-color:#bfe6ac;background:#f4fff0;color:#27613b}' +
'.wolai-page-ai-pi-lab-thinking-control{height:34px;border:1px solid #e1e4eb;border-radius:10px;background:#fff;color:#4a4f58;padding:0 8px;font:12px/1 inherit;max-width:104px}' +
'.wolai-page-ai-pi-lab-permission-wrap{position:relative;display:inline-flex;flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-permission-menu{position:absolute;left:0;bottom:40px;z-index:18;width:min(306px,calc(100vw - 28px));border:1px solid #dfe3ea;border-radius:12px;background:#fff;box-shadow:0 18px 46px rgba(15,23,42,.22);padding:6px;display:none;color:#242424}' +
'.wolai-page-ai-pi-lab-permission-wrap[data-open="true"] .wolai-page-ai-pi-lab-permission-menu{display:block}' +
'.wolai-page-ai-pi-lab-permission-option{width:100%;min-height:58px;border:0;border-radius:9px;background:#fff;color:#242424;display:grid;grid-template-columns:22px 1fr 18px;gap:10px;align-items:center;text-align:left;padding:8px 9px;font:13px/1.25 inherit;cursor:pointer}' +
'.wolai-page-ai-pi-lab-permission-option:hover{background:#f7f8fb}.wolai-page-ai-pi-lab-permission-option[data-active="true"]{background:#f3f6fb}' +
'.wolai-page-ai-pi-lab-permission-option svg{width:17px;height:17px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;color:#5d6470}' +
'.wolai-page-ai-pi-lab-permission-option strong{display:block;font-size:13px;font-weight:650}.wolai-page-ai-pi-lab-permission-option small{display:block;margin-top:4px;color:#6b7280;font-size:12px;line-height:1.25}.wolai-page-ai-pi-lab-permission-check{color:#6b7280;text-align:right}' +
'.wolai-page-ai-pi-lab-action-menu{position:absolute;left:12px;bottom:52px;z-index:16;width:min(300px,calc(100% - 24px));border:1px solid #dfe3ea;border-radius:12px;background:#fff;box-shadow:0 18px 46px rgba(15,23,42,.22);padding:6px;display:none;color:#242424}' +
'.wolai-page-ai-pi-lab-composer[data-menu-open="true"] .wolai-page-ai-pi-lab-action-menu{display:block}' +
'.wolai-page-ai-pi-lab-menu-section{padding:5px 7px 4px;color:#8a9099;font-size:11px;font-weight:650}' +
'.wolai-page-ai-pi-lab-menu-item{width:100%;min-height:34px;border:0;border-radius:8px;background:#fff;color:#242424;display:flex;align-items:center;gap:9px;text-align:left;padding:0 9px;font:13px/1.2 inherit;cursor:pointer}' +
'.wolai-page-ai-pi-lab-menu-item:hover{background:#f7f8fb}.wolai-page-ai-pi-lab-menu-item[data-active="true"]{background:#eef6ff;color:#1558a6}.wolai-page-ai-pi-lab-menu-item[disabled]{opacity:.45;cursor:default}.wolai-page-ai-pi-lab-menu-item[disabled]:hover{background:#fff}' +
'.wolai-page-ai-pi-lab-menu-item svg{width:15px;height:15px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-menu-item strong{margin-left:auto;color:#1558a6;font-size:13px}' +
'.wolai-page-ai-pi-lab-menu-sep{height:1px;background:#edf0f5;margin:6px 3px}' +
'.wolai-page-ai-pi-lab-segment{display:inline-flex;border:1px solid #e1e4eb;border-radius:10px;overflow:hidden;background:#fff}' +
'.wolai-page-ai-pi-lab-segment button{height:36px;border:0;background:#fff;color:#4a4f58;padding:0 16px;font:14px/1 inherit;cursor:pointer;white-space:nowrap}' +
'.wolai-page-ai-pi-lab-segment button[data-active=\"true\"]{background:#111827;color:#fff}' +
'.wolai-page-ai-pi-lab-stream-controls{display:inline-flex;align-items:center;gap:8px}' +
'.wolai-page-ai-pi-lab-queue-count{height:22px;min-width:22px;padding:0 6px;border-radius:999px;background:#eef2ff;color:#334155;display:inline-flex;align-items:center;justify-content:center;font-size:11px}' +
'.wolai-page-ai-pi-lab-model-control{height:34px;min-width:0;max-width:210px;flex:1 1 160px;border:1px solid #e1e4eb;border-radius:10px;background:#fff;color:#4a4f58;padding:0 10px;font:13px/1 inherit}' +
'.wolai-page-ai-pi-lab-spacer{flex:1}' +
'.wolai-page-ai-pi-lab-send{position:absolute;right:12px;bottom:11px;width:38px;height:38px;border:0;border-radius:12px;background:#1d9bf0;color:#fff;display:grid;place-items:center;cursor:pointer;box-shadow:0 10px 24px rgba(29,155,240,.25)}' +
'.wolai-page-ai-pi-lab-send svg{width:18px;height:18px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}' +
'.wolai-page-ai-pi-lab-send:disabled{opacity:.45;cursor:default}' +
'.wolai-page-ai-pi-lab-rail{position:absolute;right:14px;top:0;bottom:104px;width:260px;z-index:4;display:none;flex-direction:column;gap:8px;min-height:0;overflow:auto;padding:8px;border:1px solid #e4e7ef;border-radius:14px;background:#f7f8fb;box-shadow:0 18px 46px rgba(15,23,42,.18)}' +
'.wolai-page-ai-pi-lab-body[data-rail-open="true"] .wolai-page-ai-pi-lab-rail{display:flex}' +
'.wolai-page-ai-pi-lab-rail-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 2px 2px;color:#42403a;font-size:12px;font-weight:650}' +
'.wolai-page-ai-pi-lab-rail-close{width:24px;height:24px;border:1px solid #e1e4eb;border-radius:7px;background:#fff;color:#4a4f58;display:grid;place-items:center;cursor:pointer}' +
'.wolai-page-ai-pi-lab-rail-section{border:1px solid #e5e0d8;border-radius:10px;background:#fff;overflow:hidden}' +
'.wolai-page-ai-pi-lab-rail-section>summary{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:pointer;list-style:none;padding:8px 9px;font-size:11px;font-weight:650;color:#5d594f;background:#faf9f6}' +
'.wolai-page-ai-pi-lab-rail-section>summary::-webkit-details-marker{display:none}' +
'.wolai-page-ai-pi-lab-rail-section>summary::after{content:"▸";font-size:10px;color:#8a8378}' +
'.wolai-page-ai-pi-lab-rail-section[open]>summary::after{content:"▾"}' +
'.wolai-page-ai-pi-lab-rail-count{font-weight:600;color:#8a8378}' +
'.wolai-page-ai-pi-lab-rail-title{padding:8px 9px;border-bottom:1px solid #eee9e0;font-size:11px;font-weight:650;color:#5d594f;background:#faf9f6}' +
'.wolai-page-ai-pi-lab-tool-list{display:flex;flex-direction:column;gap:5px;padding:8px}' +
'.wolai-page-ai-pi-lab-tool-pill{border:1px solid #e6e2da;border-radius:7px;background:#fff;color:#42403a;padding:5px 7px;font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' +
'.wolai-page-ai-pi-lab-artifacts{display:flex;flex-direction:column;gap:6px;padding:8px;max-height:250px;overflow:auto}' +
'.wolai-page-ai-pi-lab-artifact{border:1px solid #e6e2da;border-radius:8px;background:#fff;color:#42403a;padding:7px;font-size:11px;line-height:1.42;overflow:hidden}' +
'.wolai-page-ai-pi-lab-artifact[data-kind="citation"]{border-color:#d9e6ff;background:#f7faff}.wolai-page-ai-pi-lab-artifact[data-kind="diff"]{border-color:#f0dcb7;background:#fff9ed}.wolai-page-ai-pi-lab-artifact[data-kind="mcp"]{border-color:#dfe6f2;background:#fafcff}' +
'.wolai-page-ai-pi-lab-artifact strong{display:block;font-size:11px;font-weight:700;color:#2f343b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wolai-page-ai-pi-lab-artifact span{display:block;margin-top:3px;color:#6f6a60;word-break:break-word}.wolai-page-ai-pi-lab-artifact-actions{display:flex;flex-wrap:wrap;gap:5px}.wolai-page-ai-pi-lab-artifact button,.wolai-page-ai-pi-lab-artifact a,.wolai-page-ai-pi-lab-rail-action{display:inline-flex;align-items:center;height:24px;margin-top:6px;border:1px solid #e1e4eb;border-radius:7px;background:#fff;color:#315d9f;text-decoration:none;padding:0 7px;font-size:11px;cursor:pointer}' +
'.wolai-page-ai-pi-lab-rail-action{margin:8px 8px 0}.wolai-page-ai-pi-lab-rail-action:hover,.wolai-page-ai-pi-lab-artifact button:hover,.wolai-page-ai-pi-lab-artifact a:hover{background:#f8fafc}' +
'.wolai-page-ai-pi-lab-receipts{display:flex;flex-direction:column;gap:5px;padding:8px;max-height:170px;overflow:auto}' +
'.wolai-page-ai-pi-lab-receipt{border-radius:7px;background:#f8f7f3;border:1px solid #e6e2da;padding:6px;font-size:11px;color:#4d4941}' +
'.wolai-page-ai-pi-lab-receipt[data-allowed="false"]{background:#fff0ee;border-color:#f2c4bd;color:#9f352c}' +
'.wolai-page-ai-pi-lab-ui-backdrop{position:relative;z-index:12;display:block;padding:10px 12px 0;background:#fff;pointer-events:none}' +
'.wolai-page-ai-pi-lab-ui-dialog{width:100%;border:1px solid #dfe4ec;border-radius:12px;background:#fff;box-shadow:0 10px 28px rgba(15,23,42,.12);overflow:hidden;color:#242424;pointer-events:auto}' +
'.wolai-page-ai-pi-lab-ui-dialog[data-collapsed="true"] .wolai-page-ai-pi-lab-ui-dialog-body,.wolai-page-ai-pi-lab-ui-dialog[data-collapsed="true"] .wolai-page-ai-pi-lab-ui-dialog-actions{display:none}' +
'.wolai-page-ai-pi-lab-ui-dialog-header{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:start;padding:11px 12px 9px;border-bottom:1px solid #edf0f5;background:#fafbfc}.wolai-page-ai-pi-lab-ui-dialog-header strong{display:block;font-size:13px;font-weight:720;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wolai-page-ai-pi-lab-ui-dialog-header span{display:block;margin-top:3px;font-size:12px;color:#6f6a60;white-space:pre-wrap}.wolai-page-ai-pi-lab-ui-collapse{width:28px;height:28px;border:1px solid #e1e4eb;border-radius:8px;background:#fff;color:#4a4f58;cursor:pointer}' +
'.wolai-page-ai-pi-lab-ui-dialog-body{padding:10px 12px;display:flex;flex-direction:column;gap:8px;max-height:min(320px,38vh);overflow:auto}.wolai-page-ai-pi-lab-ui-dialog-body input,.wolai-page-ai-pi-lab-ui-dialog-body textarea{width:100%;box-sizing:border-box;border:1px solid #ddd8cf;border-radius:8px;background:#fff;color:#242424;padding:8px 9px;font:13px/1.45 inherit;outline:none}.wolai-page-ai-pi-lab-ui-dialog-body textarea{min-height:76px;resize:vertical}' +
'.wolai-page-ai-pi-lab-ui-question{border:1px solid #edf0f5;border-radius:10px;background:#fff;padding:9px}.wolai-page-ai-pi-lab-ui-question-title{font-size:12px;font-weight:700;color:#2f343b;margin-bottom:3px}.wolai-page-ai-pi-lab-ui-question-prompt{font-size:12px;color:#6f6a60;white-space:pre-wrap;margin-bottom:7px}.wolai-page-ai-pi-lab-ui-option{width:100%;min-height:34px;border:1px solid #e1e4eb;border-radius:8px;background:#fff;color:#242424;text-align:left;padding:7px 9px;cursor:pointer;display:flex;align-items:flex-start;gap:8px}.wolai-page-ai-pi-lab-ui-option:hover,.wolai-page-ai-pi-lab-ui-option[data-selected="true"]{background:#f3f7ff;border-color:#bcd7ff}.wolai-page-ai-pi-lab-ui-option small{display:block;margin-top:2px;color:#737a86;font-size:11px;line-height:1.35}.wolai-page-ai-pi-lab-ui-option-mark{flex:0 0 auto;color:#5d6675}.wolai-page-ai-pi-lab-ui-note{border-top:1px solid #edf0f5;padding-top:8px}.wolai-page-ai-pi-lab-ui-note label{display:block;margin-bottom:4px;font-size:11px;color:#737a86}' +
'.wolai-page-ai-pi-lab-ui-dialog-actions{display:flex;justify-content:flex-end;gap:8px;padding:9px 12px 11px;border-top:1px solid #edf0f5}.wolai-page-ai-pi-lab-ui-dialog-actions button{height:30px;border:1px solid #ddd8cf;border-radius:8px;background:#fff;color:#4a4f58;padding:0 11px;cursor:pointer}.wolai-page-ai-pi-lab-ui-dialog-actions button[data-primary="true"]{border-color:#111827;background:#111827;color:#fff}' +
'.wolai-page-ai-pi-lab-ui-tui{margin:0;padding:8px 9px;border:1px solid #edf0f5;border-radius:8px;background:#fafbfc;color:#242833;white-space:pre-wrap;font:12px/1.45 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow:auto}.wolai-page-ai-pi-lab-ui-tui-options{display:flex;flex-direction:column;gap:6px}.wolai-page-ai-pi-lab-ui-option[data-custom-selected="true"]{background:#eef6ff;border-color:#9ec5fe}' +
'.wolai-page-ai-pi-lab-toast-stack{position:absolute;left:18px;right:18px;bottom:166px;z-index:13;display:flex;flex-direction:column;align-items:flex-end;gap:8px;pointer-events:none}.wolai-page-ai-pi-lab-toast{width:min(340px,100%);border:1px solid #dbe3ef;border-radius:10px;background:#fff;color:#242424;box-shadow:0 12px 34px rgba(15,23,42,.18);padding:10px 12px;font-size:13px;line-height:1.45;pointer-events:auto}.wolai-page-ai-pi-lab-toast[data-type="warning"]{border-color:#f0dcb7;background:#fff9ed}.wolai-page-ai-pi-lab-toast[data-type="error"]{border-color:#f2c4bd;background:#fff8f7}.wolai-page-ai-pi-lab-toast[data-type="success"]{border-color:#bfe6ac;background:#f4fff0}' +
'.wolai-page-ai-pi-lab-diagnostics{display:none;border-top:1px solid #e6e2da;background:#fff;flex:0 0 auto}' +
'.wolai-page-ai-pi-lab-drawer[data-config-open="true"] .wolai-page-ai-pi-lab-diagnostics{display:block}' +
'.wolai-page-ai-pi-lab-diagnostics>summary{cursor:pointer;padding:8px 12px;font-size:11px;color:#6f6a60}' +
'.wolai-page-ai-pi-lab-diagnostics pre{margin:0;padding:0 12px 10px;white-space:pre-wrap;word-break:break-word;font:11px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace;color:#5d594f}' +
'@media (max-width: 760px){.wolai-page-ai-pi-lab-drawer{left:10px;right:10px;top:58px;bottom:10px;width:auto}.wolai-page-ai-pi-lab-history-panel{width:min(320px,calc(100vw - 34px))}.wolai-page-ai-pi-lab-rail{left:14px;right:14px;top:auto;bottom:132px;width:auto;max-height:min(360px,calc(100% - 164px))}.wolai-page-ai-pi-lab-config{grid-template-columns:1fr}}' +
'@media (max-width: 520px){.wolai-page-ai-pi-lab-topbar{height:54px;padding:0 14px}.wolai-page-ai-pi-lab-title strong{font-size:21px}.wolai-page-ai-pi-lab-commandbar{height:50px;margin:0 14px 12px;gap:6px;overflow:hidden}.wolai-page-ai-pi-lab-history-panel{top:116px;left:12px;right:12px;max-height:min(300px,calc(100% - 300px))}.wolai-page-ai-pi-lab-history-row{grid-template-columns:1fr}.wolai-page-ai-pi-lab-history-actions{justify-content:flex-start}.wolai-page-ai-pi-lab-input{min-height:88px;padding:16px 58px 10px 18px;font-size:16px}.wolai-page-ai-pi-lab-modebar{min-height:48px;flex-wrap:nowrap;gap:6px;padding:6px 10px}.wolai-page-ai-pi-lab-model-control{flex:1 1 130px;min-width:92px;max-width:none}.wolai-page-ai-pi-lab-toast-stack{left:14px;right:14px;bottom:154px}.wolai-page-ai-pi-lab-toast{width:100%}}';
document.head.appendChild(style);
}
function escapeHtml(str) {
if (str == null) return '';
return String(str)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function escapeAttr(str) {
return escapeHtml(str).replace(/`/g, '`');
}
function renderMarkdownInline(text) {
var placeholders = [];
function stash(html) {
var key = '\u0000MD' + placeholders.length + '\u0000';
placeholders.push(html);
return key;
}
var value = escapeHtml(text || '');
value = value.replace(/`([^`]+)`/g, function (_, code) {
return stash('' + code + '');
});
value = value.replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, function (_, label, href) {
return stash('' + label + '');
});
value = value.replace(/\*\*([^*]+)\*\*/g, '$1');
value = value.replace(/(^|[^*])\*([^*\n]+)\*/g, '$1$2');
placeholders.forEach(function (html, index) {
value = value.replace(new RegExp('\u0000MD' + index + '\u0000', 'g'), html);
});
return value;
}
function isTableDivider(line) {
return /^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line || '');
}
function splitTableRow(line) {
var trimmed = String(line || '').trim();
if (trimmed.charAt(0) === '|') trimmed = trimmed.slice(1);
if (trimmed.charAt(trimmed.length - 1) === '|') trimmed = trimmed.slice(0, -1);
return trimmed.split('|').map(function (cell) { return cell.trim(); });
}
function renderMarkdownTable(lines, start) {
var header = splitTableRow(lines[start]);
var rows = [];
var i = start + 2;
while (i < lines.length && /\|/.test(lines[i] || '') && String(lines[i] || '').trim()) {
rows.push(splitTableRow(lines[i]));
i += 1;
}
return {
html: '
| ' + renderMarkdownInline(cell) + ' | '; }).join('') + '
|---|
| ' + renderMarkdownInline(row[index] || '') + ' | '; }).join('') + '
' + renderMarkdownInline(paragraph.join(' ')) + '
'); paragraph = []; } function flushList() { if (!list) return; html.push('<' + list.type + '>' + list.items.map(function (item) { return '' + escapeHtml(codeLines.join('\n')) + '');
inCode = false;
codeLines = [];
codeLang = '';
} else {
flushParagraph();
flushList();
inCode = true;
codeLang = fence[1] || '';
}
continue;
}
if (inCode) {
codeLines.push(line);
continue;
}
if (!trimmed) {
flushParagraph();
flushList();
continue;
}
if (i + 1 < lines.length && /\|/.test(line) && isTableDivider(lines[i + 1])) {
flushParagraph();
flushList();
var renderedTable = renderMarkdownTable(lines, i);
html.push(renderedTable.html);
i = renderedTable.next - 1;
continue;
}
var heading = trimmed.match(/^(#{1,3})\s+(.+)$/);
if (heading) {
flushParagraph();
flushList();
html.push('' + renderMarkdownInline(quote[1]) + ''); continue; } var unordered = trimmed.match(/^[-*+]\s+(.+)$/); var ordered = trimmed.match(/^\d+\.\s+(.+)$/); if (unordered || ordered) { flushParagraph(); var type = ordered ? 'ol' : 'ul'; if (!list || list.type !== type) flushList(); if (!list) list = { type: type, items: [] }; list.items.push((unordered || ordered)[1]); continue; } paragraph.push(trimmed); } if (inCode) html.push('
' + escapeHtml(codeLines.join('\n')) + '');
flushParagraph();
flushList();
return html.join('');
}
function el(tag, attrs, children) {
var elem = document.createElement(tag);
if (attrs) {
Object.keys(attrs).forEach(function (key) {
if (key === 'className') elem.className = attrs[key];
else if (key === 'textContent') elem.textContent = attrs[key];
else if (key === 'innerHTML') elem.innerHTML = attrs[key];
else if (key === 'style' && attrs[key] && typeof attrs[key] === 'object') Object.keys(attrs[key]).forEach(function (styleKey) { elem.style[styleKey] = attrs[key][styleKey]; });
else elem.setAttribute(key, attrs[key]);
});
}
if (children) {
(Array.isArray(children) ? children : [children]).forEach(function (child) {
if (typeof child === 'string') elem.appendChild(document.createTextNode(child));
else if (child instanceof Node) elem.appendChild(child);
});
}
return elem;
}
function compactJson(value) {
if (value == null || value === '') return '';
if (typeof value === 'string') return value;
try {
return JSON.stringify(value, null, 2);
} catch (_) {
return String(value);
}
}
function extractResultText(value) {
if (value == null) return '';
if (typeof value === 'string') return value;
var content = value.content;
if (Array.isArray(content)) {
var text = content.map(function (part) {
if (!part) return '';
if (typeof part === 'string') return part;
if (typeof part.text === 'string') return part.text;
return '';
}).filter(Boolean).join('');
if (text) return text;
}
return compactJson(value);
}
function truncateSingleLine(value, limit) {
var text = String(value || '').replace(/\s+/g, ' ').trim();
var max = limit || 120;
return text.length > max ? text.slice(0, max - 1) + '…' : text;
}
function copyTextToClipboard(text) {
text = String(text || '');
if (!text) return Promise.resolve(false);
if (navigator.clipboard && navigator.clipboard.writeText) {
return navigator.clipboard.writeText(text).then(function () { return true; }).catch(function () { return false; });
}
return Promise.resolve(false);
}
function messageToMarkdown(msg) {
if (!msg) return '';
var lines = [];
if (msg.text) lines.push(String(msg.text));
if (Array.isArray(msg.citations) && msg.citations.length) {
lines.push('', 'References:');
msg.citations.forEach(function (cit, index) {
lines.push((index + 1) + '. ' + (cit.title || cit.source || 'Citation') + (cit.url ? ' - ' + cit.url : ''));
});
}
if (msg.diffSummary && Array.isArray(msg.diffSummary.files) && msg.diffSummary.files.length) {
lines.push('', 'Changed files:');
msg.diffSummary.files.forEach(function (file) { lines.push('- ' + file); });
}
if (Array.isArray(msg.toolCalls) && msg.toolCalls.length) {
lines.push('', 'Tool calls:');
msg.toolCalls.forEach(function (tc) {
lines.push('- ' + toolDisplayName({ toolName: tc.name, args: tc.args, details: tc.details }) + ' · ' + (tc.status || ''));
});
}
return lines.join('\n').trim();
}
function currentSessionEventsUrl() {
if (!piLabState.sessionId) return '';
return API.SESSIONS + '/' + encodeURIComponent(piLabState.sessionId) + '/events?limit=1000';
}
function openCurrentSessionJsonl() {
var url = currentSessionEventsUrl();
if (!url) {
showPiToast('No Pi session to open', 'warning');
return Promise.resolve(false);
}
return fetch(url, { credentials: 'same-origin', cache: 'no-store' })
.then(function (response) {
if (!response.ok) throw new Error('Session events failed: ' + response.status);
return response.json();
})
.then(function (payload) {
var lines = (Array.isArray(payload.events) ? payload.events : []).map(function (event) {
return JSON.stringify({
eventType: event.eventType,
createdAt: event.createdAt,
payload: event.payload || {},
});
}).join('\n');
var blob = new Blob([lines + (lines ? '\n' : '')], { type: 'application/x-ndjson;charset=utf-8' });
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl, '_blank', 'noopener');
setTimeout(function () { URL.revokeObjectURL(objectUrl); }, 30000);
showPiToast('Session JSONL opened', 'success');
return true;
})
.catch(function (error) {
updateDiagnostics(error.message || '打开 session JSONL 失败');
showPiToast('Open session JSONL failed', 'error');
return false;
});
}
function normalizeToolCallId(payload) {
payload = payload || {};
return String(payload.toolCallId || payload.tool_call_id || payload.id || payload.callId || '').trim();
}
function normalizeToolName(payload) {
payload = payload || {};
return String(payload.toolName || payload.tool_name || payload.name || payload.tool || 'tool').trim();
}
function parseMcpArgs(args) {
if (!args) return {};
if (typeof args === 'string') {
try {
return JSON.parse(args);
} catch (_) {
return { raw: args };
}
}
return args;
}
function toolDisplayName(payload) {
var name = normalizeToolName(payload);
var args = parseMcpArgs(payload && payload.args);
var details = payload && payload.details ? payload.details : {};
var server = String(args.server || details.server || '').trim();
var tool = String(args.tool || details.tool || '').trim();
if (name === 'mcp' && server) return 'mcp:' + server + (tool ? '/' + tool : '/list');
return name;
}
function assistantToolCallPayload(msgData) {
if (!msgData) return null;
var toolCall = msgData.toolCall || null;
if (!toolCall && msgData.partial && msgData.partial.type === 'toolCall') toolCall = msgData.partial;
if (!toolCall && msgData.toolName) toolCall = msgData;
if (!toolCall && msgData.name) toolCall = msgData;
if (!toolCall || !(toolCall.name || toolCall.toolName || toolCall.tool_name || toolCall.id || toolCall.toolCallId)) return null;
return {
toolCallId: toolCall.toolCallId || toolCall.id || msgData.toolCallId || msgData.id || '',
toolName: toolCall.toolName || toolCall.tool_name || toolCall.name || msgData.toolName || msgData.name || '',
args: toolCall.arguments || toolCall.args || msgData.arguments || msgData.args || {},
details: msgData.details || null,
result: msgData.result || null,
};
}
function ensureToolCalls(msg) {
if (!msg.toolCalls) msg.toolCalls = [];
return msg.toolCalls;
}
function upsertToolCall(raw, status, patch) {
var viewModel = applyPiRunEvent({
type: 'tool_upsert',
payload: {
raw: raw || {},
status: status || 'running',
patch: patch || {},
},
});
updateMessages();
return viewModel.lastToolCall;
}
function renderToolCallCard(tc) {
var displayName = toolDisplayName({ toolName: tc.name, args: tc.args, details: tc.details });
var resultText = extractResultText(tc.result || tc.partialResult || '');
var summaryParts = [];
if (tc.args && Object.keys(tc.args).length) {
var args = parseMcpArgs(tc.args);
if (args.server) summaryParts.push('server=' + args.server);
if (args.tool) summaryParts.push('tool=' + args.tool);
}
if (resultText) summaryParts.push(truncateSingleLine(resultText, 140));
var item = el('div', {
className: 'wolai-page-ai-pi-lab-tool-call',
'data-page-ai-pi-lab-tool-card': tc.id || displayName || 'tool',
'data-page-ai-pi-lab-tool-call': displayName || 'tool',
'data-status': tc.status || '',
});
var policy = tc.toolPolicy || (tc.approvalRequired ? 'ask' : '');
var policyBadge = policy ? '' +
escapeHtml(tc.approvalRequired ? (tc.approvalConfirmed ? 'approved' : 'approval required') : policy) + '' : '';
item.appendChild(el('div', {
className: 'wolai-page-ai-pi-lab-tool-call-header',
'data-page-ai-pi-lab-tool-summary': 'true',
innerHTML: '' + escapeHtml(displayName || 'tool') + policyBadge + '' + escapeHtml(tc.status || '') + '',
}));
if (summaryParts.length) {
item.appendChild(el('div', {
className: 'wolai-page-ai-pi-lab-tool-call-summary-line',
'data-page-ai-pi-lab-tool-compact-summary': 'true',
}, summaryParts.join(' · ')));
}
var hasDetails = (tc.args && Object.keys(tc.args).length) || (tc.details && Object.keys(tc.details).length) || tc.partialResult || tc.result;
if (hasDetails) {
var details = el('details', {
className: 'wolai-page-ai-pi-lab-tool-call-details',
'data-page-ai-pi-lab-tool-details': displayName || 'tool',
});
details.appendChild(el('summary', {}, 'Input / Output / Raw'));
if (tc.args && Object.keys(tc.args).length) details.appendChild(el('pre', { textContent: 'Input\n' + compactJson(tc.args) }));
if (tc.details && Object.keys(tc.details).length) details.appendChild(el('pre', { textContent: 'Details\n' + compactJson(tc.details) }));
if (tc.partialResult && tc.status === 'running') details.appendChild(el('pre', { textContent: 'Partial output\n' + extractResultText(tc.partialResult) }));
if (tc.result) details.appendChild(el('pre', { textContent: 'Output\n' + resultText }));
item.appendChild(details);
}
return item;
}
function normalizeSlashes(value) {
return String(value || '').trim().replace(/\\/g, '/');
}
function currentUrl() {
try {
return new URL(window.location.href);
} catch (_) {
return new URL('/', window.location.origin);
}
}
function currentDocumentId() {
var fromBody = document.body && document.body.dataset ? String(document.body.dataset.documentId || '').trim() : '';
if (fromBody) return fromBody;
var pageTab = document.querySelector('[data-mnote-main-tab="page"]');
if (pageTab instanceof HTMLElement) {
var tabDocumentId = String(pageTab.getAttribute('data-document-id') || '').trim();
if (tabDocumentId) return tabDocumentId;
}
var match = currentUrl().pathname.match(/^\/documents\/([^/]+)/);
if (match) return decodeURIComponent(match[1]);
var missingPage = String(currentUrl().searchParams.get('missingPage') || currentUrl().searchParams.get('pageId') || '').trim();
return missingPage ? missingPage : '';
}
function currentWorkspaceId() {
return currentUrl().searchParams.get('workspaceId') || (document.body && document.body.dataset ? String(document.body.dataset.workspaceId || '').trim() : '');
}
function currentRootUri() {
var fromUrl = String(currentUrl().searchParams.get('rootUri') || '').trim();
if (fromUrl) return fromUrl;
var fromBody = document.body instanceof HTMLElement ? String(document.body.getAttribute('data-mnote-root-uri') || '').trim() : '';
if (fromBody) return fromBody;
return String((piLabState.session && piLabState.session.rootUri) || '').trim();
}
function localMarkdownRelativePathFromDocumentId(documentId) {
var value = String(documentId || '').trim();
if (!value.startsWith('local-md:')) return '';
var encoded = value.slice('local-md:'.length);
try {
return decodeURIComponent(encoded.replace(/~([0-9A-Fa-f]{2})/g, '%$1'));
} catch (_) {
return encoded.replace(/~2F/gi, '/');
}
}
function cssEscape(value) {
var text = String(value || '');
if (window.CSS && typeof window.CSS.escape === 'function') return window.CSS.escape(text);
return text.replace(/["\\]/g, '\\$&');
}
function currentSelectionText() {
try {
var selection = window.getSelection ? window.getSelection() : null;
return selection ? String(selection.toString() || '').trim() : '';
} catch (_) {
return '';
}
}
function activeEditorSnapshot() {
try {
var snapshot = window.__mnoteDocumentPaneRuntime
&& typeof window.__mnoteDocumentPaneRuntime.getOpenEditorsSnapshot === 'function'
? window.__mnoteDocumentPaneRuntime.getOpenEditorsSnapshot()
: null;
if (!snapshot || typeof snapshot !== 'object') return null;
if (snapshot.activeEditor) return snapshot.activeEditor;
var entries = []
.concat(Array.isArray(snapshot.editors) ? snapshot.editors : [])
.concat(Array.isArray(snapshot.resourceEditors) ? snapshot.resourceEditors : []);
return entries.find(function (entry) { return entry && entry.active === true; }) || entries[0] || null;
} catch (_) {
return null;
}
}
function activeFileTreeWorkspacePath(documentId) {
try {
var relativePath = localMarkdownRelativePathFromDocumentId(documentId);
var selector = '#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]';
if (relativePath) selector += '[data-local-relative-path="' + cssEscape(relativePath) + '"]';
var row = document.querySelector(selector);
var reader = window.__mnoteFileTreeRuntime && typeof window.__mnoteFileTreeRuntime.readWorkspacePathFromRow === 'function'
? window.__mnoteFileTreeRuntime.readWorkspacePathFromRow
: null;
if (row instanceof HTMLElement && reader) {
var workspacePath = reader(row);
if (workspacePath && typeof workspacePath === 'object') {
return Object.assign({}, workspacePath, {
relativePath: workspacePath.relativePath || row.getAttribute('data-local-relative-path') || '',
rootUri: workspacePath.rootUri || row.getAttribute('data-root-uri') || '',
sourceKind: workspacePath.sourceKind || row.getAttribute('data-source-kind') || '',
documentId: workspacePath.documentId || row.getAttribute('data-document-id') || documentId || '',
});
}
}
if (row instanceof HTMLElement) {
return {
relativePath: row.getAttribute('data-local-relative-path') || '',
rootUri: row.getAttribute('data-root-uri') || '',
sourceKind: row.getAttribute('data-source-kind') || '',
documentId: row.getAttribute('data-document-id') || documentId || '',
};
}
} catch (_) {}
return null;
}
function currentPageContext() {
var active = activeEditorSnapshot() || {};
var activeWorkspacePath = active.workspacePath && typeof active.workspacePath === 'object' ? active.workspacePath : {};
var documentId = String(activeWorkspacePath.documentId || active.documentId || currentDocumentId() || '').trim();
var fileTreeWorkspacePath = activeFileTreeWorkspacePath(documentId) || {};
var workspacePath = Object.assign({}, activeWorkspacePath, fileTreeWorkspacePath);
var session = piLabState.session || {};
var pagePath = normalizeSlashes(workspacePath.relativePath || workspacePath.path || active.relativePath || active.path || localMarkdownRelativePathFromDocumentId(documentId) || session.pagePath || '');
var rootUri = String(workspacePath.rootUri || active.rootUri || currentRootUri() || session.rootUri || '').trim();
var workspaceId = String(workspacePath.workspaceId || active.workspaceId || currentWorkspaceId() || session.workspaceId || '').trim();
var titleNode = document.querySelector('[data-page-title-current="true"]') || document.querySelector('.wolai-breadcrumb-current');
var title = String(active.title || workspacePath.title || (titleNode && titleNode.textContent) || document.title || '').trim();
var selection = currentSelectionText();
return {
pageId: documentId,
pagePath: pagePath,
pageTitle: title,
rootUri: rootUri,
workspaceId: workspaceId,
selection: selection,
};
}
function currentFolderPathFromPagePath(pagePath) {
var normalized = normalizeSlashes(pagePath || '').replace(/^\/+/, '');
if (!normalized) return null;
var parts = normalized.split('/').filter(Boolean);
if (parts.length <= 1) return '';
parts.pop();
return parts.join('/');
}
function contextSelectionState() {
if (!piLabState.contextSelection || typeof piLabState.contextSelection !== 'object') {
piLabState.contextSelection = {};
}
if (typeof piLabState.contextSelection.currentPage !== 'boolean') piLabState.contextSelection.currentPage = false;
if (typeof piLabState.contextSelection.currentFolder !== 'boolean') piLabState.contextSelection.currentFolder = false;
if (typeof piLabState.contextSelection.selection !== 'boolean') piLabState.contextSelection.selection = false;
if (typeof piLabState.contextSelection.lightrag !== 'boolean') piLabState.contextSelection.lightrag = false;
return piLabState.contextSelection;
}
function selectedContextRefs() {
var selection = contextSelectionState();
var refs = [];
if (selection.currentPage) refs.push('current_page');
if (selection.currentFolder) refs.push('folder');
if (selection.selection) refs.push('selection');
if (selection.lightrag) refs.push('lightrag');
return refs;
}
function selectedContextPayload(context) {
context = context || currentPageContext();
var selection = contextSelectionState();
var folderPath = currentFolderPathFromPagePath(context.pagePath);
return {
refs: selectedContextRefs(),
currentPage: selection.currentPage ? {
rootUri: context.rootUri || null,
workspaceId: context.workspaceId || null,
pagePath: context.pagePath || null,
pageTitle: context.pageTitle || null,
} : null,
currentFolder: selection.currentFolder ? {
rootUri: context.rootUri || null,
workspaceId: context.workspaceId || null,
folderPath: folderPath === null ? null : folderPath,
} : null,
selection: selection.selection ? {
text: context.selection || piLabState.selectionText || '',
source: 'mnote_sidebar_host',
} : null,
lightrag: selection.lightrag ? {
enabled: true,
provider: 'lightrag',
} : null,
};
}
function refreshSelectionSummary() {
var selection = currentSelectionText();
if (selection) piLabState.selectionText = selection;
var visibleSelection = selection || piLabState.selectionText;
piLabState.selectionSummary = visibleSelection ? ('已选中 ' + visibleSelection.length + ' 字') : '';
return visibleSelection;
}
function applyCurrentContextToState() {
var context = currentPageContext();
refreshSelectionSummary();
if (!piLabState.session) piLabState.session = {};
if (context.pagePath) piLabState.session.pagePath = context.pagePath;
if (context.pageTitle) piLabState.session.pageTitle = context.pageTitle;
if (context.rootUri) piLabState.session.rootUri = context.rootUri;
if (context.workspaceId) piLabState.session.workspaceId = context.workspaceId;
var folderPath = currentFolderPathFromPagePath(context.pagePath);
if (folderPath !== null) piLabState.session.folderPath = folderPath;
updateContextStrip();
return context;
}
function setContextQuickActive(kind, active) {
var selection = contextSelectionState();
if (kind === 'read-page') selection.currentPage = active !== false;
if (kind === 'current-folder') selection.currentFolder = active !== false;
if (kind === 'selection') selection.selection = active !== false;
if (kind === 'rag') selection.lightrag = active !== false;
updateContextStrip();
updateButtons();
}
function toggleContextQuick(kind) {
var selection = contextSelectionState();
var current = false;
if (kind === 'read-page') current = selection.currentPage;
else if (kind === 'current-folder') current = selection.currentFolder;
else if (kind === 'selection') current = selection.selection;
else if (kind === 'rag') current = selection.lightrag;
setContextQuickActive(kind, !current);
}
function currentModelLabel() {
var provider = piLabState.modelProvider || piLabState.defaultModelProvider || DEFAULT_MODEL_PROVIDER;
var modelId = piLabState.modelId || piLabState.defaultModelId || DEFAULT_MODEL_ID;
if (String(modelId).indexOf(provider + '/') === 0) modelId = String(modelId).slice(provider.length + 1);
return [provider, modelId].filter(Boolean).join('/');
}
function normalizeThinkingLevel(value) {
var level = String(value || '').trim().toLowerCase();
return ['off', 'minimal', 'low', 'medium', 'high', 'xhigh'].indexOf(level) >= 0 ? level : DEFAULT_THINKING_LEVEL;
}
function currentThinkingLabel() {
var labels = {
off: '关',
minimal: '极低',
low: '低',
medium: '中',
high: '高',
xhigh: '最高',
};
return labels[normalizeThinkingLevel(piLabState.thinkingLevel || piLabState.defaultThinkingLevel)] || '中';
}
function normalizePermissionMode(value) {
var mode = String(value || '').trim().toLowerCase();
if (mode === 'ask') return 'confirm';
return ['confirm', 'auto_edit', 'plan', 'full_access'].indexOf(mode) >= 0 ? mode : DEFAULT_PERMISSION_MODE;
}
function permissionModeOptions() {
return [
{ mode: 'confirm', icon: 'status', label: '变更前确认', description: '改文件、执行命令前先问我。' },
{ mode: 'auto_edit', icon: 'zap', label: '自动编辑', description: '授权目录内读写自动放行。' },
{ mode: 'plan', icon: 'settings', label: '计划模式', description: '只读分析,禁止写入和命令。' },
{ mode: 'full_access', icon: 'shield', label: '完全访问', description: '本会话内尽量不再确认。' },
];
}
function permissionModeLabel(mode) {
mode = normalizePermissionMode(mode);
var found = permissionModeOptions().filter(function (item) { return item.mode === mode; })[0];
return found ? found.label : '变更前确认';
}
function currentRuntimePolicy() {
return (piLabState.session && (piLabState.session.runtimePolicySnapshot || piLabState.session.runtimePolicy)) || {};
}
function toolPolicyValues() {
var policy = currentRuntimePolicy();
var policies = policy.mnoteToolPolicies || policy.mnote_tool_policies || {};
return Object.keys(policies).map(function (key) { return String(policies[key] || '').toLowerCase(); }).filter(Boolean);
}
function permissionSummary() {
var selectedMode = normalizePermissionMode(piLabState.permissionMode);
if (selectedMode === 'plan') return { label: '计划模式', tone: 'warn' };
if (selectedMode === 'auto_edit') return { label: '自动编辑', tone: 'ok' };
if (selectedMode === 'full_access') return { label: '完全访问', tone: 'ok' };
var values = toolPolicyValues();
var hasAsk = values.indexOf('ask') >= 0;
var hasDeny = values.indexOf('deny') >= 0;
var rootsText = String(piLabState.allowedRootsSummary || '').toLowerCase();
var readonly = rootsText.indexOf('read') >= 0 || rootsText.indexOf('只读') >= 0;
if (hasDeny || readonly) return { label: hasAsk ? '受限/审批' : '受限', tone: 'danger' };
if (hasAsk || !values.length) return { label: '变更前确认', tone: 'warn' };
return { label: '自动工具', tone: 'ok' };
}
function updateThinkingControl() {
if (!piLabPanelEl) return;
var thinkingSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-thinking]');
var level = normalizeThinkingLevel(piLabState.thinkingLevel || piLabState.defaultThinkingLevel);
piLabState.thinkingLevel = level;
if (thinkingSelect) {
if (thinkingSelect.value !== level) thinkingSelect.value = level;
thinkingSelect.title = '思考深度:' + currentThinkingLabel() + ';启动本次 Pi 会话时应用';
}
}
function updatePermissionControl() {
if (!piLabPanelEl) return;
var control = piLabPanelEl.querySelector('[data-page-ai-pi-lab-permission]');
var label = piLabPanelEl.querySelector('[data-page-ai-pi-lab-permission-label]');
var wrap = piLabPanelEl.querySelector('[data-page-ai-pi-lab-permission-wrap]');
var summary = permissionSummary();
if (label) label.textContent = summary.label;
if (control) {
control.setAttribute('data-tone', summary.tone || '');
control.setAttribute('data-active', piLabState.permissionMenuOpen ? 'true' : 'false');
control.title = 'Pi 模式:' + permissionModeLabel(piLabState.permissionMode) + ';目录范围:' + (piLabState.allowedRootsSummary || 'pending');
}
if (wrap) wrap.setAttribute('data-open', piLabState.permissionMenuOpen ? 'true' : 'false');
Array.prototype.slice.call(piLabPanelEl.querySelectorAll('[data-page-ai-pi-lab-permission-mode]')).forEach(function (node) {
node.setAttribute('data-active', node.getAttribute('data-page-ai-pi-lab-permission-mode') === normalizePermissionMode(piLabState.permissionMode) ? 'true' : 'false');
var check = node.querySelector('[data-page-ai-pi-lab-permission-check]');
if (check) check.textContent = node.getAttribute('data-active') === 'true' ? '✓' : '';
});
}
function setPermissionMenuOpen(open) {
piLabState.permissionMenuOpen = !!open;
updatePermissionControl();
}
function selectPermissionMode(mode) {
piLabState.permissionMode = normalizePermissionMode(mode);
setPermissionMenuOpen(false);
updatePermissionControl();
if (piLabState.sessionId && piLabState.status !== STATE_STREAMING && piLabState.status !== STATE_STARTING) {
return applyPermissionModeToRuntime();
}
if (piLabState.status === STATE_STREAMING) {
piLabState.pendingPermissionModeApply = true;
showPiToast('当前回复结束后自动应用:' + permissionModeLabel(piLabState.permissionMode), 'warning');
return Promise.resolve({ queued: true });
}
showPiToast('Pi 模式已切换为:' + permissionModeLabel(piLabState.permissionMode), 'info');
return Promise.resolve({ queued: false });
}
function maybeApplyPendingPermissionMode() {
if (!piLabState.pendingPermissionModeApply || piLabState.applyingPermissionMode) return;
if (!piLabState.sessionId || !piLabState.enabled) return;
if (piLabState.status === STATE_STREAMING || piLabState.status === STATE_STARTING) return;
window.setTimeout(function () {
if (!piLabState.pendingPermissionModeApply || piLabState.applyingPermissionMode) return;
if (piLabState.status === STATE_STREAMING || piLabState.status === STATE_STARTING) return;
applyPermissionModeToRuntime().catch(function () {});
}, 0);
}
function applyPermissionModeToRuntime() {
if (!piLabState.sessionId || !piLabState.enabled) return Promise.resolve({ skipped: true });
if (piLabState.applyingPermissionMode) {
piLabState.pendingPermissionModeApply = true;
return Promise.resolve({ queued: true });
}
var context = applyCurrentContextToState();
var nextMode = normalizePermissionMode(piLabState.permissionMode);
piLabState.pendingPermissionModeApply = false;
piLabState.applyingPermissionMode = true;
setState(STATE_STARTING);
updateDiagnostics('Applying Pi mode');
return fetch(API.START, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionId: piLabState.sessionId,
rootUri: context.rootUri || (piLabState.session && piLabState.session.rootUri) || undefined,
workspaceId: context.workspaceId || (piLabState.session && piLabState.session.workspaceId) || undefined,
pagePath: context.pagePath || (piLabState.session && piLabState.session.pagePath) || undefined,
pageTitle: context.pageTitle || (piLabState.session && piLabState.session.pageTitle) || undefined,
modelProvider: piLabState.modelProvider || piLabState.defaultModelProvider,
modelId: piLabState.modelId || piLabState.defaultModelId,
thinkingLevel: normalizeThinkingLevel(piLabState.thinkingLevel || piLabState.defaultThinkingLevel),
permissionMode: nextMode,
}),
})
.then(function (r) {
if (!r.ok) throw new Error('Mode switch failed: ' + r.status);
return r.json();
})
.then(function (data) {
var session = data.session || {};
piLabState.sessionId = session.sessionId || data.sessionId || piLabState.sessionId;
piLabState.providerSessionId = session.providerSessionId || data.providerSessionId || piLabState.providerSessionId;
piLabState.permissionMode = normalizePermissionMode(session.permissionMode || data.permissionMode || (session.runtimePolicySnapshot && session.runtimePolicySnapshot.permissionMode) || nextMode);
piLabState.session = session || piLabState.session || null;
piLabState.runtimeMode = session.runtimeMode || data.runtimeMode || piLabState.runtimeMode || null;
piLabState.runtimePid = session.runtimePid || data.pid || piLabState.runtimePid || null;
piLabState.piExtensionSources = data.piExtensionSources || piLabState.piExtensionSources || [];
piLabState.piExtensionToolNames = data.piExtensionToolNames || piLabState.piExtensionToolNames || [];
connectEventSource();
piLabState.applyingPermissionMode = false;
setState(STATE_STARTED);
updateDiagnostics('Pi mode applied');
updatePermissionControl();
showPiToast('Pi 模式已应用:' + permissionModeLabel(piLabState.permissionMode), 'success');
maybeApplyPendingPermissionMode();
return data;
})
.catch(function (error) {
piLabState.applyingPermissionMode = false;
setState(STATE_ERROR);
updateDiagnostics(error && error.message ? error.message : 'Pi mode switch failed');
showPiToast('Pi 模式切换失败', 'error');
throw error;
});
}
function setActionMenuOpen(open) {
piLabState.actionMenuOpen = !!open;
if (!piLabPanelEl) return;
var composer = piLabPanelEl.querySelector('.wolai-page-ai-pi-lab-composer');
var toggle = piLabPanelEl.querySelector('[data-page-ai-pi-lab-action-menu-toggle]');
if (composer) composer.setAttribute('data-menu-open', piLabState.actionMenuOpen ? 'true' : 'false');
if (toggle) toggle.setAttribute('data-active', piLabState.actionMenuOpen ? 'true' : 'false');
}
function closeActionMenu() {
setActionMenuOpen(false);
}
function permissionModeMenuHtml() {
return permissionModeOptions().map(function (item) {
var active = item.mode === normalizePermissionMode(piLabState.permissionMode);
return '';
}).join('');
}
function handleActionMenuAction(action) {
closeActionMenu();
if (action === 'read-page' || action === 'current-folder' || action === 'selection' || action === 'rag') {
handleQuickAction(action);
return;
}
if (action === 'directory-permission') {
window.location.assign('/user/ai#ai-admin-access');
return;
}
if (action === 'send-steer') {
sendCurrentInput({ streamingBehavior: 'steer' });
return;
}
if (action === 'send-followup') {
sendCurrentInput({ streamingBehavior: 'followUp' });
return;
}
if (action === 'plan-mode') {
var input = piLabPanelEl && piLabPanelEl.querySelector('[data-page-ai-pi-lab-input]');
var current = input ? input.value.trim() : '';
piLabState.permissionMode = 'plan';
updatePermissionControl();
if (piLabState.sessionId && piLabState.status !== STATE_STREAMING && piLabState.status !== STATE_STARTING) {
applyPermissionModeToRuntime().catch(function () {});
} else {
piLabState.pendingPermissionModeApply = true;
}
var planPrompt = current || '请先只做计划评审,不要修改文件。';
if (input) {
input.value = planPrompt;
input.focus();
updateButtons();
}
showPiToast('已切换到 MNote 计划评审模式;发送后由后端只读 wrapper 处理', 'info');
}
}
function applyModelControls() {
if (!piLabPanelEl) return;
var providerSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-model-provider]');
var modelSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-model-id]');
var bottomModelSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-model-id-bottom]');
var thinkingSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-thinking]');
var customInput = piLabPanelEl.querySelector('[data-page-ai-pi-lab-model-custom]');
if (providerSelect && providerSelect.value) piLabState.modelProvider = providerSelect.value;
if (customInput && customInput.value.trim()) piLabState.modelId = customInput.value.trim();
else if (modelSelect && modelSelect.value) piLabState.modelId = modelSelect.value;
else if (bottomModelSelect && bottomModelSelect.value) piLabState.modelId = bottomModelSelect.value;
if (thinkingSelect && thinkingSelect.value) piLabState.thinkingLevel = normalizeThinkingLevel(thinkingSelect.value);
piLabState.permissionMode = normalizePermissionMode(piLabState.permissionMode);
updateModelLabel();
updateThinkingControl();
updatePermissionControl();
}
function splitModelRef(value) {
var raw = String(value || '').trim();
var slash = raw.indexOf('/');
if (slash < 0) return { provider: DEFAULT_MODEL_PROVIDER, modelId: raw || DEFAULT_MODEL_ID };
return { provider: raw.slice(0, slash), modelId: raw.slice(slash + 1) };
}
function applyEffectiveConfig(data) {
data = data || {};
var defaultRef = splitModelRef(data.defaultModel || data.default_model || '');
piLabState.defaultModelProvider = defaultRef.provider || DEFAULT_MODEL_PROVIDER;
piLabState.defaultModelId = defaultRef.modelId || DEFAULT_MODEL_ID;
piLabState.defaultThinkingLevel = normalizeThinkingLevel(data.defaultThinkingLevel || data.default_thinking_level || piLabState.defaultThinkingLevel);
if (!piLabState.thinkingLevel) piLabState.thinkingLevel = piLabState.defaultThinkingLevel;
piLabState.modelOptions = Array.isArray(data.models) ? data.models : [];
if (Array.isArray(data.allowedRoots)) {
piLabState.allowedRootsSummary = data.allowedRoots.length + ' roots';
}
if (!piLabPanelEl) return;
var providerSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-model-provider]');
var modelSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-model-id]');
var bottomModelSelect = piLabPanelEl.querySelector('[data-page-ai-pi-lab-model-id-bottom]');
var providers = [];
piLabState.modelOptions.forEach(function (item) {
var provider = String(item.provider || DEFAULT_MODEL_PROVIDER);
if (providers.indexOf(provider) < 0) providers.push(provider);
});
if (!providers.length) providers.push(piLabState.defaultModelProvider);
if (providerSelect) {
providerSelect.innerHTML = providers.map(function (provider) {
return '';
}).join('');
providerSelect.value = piLabState.modelProvider || piLabState.defaultModelProvider;
}
var modelOptions = piLabState.modelOptions.length ? piLabState.modelOptions : [{
provider: piLabState.defaultModelProvider,
id: piLabState.defaultModelId,
name: piLabState.defaultModelId,
}];
var optionHtml = modelOptions.map(function (item) {
var id = String(item.id || item.modelId || item.name || DEFAULT_MODEL_ID);
var label = String(item.name || id);
return '';
}).join('');
if (modelSelect) modelSelect.innerHTML = optionHtml;
if (bottomModelSelect) bottomModelSelect.innerHTML = optionHtml;
updateModelLabel();
updateThinkingControl();
updateContextStrip();
}
function loadEffectiveConfig() {
return fetch(API.EFFECTIVE, { credentials: 'same-origin', cache: 'no-store' })
.then(function (response) {
if (!response.ok) throw new Error('Effective config failed: ' + response.status);
return response.json();
})
.then(function (data) {
applyEffectiveConfig(data);
return data;
});
}
function currentRuntimeLabel() {
var parts = [];
if (piLabState.runtimeMode) parts.push(piLabState.runtimeMode);
if (piLabState.runtimePid) parts.push('pid ' + piLabState.runtimePid);
return parts.join(' · ') || 'runtime pending';
}
function statusTone() {
if (!piLabState.enabled || piLabState.status === STATE_ERROR) return 'danger';
if (piLabState.status === STATE_STREAMING || piLabState.status === STATE_STARTED) return 'ok';
if (piLabState.status === STATE_STARTING || piLabState.status === STATE_ABORTED) return 'warn';
return '';
}
function statusText() {
if (!piLabState.enabled) return 'disabled';
if (piLabState.status === STATE_IDLE) return 'idle';
if (piLabState.status === STATE_STARTING) return 'starting';
if (piLabState.status === STATE_STARTED) return 'ready';
if (piLabState.status === STATE_STREAMING) return 'streaming';
if (piLabState.status === STATE_ABORTED) return 'aborted';
return 'error';
}
function piIcon(name) {
var icons = {
plus: '试试以下示例,或直接输入您的指令
' + '