feat: add persistent multi-model workers and orchestration budgets
This commit is contained in:
+40
-2
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user