feat: add persistent multi-model workers and orchestration budgets

This commit is contained in:
WHC
2026-10-19 11:29:26 +08:00
parent 235652604d
commit 143dba203b
14 changed files with 1043 additions and 32 deletions
+40 -2
View File
@@ -2327,6 +2327,14 @@ async function showExtensions(focus) {
catch (e) { return toast('读取扩展失败:' + errMsg(e)); }
const box = document.createDocumentFragment();
box.appendChild(el('h3', null, '扩展'));
if (d.worker_budget) {
const b = d.worker_budget;
box.appendChild(el('p', 'muted tiny',
'本回合子任务 ' + b.delegations + '/' + b.max_tasks +
' · 请求 ' + b.requests + '/' + b.max_requests +
' · 缓存 ' + (b.cached_tokens == null ? '未知' : b.cached_tokens + '/' + b.prompt_tokens) +
(b.cost == null ? '' : ' · ' + b.currency + b.cost.toFixed(6))));
}
if (!d.enabled)
box.appendChild(el('p', 'warn-text tiny', '当前工具集是 minimal:MCP、插件、skills 和子代理都不加载。在运行设置里换回 default,再点"重新加载"。'));
box.appendChild(el('p', 'muted tiny', (d.report ? '已加载:' + reportZh(d.report) + '。' : '没有加载任何扩展。') +
@@ -2334,6 +2342,30 @@ async function showExtensions(focus) {
? '这个工作区已信任:它的 .agent/plugins 和 .agent/mcp.json 会加载。'
: '这个工作区未信任:它的 .agent/plugins 和 .agent/mcp.json 不会加载(配置目录里的照常加载)。')));
const acts = el('div', 'buttons left');
acts.appendChild(Object.assign(el('button', null, '模型与 worker 配置'), {
onclick: async () => {
try {
const config = await getJSON('api/workers/config');
const editor = el('div');
editor.appendChild(el('h3', null, 'Worker 配置'));
editor.appendChild(el('p', null, 'profiles 定义 provider/model/effort,roles 将角色绑定到档案;预算为 max_steps/max_tasks/max_requests。orchestrate 开启编排模式。密钥使用已有平台凭据。'));
const text = el('textarea');
text.rows = 20; text.style.width = '100%';
text.value = JSON.stringify(config, null, 2);
editor.appendChild(text);
editor.appendChild(Object.assign(el('button', null, '保存'), {
onclick: async () => {
try {
await post('api/workers/config', JSON.parse(text.value));
toast('Worker 配置已保存', 'ok');
showExtensions('agents');
} catch (e) { toastErr(e); }
},
}));
openModal(editor, true);
} catch (e) { toastErr(e); }
},
}));
const act = async (path, body, done) => {
try {
const r = await post(path, body);
@@ -2392,12 +2424,18 @@ async function showExtensions(focus) {
(s) => row(s.name, null, null, s.source, s.desc, useBtn('使用', '/skill ' + s.name + ' ')));
section('agents', '子代理角色', d.roles || [],
d.task_tool ? '没有角色。' : 'task 工具没开(工具集是 minimal)。',
(r) => row(r.name, r.read_only ? '只读' : null, null, r.source + (r.model ? ' · ' + r.model : ''), r.desc,
(r) => row(r.name, r.read_only ? '只读' : null, null, r.source + ' · ' + (r.profile || r.model || '继承主模型'), r.desc,
d.task_tool ? useBtn('交给它', '用 ' + r.name + ' 子代理(task 工具)来 ') : null));
section('runs', '本会话的子代理运行', d.runs || [], '这个会话还没有用过子代理。',
(r) => row(r.role + ' · ' + r.file, RUN_ZH[r.status] || r.status,
r.status === 'done' ? 'ok' : r.status === 'error' ? 'bad' : '',
r.steps + ' 步 · ' + r.tools + ' 次工具 · ' + fmtSecs(r.ms || 0), r.desc));
(r.provider || '') + '/' + (r.model || '') + ' · ' +
r.requests + '/' + r.max_steps + ' 请求 · ' + r.tools + ' 次工具 · ' +
'缓存 ' + (r.cached_tokens == null ? '未知' : r.cached_tokens + '/' + r.prompt_tokens + ' tokens') +
' · ' + fmtSecs(r.ms || 0) + (r.cost == null ? '' : ' · ' + r.currency + r.cost.toFixed(6)), r.desc,
r.status === 'running' ? Object.assign(el('button', 'danger', '取消'), {
onclick: () => act('api/workers/cancel', { worker_id: r.file }, '已请求取消'),
}) : useBtn('续接', '继续 worker_id=' + r.file + ' 的任务:')));
const close = el('div', 'buttons');
close.appendChild(Object.assign(el('button', null, '关闭'), { onclick: closeModal }));
box.appendChild(close);