const flows = { agent: { kicker: 'AGENT REQUEST / 7 HOPS', description: '浏览器的已登录请求由 Web 转换成兼容 OpenAI 的流式调用;Runtime 独立完成上下文构建、模型调用、工具循环和证据校验。', nodes: ['browser', 'web', 'runtime', 'provider', 'gateway', 'workspace', 'store'] }, identity: { kicker: 'IDENTITY / SHORT-LIVED & SERVER-SIDE', description: 'Web 先验证登录用户并签发短期身份;Runtime 验证一次后,在每次 Gateway 工具调用前重新签发,避免长任务复用过期令牌。', nodes: ['browser', 'web', 'runtime', 'gateway', 'workspace'] }, tool: { kicker: 'TOOL EXECUTION / POLICY BEFORE DOCKER', description: 'Runtime 校验并调度工具,Gateway 再执行身份、路径和资源策略,最后才通过 SSH Docker 进入该用户唯一的工作区。', nodes: ['runtime', 'gateway', 'workspace', 'store'] }, file: { kicker: 'FILE DELIVERY / AUTHENTICATED STREAM', description: '用户在工作区抽屉发起浏览或下载;Web 验证会话后请求 Gateway,文件或归档以流式响应返回,浏览器从不接触内部服务密钥。', nodes: ['browser', 'web', 'gateway', 'workspace'] } }; const stages = { context: { kicker: 'CONTEXT / recent-visible-v1', title: '把有限上下文留给真正影响下一步的内容', description: '移除旧的工具详情渲染,按模型预算保留最新可见消息,再注入最多 8 条持久记忆。上下文策略和 Agent Loop 分别版本化。', points: [ '去掉历史消息中的工具 UI 标记', '最近消息优先,按字符预算截断', '记忆只作为补充上下文,不直接取得执行权限' ] }, model: { kicker: 'MODEL / SERVER-SIDE CATALOG', title: '模型提出下一步,平台控制它能看到和能花费什么', description: 'Runtime 根据公开模型 ID 选择固定 provider、上下文预算、输出预算和循环上限。用户不能从前端注入密钥或任意模型参数。', points: ['支持流式内容与工具调用', '模型和推理强度明确标注', 'provider 差异在传输层统一'] }, validate: { kicker: 'VALIDATE / NORMALIZE BEFORE TRUST', title: '先把模型输出变成可约束的数据,再决定是否执行', description: '工具名称、参数、批次数量和权限都在执行前检查。一次模型响应最多接受 8 个工具调用,未知或畸形调用会成为可见错误。', points: ['JSON 参数规范化', '工具白名单与参数校验', '重复无进展调用守卫'] }, schedule: { kicker: 'SCHEDULER / safe-parallel-v1', title: '读取可以加速,写入必须保持可预测', description: '连续且标记为 parallel_safe 的工具并发执行;任何文件写入、命令或状态变更都会形成串行边界,结果按请求顺序返回模型。', points: ['只读调用成组并发', '变更操作严格串行', '批次结果仍保持稳定顺序'] }, execute: { kicker: 'EXECUTE / TOOLS + BOUNDED DELEGATION', title: '所有能力都通过可记录、可验证的工具边界发生', description: '文件、命令、Git、计划和记忆都有结构化工具。Workspace 工具经 Gateway 进入用户容器;只读子任务可以受限委派。', points: ['工作区工具与状态工具分离', '每次调用记录开始和结果事件', '子 Agent 不得再次委派'] }, evidence: { kicker: 'EVIDENCE / COMPLETION IS A POLICY', title: '“完成”不是一句自然语言,而是一组已经发生的事实', description: '如果任务要求生成文件、修改代码或给出测量报告,循环必须看到相应的写入、验证和精确结果。证据不足时会继续循环或明确失败。', points: ['变更后必须有后续验证', '失败命令必须修复并重跑', '报告必须晚于来源或实验结果'] } }; const statusLabels = { baseline: '当前基线', validated: '已验证', backlog: '待实验' }; let experimentData = []; let activeExperimentFilter = 'all'; function activateFlow(flowName) { const flow = flows[flowName]; if (!flow) return; document.querySelectorAll('.flow-tab').forEach((button) => { const active = button.dataset.flow === flowName; button.classList.toggle('is-active', active); button.setAttribute('aria-selected', String(active)); }); document.querySelectorAll('.system-node').forEach((node) => { node.classList.toggle('is-flow-active', flow.nodes.includes(node.dataset.node)); }); document.querySelector('.system-map')?.classList.add('has-selection'); document.querySelector('#flow-kicker').textContent = flow.kicker; document.querySelector('#flow-description').textContent = flow.description; } function activateStage(stageName) { const stage = stages[stageName]; if (!stage) return; document.querySelectorAll('.loop-stage').forEach((button) => { const active = button.dataset.stage === stageName; button.classList.toggle('is-active', active); button.setAttribute('aria-selected', String(active)); }); document.querySelector('#stage-kicker').textContent = stage.kicker; document.querySelector('#stage-title').textContent = stage.title; document.querySelector('#stage-description').textContent = stage.description; const list = document.querySelector('#stage-points'); list.replaceChildren( ...stage.points.map((point) => { const item = document.createElement('li'); item.textContent = point; return item; }) ); } function experimentCard(experiment) { const article = document.createElement('article'); article.className = 'experiment-card'; const meta = document.createElement('div'); meta.className = 'experiment-meta'; const id = document.createElement('span'); id.textContent = experiment.id; const badge = document.createElement('span'); badge.className = `status-badge status-${experiment.status}`; badge.textContent = statusLabels[experiment.status]; meta.append(id, badge); const title = document.createElement('h3'); title.textContent = experiment.title; const summary = document.createElement('p'); summary.textContent = experiment.summary; const footer = document.createElement('div'); footer.className = 'experiment-footer'; [experiment.area, experiment.version, ...(experiment.metrics || [])].filter(Boolean).forEach((text) => { const tag = document.createElement('span'); tag.textContent = text; footer.append(tag); }); article.append(meta, title, summary, footer); return article; } function renderExperiments() { const query = document.querySelector('#experiment-search').value.trim().toLocaleLowerCase('zh-CN'); const filtered = experimentData.filter((experiment) => { const statusMatches = activeExperimentFilter === 'all' || experiment.status === activeExperimentFilter; const haystack = [ experiment.id, experiment.title, experiment.summary, experiment.area, experiment.version, ...(experiment.metrics || []) ] .join(' ') .toLocaleLowerCase('zh-CN'); return statusMatches && (!query || haystack.includes(query)); }); const grid = document.querySelector('#experiment-grid'); if (filtered.length === 0) { const empty = document.createElement('article'); empty.className = 'experiment-empty'; empty.textContent = '没有匹配的实验记录。'; grid.replaceChildren(empty); } else { grid.replaceChildren(...filtered.map(experimentCard)); } document.querySelector('#experiment-count').textContent = `${String(filtered.length).padStart(2, '0')} / ${String(experimentData.length).padStart(2, '0')} RECORDS`; } async function loadExperiments() { const grid = document.querySelector('#experiment-grid'); try { const response = await fetch('./experiments.json', { cache: 'no-cache' }); if (!response.ok) throw new Error(`HTTP ${response.status}`); experimentData = await response.json(); renderExperiments(); } catch (error) { const failure = document.createElement('article'); failure.className = 'experiment-empty'; failure.textContent = '实验台账暂时无法读取,请查看仓库中的 docs/experiments.md。'; grid.replaceChildren(failure); document.querySelector('#experiment-count').textContent = 'DATA UNAVAILABLE'; } } function setActiveNavigation(sectionId) { document.querySelectorAll('.nav-link').forEach((link) => { link.classList.toggle('is-active', link.getAttribute('href') === `#${sectionId}`); }); } document.querySelectorAll('.flow-tab').forEach((button) => { button.addEventListener('click', () => activateFlow(button.dataset.flow)); }); document.querySelectorAll('.loop-stage').forEach((button) => { button.addEventListener('click', () => activateStage(button.dataset.stage)); }); document.querySelectorAll('.filter-button').forEach((button) => { button.addEventListener('click', () => { activeExperimentFilter = button.dataset.filter; document .querySelectorAll('.filter-button') .forEach((candidate) => candidate.classList.toggle('is-active', candidate === button)); renderExperiments(); }); }); document.querySelector('#experiment-search').addEventListener('input', renderExperiments); const toggle = document.querySelector('.nav-toggle'); const sidebar = document.querySelector('.sidebar'); toggle.addEventListener('click', () => { const isOpen = sidebar.classList.toggle('is-open'); toggle.setAttribute('aria-expanded', String(isOpen)); }); document.querySelectorAll('.nav-link').forEach((link) => { link.addEventListener('click', () => { sidebar.classList.remove('is-open'); toggle.setAttribute('aria-expanded', 'false'); }); }); if ('IntersectionObserver' in window) { const observer = new IntersectionObserver( (entries) => { const visible = entries .filter((entry) => entry.isIntersecting) .sort((a, b) => b.intersectionRatio - a.intersectionRatio); if (visible[0]) setActiveNavigation(visible[0].target.id); }, { rootMargin: '-20% 0px -62% 0px', threshold: [0.05, 0.3] } ); document.querySelectorAll('main > section[id]').forEach((section) => observer.observe(section)); } activateFlow('agent'); activateStage('context'); loadExperiments();