codebee 0.1.54 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +3 -4
- package/app/core/builtin_agent.py +67 -26
- package/app/core/jobs.py +21 -2
- package/app/core/knowledge.py +21 -4
- package/app/core/modelhub.py +33 -4
- package/app/core/pipeline.py +143 -61
- package/app/core/planner.py +27 -13
- package/app/core/runner.py +280 -78
- package/app/core/store.py +64 -27
- package/app/core/zentao.py +26 -6
- package/app/ui/app.js +23 -13
- package/app/ui/board.css +360 -262
- package/app/ui/board.html +119 -41
- package/app/ui/board.js +60 -14
- package/app/ui/i18n.js +2698 -2659
- package/app/ui/index.html +2 -0
- package/package.json +1 -1
package/app/ui/board.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
|
-
<title>CodeBee
|
|
6
|
+
<title>CodeBee · 任务驾驶舱</title>
|
|
7
7
|
<link rel="icon" href="/icons/icon-192.png">
|
|
8
8
|
<link rel="stylesheet" href="/board.css">
|
|
9
9
|
</head>
|
|
@@ -12,70 +12,148 @@
|
|
|
12
12
|
<!-- 远程访问令牌门(本机免输;与主界面共用 orch.token) -->
|
|
13
13
|
<div id="gate" class="gate hidden">
|
|
14
14
|
<div class="gate-box">
|
|
15
|
+
<div class="gate-mark" aria-hidden="true"><span></span><span></span><span></span></div>
|
|
15
16
|
<div class="gate-title" data-i18n="需要访问令牌">需要访问令牌</div>
|
|
16
17
|
<div class="gate-sub" data-i18n="启动 CodeBee 时控制台会显示">启动 CodeBee 时控制台会显示</div>
|
|
17
18
|
<input id="gate-token" type="password" data-i18n-ph="访问令牌" placeholder="访问令牌" autocomplete="off">
|
|
18
|
-
<button id="gate-ok" data-i18n="进入大屏">进入大屏</button>
|
|
19
|
+
<button id="gate-ok" type="button" data-i18n="进入大屏">进入大屏</button>
|
|
19
20
|
<div id="gate-err" class="gate-err"></div>
|
|
20
21
|
</div>
|
|
21
22
|
</div>
|
|
22
23
|
|
|
23
24
|
<header id="hd">
|
|
24
25
|
<div class="hd-brand">
|
|
25
|
-
<div class="
|
|
26
|
+
<div class="brand-mark" aria-hidden="true"><i></i><i></i><i></i><b></b></div>
|
|
27
|
+
<div class="brand-copy">
|
|
28
|
+
<div class="brand-kicker">CODEBEE / OPERATIONS</div>
|
|
29
|
+
<div class="hd-name" data-i18n="任务驾驶舱">任务驾驶舱</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="hd-center">
|
|
33
|
+
<span class="live-pip"></span>
|
|
34
|
+
<span data-i18n="实时监控">实时监控</span>
|
|
35
|
+
<span class="hd-sep">/</span>
|
|
36
|
+
<span id="hd-updated" class="hd-updated" data-i18n="同步中">同步中</span>
|
|
26
37
|
</div>
|
|
27
38
|
<div class="hd-right">
|
|
28
|
-
<div id="hd-pool" class="hd-pill" title="执行池占用">—</div>
|
|
39
|
+
<div id="hd-pool" class="hd-pill" title="执行池占用" data-i18n-title="执行池占用">—</div>
|
|
29
40
|
<div id="hd-health" class="hd-pill warn hidden" title=""></div>
|
|
30
41
|
<div id="hd-conn" class="hd-pill off hidden" data-i18n="连接断开">连接断开</div>
|
|
31
42
|
<div id="hd-clock" class="hd-clock">--:--:--</div>
|
|
32
43
|
</div>
|
|
33
44
|
</header>
|
|
34
45
|
|
|
35
|
-
<
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
<
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
<ellipse cx="35" cy="12" rx="9" ry="6" fill="#2a3a58" opacity=".8"/>
|
|
54
|
-
<circle cx="24" cy="11" r="6" fill="#0d1626"/>
|
|
55
|
-
</svg>
|
|
56
|
-
<div class="idle-t1" data-i18n="蜂巢空闲 · 等蜂回巢">蜂巢空闲 · 等蜂回巢</div>
|
|
57
|
-
<div class="idle-t2" data-i18n="没有正在运行的任务,新任务在主界面创建后会实时出现在这里">没有正在运行的任务,新任务在主界面创建后会实时出现在这里</div>
|
|
46
|
+
<main id="board">
|
|
47
|
+
<section id="overview" class="overview panel">
|
|
48
|
+
<div class="overview-copy">
|
|
49
|
+
<div class="eyebrow"><span></span><span data-i18n="蜂群状态">蜂群状态</span></div>
|
|
50
|
+
<div class="overview-line">
|
|
51
|
+
<div>
|
|
52
|
+
<h1 id="hero-state" data-i18n="蜂群待命">蜂群待命</h1>
|
|
53
|
+
<p id="hero-copy" data-i18n="没有正在运行的任务,新任务在主界面创建后会实时出现在这里">没有正在运行的任务,新任务在主界面创建后会实时出现在这里</p>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="hero-count">
|
|
56
|
+
<strong id="hero-live-count">0</strong>
|
|
57
|
+
<span data-i18n="个活动单元">个活动单元</span>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="overview-foot">
|
|
61
|
+
<span class="signal-chip"><i></i><span id="hero-signal" data-i18n="系统状态良好">系统状态良好</span></span>
|
|
62
|
+
<span class="overview-note" data-i18n="实时聚合 · 每 4 秒刷新">实时聚合 · 每 4 秒刷新</span>
|
|
63
|
+
</div>
|
|
58
64
|
</div>
|
|
59
|
-
<div
|
|
60
|
-
<
|
|
61
|
-
<
|
|
65
|
+
<div class="overview-visual" aria-hidden="true">
|
|
66
|
+
<div class="orbit orbit-a"></div>
|
|
67
|
+
<div class="orbit orbit-b"></div>
|
|
68
|
+
<div class="orbit-dot dot-a"></div>
|
|
69
|
+
<div class="orbit-dot dot-b"></div>
|
|
70
|
+
<div class="orbit-dot dot-c"></div>
|
|
71
|
+
<div class="core-glow"></div>
|
|
72
|
+
<div class="overview-core"><strong id="orb-number">0</strong><span>ACTIVE</span></div>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="overview-aside">
|
|
75
|
+
<div class="aside-label" data-i18n="执行池">执行池</div>
|
|
76
|
+
<div class="pool-meter"><i id="pool-meter-fill"></i></div>
|
|
77
|
+
<div class="pool-readout"><strong id="pool-alive">0</strong><span>/</span><span id="pool-target">0</span><em data-i18n="在线槽位">在线槽位</em></div>
|
|
78
|
+
<div class="aside-divider"></div>
|
|
79
|
+
<div class="aside-row"><span data-i18n="队列等待">队列等待</span><b id="overview-queued">0</b></div>
|
|
80
|
+
<div class="aside-row"><span data-i18n="今日成功率">今日成功率</span><b id="overview-success">—</b></div>
|
|
62
81
|
</div>
|
|
63
82
|
</section>
|
|
64
83
|
|
|
65
|
-
<
|
|
66
|
-
<div class="
|
|
67
|
-
<div class="
|
|
68
|
-
<div
|
|
84
|
+
<section id="kpis" aria-label="核心指标" data-i18n-aria="核心指标">
|
|
85
|
+
<div class="kpi k-run">
|
|
86
|
+
<div class="kpi-head"><span data-i18n="运行中">运行中</span><i class="kpi-icon"></i></div>
|
|
87
|
+
<div class="k-num" id="k-running">0</div>
|
|
88
|
+
<div class="kpi-foot"><span data-i18n="当前活动">当前活动</span><b>LIVE</b></div>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="kpi k-queue">
|
|
91
|
+
<div class="kpi-head"><span data-i18n="排队中">排队中</span><i class="kpi-icon"></i></div>
|
|
92
|
+
<div class="k-num" id="k-queued">0</div>
|
|
93
|
+
<div class="kpi-foot"><span data-i18n="等待调度">等待调度</span><b>QUEUE</b></div>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="kpi k-done">
|
|
96
|
+
<div class="kpi-head"><span data-i18n="今日完成">今日完成</span><i class="kpi-icon"></i></div>
|
|
97
|
+
<div class="k-num" id="k-done">0</div>
|
|
98
|
+
<div class="kpi-foot"><span data-i18n="完成运行">完成运行</span><b>DONE</b></div>
|
|
69
99
|
</div>
|
|
70
|
-
<div class="
|
|
71
|
-
<div class="
|
|
72
|
-
<div
|
|
100
|
+
<div class="kpi k-fail">
|
|
101
|
+
<div class="kpi-head"><span data-i18n="今日失败">今日失败</span><i class="kpi-icon"></i></div>
|
|
102
|
+
<div class="k-num" id="k-failed">0</div>
|
|
103
|
+
<div class="kpi-foot"><span data-i18n="需要关注">需要关注</span><b>ALERT</b></div>
|
|
73
104
|
</div>
|
|
74
|
-
<div class="
|
|
75
|
-
<div class="
|
|
76
|
-
<div
|
|
105
|
+
<div class="kpi k-tok">
|
|
106
|
+
<div class="kpi-head"><span data-i18n="今日 tokens">今日 tokens</span><i class="kpi-icon"></i></div>
|
|
107
|
+
<div class="k-num" id="k-tokens">0</div>
|
|
108
|
+
<div class="kpi-foot"><span data-i18n="模型消耗">模型消耗</span><b>USAGE</b></div>
|
|
77
109
|
</div>
|
|
78
|
-
|
|
110
|
+
<div class="kpi k-cost">
|
|
111
|
+
<div class="kpi-head"><span data-i18n="今日成本">今日成本</span><i class="kpi-icon"></i></div>
|
|
112
|
+
<div class="k-num" id="k-cost">$0.00</div>
|
|
113
|
+
<div class="kpi-foot"><span data-i18n="运行成本">运行成本</span><b>COST</b></div>
|
|
114
|
+
</div>
|
|
115
|
+
</section>
|
|
116
|
+
|
|
117
|
+
<section id="main">
|
|
118
|
+
<section id="wall" class="panel live-panel">
|
|
119
|
+
<header class="panel-head">
|
|
120
|
+
<div>
|
|
121
|
+
<div class="eyebrow"><span></span><span data-i18n="实时任务流">实时任务流</span></div>
|
|
122
|
+
<h2 data-i18n="运行中任务">运行中任务</h2>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="panel-head-right">
|
|
125
|
+
<span id="wall-count" class="live-count">0 ACTIVE</span>
|
|
126
|
+
<span id="wall-mode" class="mode-label" data-i18n="监控中">监控中</span>
|
|
127
|
+
</div>
|
|
128
|
+
</header>
|
|
129
|
+
<div id="wall-cards"></div>
|
|
130
|
+
<div id="wall-empty" class="wall-empty hidden">
|
|
131
|
+
<div class="empty-orbit" aria-hidden="true"><i></i><i></i><i></i><b>0</b></div>
|
|
132
|
+
<div class="idle-t1" data-i18n="队列已清空">队列已清空</div>
|
|
133
|
+
<div class="idle-t2" data-i18n="等待新的任务接入蜂巢">等待新的任务接入蜂巢</div>
|
|
134
|
+
<div class="empty-meta"><span><i></i><b data-i18n="工作池就绪">工作池就绪</b></span><span><i></i><b data-i18n="监控在线">监控在线</b></span></div>
|
|
135
|
+
</div>
|
|
136
|
+
<div id="queue-row" class="queue-row hidden">
|
|
137
|
+
<div class="q-label"><span class="q-mark"></span><span data-i18n="排队等待">排队等待</span><b id="queue-count">0</b></div>
|
|
138
|
+
<span id="queue-chips"></span>
|
|
139
|
+
</div>
|
|
140
|
+
</section>
|
|
141
|
+
|
|
142
|
+
<aside id="rail">
|
|
143
|
+
<section class="rail-card rail-trend panel">
|
|
144
|
+
<div class="rail-head"><div><div class="eyebrow"><span></span><span data-i18n="资源脉冲">资源脉冲</span></div><h3 data-i18n="近 7 日 tokens">近 7 日 tokens</h3></div><span class="rail-badge">7 DAYS</span></div>
|
|
145
|
+
<div id="trend" class="trend"></div>
|
|
146
|
+
</section>
|
|
147
|
+
<section class="rail-card rail-models panel">
|
|
148
|
+
<div class="rail-head"><div><div class="eyebrow"><span></span><span data-i18n="模型分布">模型分布</span></div><h3 data-i18n="近 7 日模型 TOP5">近 7 日模型 TOP5</h3></div><span class="rail-badge">TOP 5</span></div>
|
|
149
|
+
<div id="models" class="models"></div>
|
|
150
|
+
</section>
|
|
151
|
+
<section class="rail-card rail-recent panel grow">
|
|
152
|
+
<div class="rail-head"><div><div class="eyebrow"><span></span><span data-i18n="事件日志">事件日志</span></div><h3 data-i18n="最近动态">最近动态</h3></div><span id="recent-count" class="rail-badge">—</span></div>
|
|
153
|
+
<div id="recent" class="recent"></div>
|
|
154
|
+
</section>
|
|
155
|
+
</aside>
|
|
156
|
+
</section>
|
|
79
157
|
</main>
|
|
80
158
|
|
|
81
159
|
<script src="/i18n.js"></script>
|
package/app/ui/board.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const $ = (s) => document.querySelector(s);
|
|
6
|
-
const t = (
|
|
6
|
+
const t = (...a) => (window.t ? window.t(...a) : a[0]); // i18n.js 先于本脚本加载;透传占位符参数({0}/{1})
|
|
7
7
|
const POLL_MS = 4000;
|
|
8
8
|
|
|
9
9
|
// URL ?lang=en|zh 可覆盖语言(i18n.js 已按 localStorage 自动 apply 过一次,
|
|
@@ -77,6 +77,7 @@ async function poll() {
|
|
|
77
77
|
if (connLost) { connLost = false; $("#hd-conn").classList.add("hidden"); }
|
|
78
78
|
} catch (e) {
|
|
79
79
|
if (!connLost) { connLost = true; $("#hd-conn").classList.remove("hidden"); }
|
|
80
|
+
$("#hd-updated").textContent = t("重试连接中");
|
|
80
81
|
return;
|
|
81
82
|
}
|
|
82
83
|
render(data);
|
|
@@ -86,43 +87,87 @@ async function poll() {
|
|
|
86
87
|
const cardEls = new Map(); // task_id -> 卡元素(复用防闪烁)
|
|
87
88
|
|
|
88
89
|
function render(d) {
|
|
90
|
+
const running = Array.isArray(d.running) ? d.running : [];
|
|
91
|
+
const queued = Array.isArray(d.queued) ? d.queued : [];
|
|
92
|
+
const recent = Array.isArray(d.recent) ? d.recent : [];
|
|
93
|
+
const usage = d.usage_today || {};
|
|
94
|
+
const pool = d.pool || {};
|
|
95
|
+
const health = Array.isArray(d.health) ? d.health : [];
|
|
96
|
+
|
|
89
97
|
// KPI
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
$("#k-
|
|
94
|
-
$("#k-
|
|
95
|
-
$("#k-
|
|
98
|
+
const done = Number(d.today_done) || 0;
|
|
99
|
+
const failed = Number(d.today_failed) || 0;
|
|
100
|
+
const finished = done + failed;
|
|
101
|
+
$("#k-running").textContent = running.length;
|
|
102
|
+
$("#k-queued").textContent = queued.length;
|
|
103
|
+
$("#k-done").textContent = done;
|
|
104
|
+
$("#k-failed").textContent = failed;
|
|
105
|
+
$("#k-tokens").textContent = fmtTokens(usage.tokens);
|
|
106
|
+
$("#k-cost").textContent = fmtCost(usage.cost_usd);
|
|
107
|
+
|
|
108
|
+
// 总态势 Hero:把“有没有活”变成第一眼可读的状态,而不是只重复 KPI。
|
|
109
|
+
const heroActive = running.length > 0;
|
|
110
|
+
$("#hero-live-count").textContent = running.length;
|
|
111
|
+
$("#orb-number").textContent = running.length;
|
|
112
|
+
$("#hero-state").textContent = heroActive ? t("蜂群运行中") : t("蜂群待命");
|
|
113
|
+
if (heroActive) {
|
|
114
|
+
let copy = t("当前有 {0} 个任务正在并行执行", running.length);
|
|
115
|
+
if (queued.length) copy += " · " + t("有 {0} 个任务等待调度", queued.length);
|
|
116
|
+
$("#hero-copy").textContent = copy;
|
|
117
|
+
} else if (queued.length) {
|
|
118
|
+
$("#hero-copy").textContent = t("有 {0} 个任务等待调度", queued.length);
|
|
119
|
+
} else {
|
|
120
|
+
$("#hero-copy").textContent = t("没有正在运行的任务,新任务在主界面创建后会实时出现在这里");
|
|
121
|
+
}
|
|
96
122
|
|
|
97
123
|
// 顶栏
|
|
98
|
-
const pool = d.pool || {};
|
|
99
124
|
$("#hd-pool").textContent = t("蜂巢") + " " + (pool.alive || 0) + "/" + (pool.target || 0)
|
|
100
125
|
+ " · " + t("对话") + " " + (pool.chat_alive || 0) + "/" + (pool.chat_pool || 0);
|
|
101
|
-
const
|
|
126
|
+
const syncTime = String(d.now || "").slice(11, 19) || new Date().toLocaleTimeString([], { hour12: false });
|
|
127
|
+
$("#hd-updated").textContent = t("已同步") + " · " + syncTime;
|
|
128
|
+
const downs = health.filter((h) => h.status === "down" && !h.silenced);
|
|
102
129
|
const hp = $("#hd-health");
|
|
103
130
|
if (downs.length) {
|
|
104
131
|
hp.classList.remove("hidden");
|
|
105
132
|
hp.textContent = "⚠ " + downs.map((h) => h.provider).join("、") + " " + t("异常");
|
|
106
133
|
hp.title = downs.map((h) => (h.provider + " " + (h.model || "")).trim()).join("\n");
|
|
134
|
+
$("#hero-signal").textContent = t("有 {0} 个服务异常", downs.length);
|
|
135
|
+
$("#overview").classList.add("has-alert");
|
|
107
136
|
} else {
|
|
108
137
|
hp.classList.add("hidden");
|
|
138
|
+
$("#hero-signal").textContent = t("系统状态良好");
|
|
139
|
+
$("#overview").classList.remove("has-alert");
|
|
109
140
|
}
|
|
110
141
|
|
|
142
|
+
// 执行池 / 概览侧栏
|
|
143
|
+
const alive = Math.max(0, Number(pool.alive) || 0);
|
|
144
|
+
const target = Math.max(0, Number(pool.target) || 0);
|
|
145
|
+
const fill = target ? Math.min(100, alive / target * 100) : 0;
|
|
146
|
+
$("#pool-meter-fill").style.width = fill + "%";
|
|
147
|
+
$("#pool-alive").textContent = alive;
|
|
148
|
+
$("#pool-target").textContent = target;
|
|
149
|
+
$("#overview-queued").textContent = queued.length;
|
|
150
|
+
$("#overview-success").textContent = finished ? Math.round(done / finished * 100) + "%" : "—";
|
|
151
|
+
|
|
111
152
|
renderWall(d);
|
|
112
153
|
renderTrend(d.trend || []);
|
|
113
154
|
renderModels(d.models || []);
|
|
114
|
-
renderRecent(
|
|
155
|
+
renderRecent(recent);
|
|
115
156
|
}
|
|
116
157
|
|
|
117
158
|
function renderWall(d) {
|
|
118
159
|
const wrap = $("#wall-cards");
|
|
119
160
|
const empty = $("#wall-empty");
|
|
120
|
-
const
|
|
161
|
+
const running = Array.isArray(d.running) ? d.running : [];
|
|
162
|
+
const queued = Array.isArray(d.queued) ? d.queued : [];
|
|
163
|
+
const has = running.length > 0;
|
|
164
|
+
$("#wall-count").textContent = running.length + " ACTIVE";
|
|
165
|
+
$("#queue-count").textContent = queued.length;
|
|
121
166
|
empty.classList.toggle("hidden", has);
|
|
122
167
|
wrap.classList.toggle("hidden", !has);
|
|
123
168
|
|
|
124
169
|
const seen = new Set();
|
|
125
|
-
for (const c of
|
|
170
|
+
for (const c of running) {
|
|
126
171
|
seen.add(c.task_id);
|
|
127
172
|
let el = cardEls.get(c.task_id);
|
|
128
173
|
if (!el) {
|
|
@@ -204,8 +249,8 @@ function renderWall(d) {
|
|
|
204
249
|
|
|
205
250
|
// 排队条
|
|
206
251
|
const qr = $("#queue-row");
|
|
207
|
-
qr.classList.toggle("hidden", !
|
|
208
|
-
$("#queue-chips").innerHTML =
|
|
252
|
+
qr.classList.toggle("hidden", !queued.length);
|
|
253
|
+
$("#queue-chips").innerHTML = queued.map((q) =>
|
|
209
254
|
'<span class="chip" title="' + esc(q.title) + '">' + esc(q.title) + "</span>").join("");
|
|
210
255
|
}
|
|
211
256
|
|
|
@@ -232,6 +277,7 @@ function renderModels(models) {
|
|
|
232
277
|
|
|
233
278
|
function renderRecent(recent) {
|
|
234
279
|
const box = $("#recent");
|
|
280
|
+
$("#recent-count").textContent = recent.length + " " + t("条事件");
|
|
235
281
|
if (!recent.length) { box.innerHTML = '<div class="empty">' + t("还没有已完成的运行") + "</div>"; return; }
|
|
236
282
|
const dot = { done: "done", failed: "failed", cancelled: "cancelled" };
|
|
237
283
|
box.innerHTML = recent.map((r) => {
|