@baimingtao/lbs-agent 1.3.0 → 1.5.0
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/bin/lbs.js +44 -31
- package/interfaces/cli/_impl/cli_theme.py +179 -146
- package/interfaces/cli/_impl/commands/chat_repl.py +83 -92
- package/interfaces/cli/_impl/commands/run_agent.py +20 -13
- package/interfaces/cli/_impl/commands/setup.py +20 -20
- package/package.json +1 -1
- package/runtime/orchestration/display.py +86 -62
- package/runtime/orchestration/loop/main_loop.py +25 -16
- package/scripts/init.js +31 -31
package/bin/lbs.js
CHANGED
|
@@ -46,21 +46,21 @@ const INIT_SCRIPT = path.join(PKG_ROOT, 'scripts', 'init.js');
|
|
|
46
46
|
|
|
47
47
|
// ── 颜色与图标 (对标 Hermes banner/colors) ─────────────────────
|
|
48
48
|
|
|
49
|
-
// ──
|
|
49
|
+
// ── Aurora Pink 配色 ───────────────────────────────────────────
|
|
50
50
|
|
|
51
51
|
const C = {
|
|
52
52
|
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', italic: '\x1b[3m',
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
pink: '\x1b[38;2;255;79;164m', // #FF4FA4
|
|
54
|
+
pinkL: '\x1b[38;2;255;167;213m', // #FFA7D5
|
|
55
|
+
purple: '\x1b[38;2;194;107;255m', // #C26BFF
|
|
56
|
+
blue: '\x1b[38;2;110;139;255m', // #6E8BFF
|
|
57
|
+
mint: '\x1b[38;2;152;216;200m', // #98D8C8
|
|
58
|
+
mintD: '\x1b[38;2;111;196;176m', // #6FC4B0
|
|
59
|
+
ok: '\x1b[38;2;62;229;138m', // #3EE58A
|
|
60
|
+
warn: '\x1b[38;2;255;179;71m', // #FFB347
|
|
61
|
+
err: '\x1b[38;2;255;107;129m', // #FF6B81
|
|
62
|
+
subtle: '\x1b[38;2;138;138;150m', // #8A8A96
|
|
63
|
+
faint: '\x1b[38;2;90;90;102m', // #5A5A66
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
function supportsColor() {
|
|
@@ -74,23 +74,36 @@ function paint(text, ...colors) {
|
|
|
74
74
|
return colors.join('') + text + C.reset;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
//
|
|
77
|
+
// 逐字符渐变
|
|
78
|
+
function gradient(text) {
|
|
79
|
+
if (!supportsColor()) return text;
|
|
80
|
+
const stops = [
|
|
81
|
+
'\x1b[38;2;255;79;164m', // pink
|
|
82
|
+
'\x1b[38;2;255;127;184m', // pink-pu
|
|
83
|
+
'\x1b[38;2;224;119;220m', // mid
|
|
84
|
+
'\x1b[38;2;194;107;255m', // purple
|
|
85
|
+
'\x1b[38;2;160;123;240m', // pu-blue
|
|
86
|
+
'\x1b[38;2;130;131;248m', // blue-ish
|
|
87
|
+
'\x1b[38;2;110;139;255m', // blue
|
|
88
|
+
];
|
|
89
|
+
const n = text.length;
|
|
90
|
+
let out = '';
|
|
91
|
+
for (let i = 0; i < n; i++) {
|
|
92
|
+
if (text[i] === ' ') { out += ' '; continue; }
|
|
93
|
+
const idx = Math.min(Math.floor(i / Math.max(n, 1) * stops.length), stops.length - 1);
|
|
94
|
+
out += stops[idx] + text[i] + C.reset;
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
78
98
|
|
|
79
|
-
|
|
80
|
-
'',
|
|
81
|
-
' ' + paint('╔══╗', C.sakura) + ' ' + paint('╔═══╗', C.mint) + ' ' + paint('╔═════╗', C.mint),
|
|
82
|
-
' ' + paint('║ ║', C.sakura) + ' ' + paint('║ ║', C.mint) + ' ' + paint('║ ╔═╝', C.mint),
|
|
83
|
-
' ' + paint('╠══╣', C.sakura) + ' ' + paint('╠═══╣', C.mint) + ' ' + paint('║ ╚═╗', C.mint),
|
|
84
|
-
' ' + paint('║ ║', C.sakura) + ' ' + paint('║ ║', C.mint) + ' ' + paint('╚═════╝', C.mint),
|
|
85
|
-
' ' + paint('╚══╝', C.sakura) + ' ' + paint('╚═══╝', C.mint) + ' ' + paint('AGENT', C.dim),
|
|
86
|
-
].join('\n');
|
|
99
|
+
// ── Banner — 极简留白 ─────────────────────────────────────────
|
|
87
100
|
|
|
88
101
|
function printBanner() {
|
|
89
|
-
|
|
90
|
-
console.log(
|
|
91
|
-
console.log(
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
console.log();
|
|
103
|
+
console.log(' ' + paint('✦', C.pink));
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(' ' + gradient('LBS Agent'));
|
|
106
|
+
console.log(' ' + paint('Autonomous AI Runtime', C.subtle));
|
|
94
107
|
console.log();
|
|
95
108
|
}
|
|
96
109
|
// ── 初始化检查 ─────────────────────────────────────────────────
|
|
@@ -102,13 +115,13 @@ function isInitialized() {
|
|
|
102
115
|
function ensureInitialized() {
|
|
103
116
|
if (isInitialized()) return true;
|
|
104
117
|
|
|
105
|
-
console.log(paint('⚙ ', C.
|
|
118
|
+
console.log(paint('⚙ ', C.pink) + paint('首次运行,正在初始化 LBS Agent...', C.bold));
|
|
106
119
|
console.log(paint(' 状态目录: ', C.dim) + paint(STATE_ROOT, C.mint));
|
|
107
120
|
console.log(paint(' 创建 Python 虚拟环境 + 安装依赖(约 1-2 分钟)', C.dim));
|
|
108
121
|
console.log();
|
|
109
122
|
|
|
110
123
|
if (!fs.existsSync(INIT_SCRIPT)) {
|
|
111
|
-
console.error(paint('✖ ', C.
|
|
124
|
+
console.error(paint('✖ ', C.err) + '初始化脚本不存在: ' + INIT_SCRIPT);
|
|
112
125
|
return false;
|
|
113
126
|
}
|
|
114
127
|
|
|
@@ -119,11 +132,11 @@ function ensureInitialized() {
|
|
|
119
132
|
});
|
|
120
133
|
|
|
121
134
|
if (result.status !== 0) {
|
|
122
|
-
console.error(paint('\n✖ ', C.
|
|
135
|
+
console.error(paint('\n✖ ', C.err) + '初始化失败');
|
|
123
136
|
return false;
|
|
124
137
|
}
|
|
125
138
|
|
|
126
|
-
console.log(paint('\n✓ ', C.
|
|
139
|
+
console.log(paint('\n✓ ', C.ok) + paint('初始化完成!', C.bold, C.ok));
|
|
127
140
|
console.log();
|
|
128
141
|
return true;
|
|
129
142
|
}
|
|
@@ -144,7 +157,7 @@ if (subcmd === 'init' || subcmd === '--init') {
|
|
|
144
157
|
});
|
|
145
158
|
process.exit(result.status || 0);
|
|
146
159
|
}
|
|
147
|
-
console.error(paint('✖ ', C.
|
|
160
|
+
console.error(paint('✖ ', C.err) + '初始化脚本不存在');
|
|
148
161
|
process.exit(1);
|
|
149
162
|
}
|
|
150
163
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
"""LBS CLI
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
green #45D6A3 → 翠绿 (成功)
|
|
1
|
+
"""LBS CLI Theme — Aurora Pink 现代终端设计系统。
|
|
2
|
+
|
|
3
|
+
设计原则:
|
|
4
|
+
留白 > 密集
|
|
5
|
+
符号 > 字符画
|
|
6
|
+
渐变 > 纯色
|
|
7
|
+
|
|
8
|
+
对标: Claude Code, Gemini CLI, Warp Terminal, Charm BubbleTea
|
|
10
9
|
"""
|
|
11
10
|
|
|
12
11
|
from __future__ import annotations
|
|
@@ -15,51 +14,37 @@ import os
|
|
|
15
14
|
import sys
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
# ──
|
|
19
|
-
|
|
20
|
-
class
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
OK = "\033[1;38;2;69;214;163m" # green bold
|
|
50
|
-
ERR = "\033[1;38;2;255;107;129m" # red bold
|
|
51
|
-
WARN = "\033[1;38;2;255;184;107m" # honey bold
|
|
52
|
-
INFO = "\033[38;2;101;168;255m" # blue
|
|
53
|
-
DIM_TEXT = "\033[2m"
|
|
54
|
-
|
|
55
|
-
# 渐变 (用多段 ANSI 近似模拟)
|
|
56
|
-
GRADIENT_PINK = "\033[1;38;2;255;183;197m"
|
|
57
|
-
GRADIENT_MINT = "\033[1;38;2;152;216;200m"
|
|
58
|
-
GRADIENT_VIOLET = "\033[1;38;2;110;90;168m"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def _use_color() -> bool:
|
|
62
|
-
"""检测是否使用彩色输出。"""
|
|
17
|
+
# ── 色彩 ───────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
class C:
|
|
20
|
+
RESET = "\033[0m"
|
|
21
|
+
BOLD = "\033[1m"
|
|
22
|
+
DIM = "\033[2m"
|
|
23
|
+
ITALIC = "\033[3m"
|
|
24
|
+
|
|
25
|
+
# Aurora Pink 渐变 (Pink → Purple → Blue)
|
|
26
|
+
PINK = "\033[38;2;255;79;164m" # #FF4FA4
|
|
27
|
+
PINK_L = "\033[38;2;255;167;213m" # #FFA7D5
|
|
28
|
+
PURPLE = "\033[38;2;194;107;255m" # #C26BFF
|
|
29
|
+
BLUE = "\033[38;2;110;139;255m" # #6E8BFF
|
|
30
|
+
|
|
31
|
+
# Mint (Web 端品牌色)
|
|
32
|
+
MINT = "\033[38;2;152;216;200m" # #98D8C8
|
|
33
|
+
MINT_D = "\033[38;2;111;196;176m" # #6FC4B0
|
|
34
|
+
|
|
35
|
+
# 状态
|
|
36
|
+
OK = "\033[38;2;62;229;138m" # #3EE58A
|
|
37
|
+
WARN = "\033[38;2;255;179;71m" # #FFB347
|
|
38
|
+
ERR = "\033[38;2;255;107;129m" # #FF6B81
|
|
39
|
+
INFO = "\033[38;2;101;168;255m" # #65A8FF
|
|
40
|
+
|
|
41
|
+
# 文字
|
|
42
|
+
TEXT = "\033[38;2;235;235;245m" # #EBEBF5 (正文)
|
|
43
|
+
SUBTLE = "\033[38;2;138;138;150m" # #8A8A96 (辅助)
|
|
44
|
+
FAINT = "\033[38;2;90;90;102m" # #5A5A66 (最弱)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _ok() -> bool:
|
|
63
48
|
if os.environ.get("NO_COLOR"):
|
|
64
49
|
return False
|
|
65
50
|
if os.environ.get("TERM") == "dumb":
|
|
@@ -67,134 +52,182 @@ def _use_color() -> bool:
|
|
|
67
52
|
return sys.stdout.isatty()
|
|
68
53
|
|
|
69
54
|
|
|
70
|
-
def
|
|
71
|
-
"""
|
|
72
|
-
if not
|
|
55
|
+
def p(text: str, *codes: str) -> str:
|
|
56
|
+
"""上色"""
|
|
57
|
+
if not _ok():
|
|
73
58
|
return text
|
|
74
|
-
return "".join(codes) + text +
|
|
59
|
+
return "".join(codes) + text + C.RESET
|
|
75
60
|
|
|
76
61
|
|
|
77
|
-
|
|
62
|
+
def dim(text: str) -> str:
|
|
63
|
+
return p(text, C.SUBTLE)
|
|
78
64
|
|
|
79
|
-
def sakura_label(text: str) -> str:
|
|
80
|
-
"""粉色标签 (用于品牌名)。"""
|
|
81
|
-
return paint(text, Theme.BOLD, Theme.SAKURA_DARK)
|
|
82
65
|
|
|
66
|
+
def faint(text: str) -> str:
|
|
67
|
+
return p(text, C.FAINT)
|
|
83
68
|
|
|
84
|
-
def mint_label(text: str) -> str:
|
|
85
|
-
"""薄荷标签 (用于成功状态)。"""
|
|
86
|
-
return paint(text, Theme.BOLD, Theme.MINT_DARK)
|
|
87
69
|
|
|
70
|
+
def pink(text: str) -> str:
|
|
71
|
+
return p(text, C.PINK)
|
|
88
72
|
|
|
89
|
-
def dim(text: str) -> str:
|
|
90
|
-
"""灰色辅助文字。"""
|
|
91
|
-
return paint(text, Theme.DIM)
|
|
92
73
|
|
|
74
|
+
def purple(text: str) -> str:
|
|
75
|
+
return p(text, C.PURPLE)
|
|
93
76
|
|
|
94
|
-
def agent_badge(name: str) -> str:
|
|
95
|
-
"""Agent 名称紫色胶囊。"""
|
|
96
|
-
return paint(f" {name} ", Theme.BOLD, Theme.VIOLET)
|
|
97
77
|
|
|
78
|
+
def mint(text: str) -> str:
|
|
79
|
+
return p(text, C.MINT_D)
|
|
98
80
|
|
|
99
|
-
def model_pill(model: str) -> str:
|
|
100
|
-
"""模型名粉色文字。"""
|
|
101
|
-
return paint(model, Theme.SAKURA_DARK)
|
|
102
81
|
|
|
82
|
+
def ok(text: str) -> str:
|
|
83
|
+
return p(text, C.OK)
|
|
103
84
|
|
|
104
|
-
def status_dot(ok: bool = True) -> str:
|
|
105
|
-
"""状态圆点。"""
|
|
106
|
-
color = Theme.GREEN if ok else Theme.RED
|
|
107
|
-
return paint("●", color)
|
|
108
85
|
|
|
86
|
+
def err(text: str) -> str:
|
|
87
|
+
return p(text, C.ERR)
|
|
109
88
|
|
|
110
|
-
def divider(width: int = 56) -> str:
|
|
111
|
-
"""分隔线 — 樱花粉渐变薄荷。"""
|
|
112
|
-
return paint("─" * width, Theme.SAKURA, Theme.DIM)
|
|
113
89
|
|
|
90
|
+
# ── 组件 ───────────────────────────────────────────────────────
|
|
114
91
|
|
|
115
|
-
def
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
92
|
+
def gradient_text(text: str) -> str:
|
|
93
|
+
"""Pink → Purple → Blue 逐字符渐变。"""
|
|
94
|
+
if not _ok():
|
|
95
|
+
return text
|
|
96
|
+
colors = [C.PINK, C.PINK_L, "\033[38;2;255;127;184m",
|
|
97
|
+
"\033[38;2;224;119;220m", C.PURPLE,
|
|
98
|
+
"\033[38;2;160;123;240m", C.BLUE]
|
|
99
|
+
n = len(text)
|
|
100
|
+
result = []
|
|
101
|
+
for i, ch in enumerate(text):
|
|
102
|
+
if ch == " ":
|
|
103
|
+
result.append(ch)
|
|
104
|
+
continue
|
|
105
|
+
idx = min(int(i / max(n, 1) * len(colors)), len(colors) - 1)
|
|
106
|
+
result.append(colors[idx] + ch + C.RESET)
|
|
107
|
+
return "".join(result)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def header() -> str:
|
|
111
|
+
"""启动 header — 极简留白风格。"""
|
|
112
|
+
lines = [
|
|
113
|
+
"",
|
|
114
|
+
f" {p('✦', C.PINK)}",
|
|
115
|
+
"",
|
|
116
|
+
f" {gradient_text('LBS Agent')}",
|
|
117
|
+
f" {dim('Autonomous AI Runtime')}",
|
|
118
|
+
"",
|
|
119
|
+
]
|
|
128
120
|
return "\n".join(lines)
|
|
129
121
|
|
|
130
122
|
|
|
131
|
-
def
|
|
132
|
-
"""
|
|
133
|
-
|
|
123
|
+
def session_card(rows: list[tuple[str, str]]) -> str:
|
|
124
|
+
"""Session 信息卡 — 上下布局,图标 + label + value。"""
|
|
125
|
+
icons = {
|
|
126
|
+
"session": "◇",
|
|
127
|
+
"workspace": "▸",
|
|
128
|
+
"agent": "◐",
|
|
129
|
+
"model": "✦",
|
|
130
|
+
"provider": "☁",
|
|
131
|
+
"memory": "◈",
|
|
132
|
+
"runtime": "⚙",
|
|
133
|
+
"turns": "⟩",
|
|
134
|
+
"elapsed": "⏱",
|
|
135
|
+
}
|
|
136
|
+
lines = []
|
|
137
|
+
for label, value in rows:
|
|
138
|
+
icon = icons.get(label, "·")
|
|
139
|
+
lines.append(f" {p(icon, C.PURPLE)} {dim(f'{label:11}')} {value}")
|
|
140
|
+
return "\n".join(lines)
|
|
134
141
|
|
|
135
142
|
|
|
136
|
-
def
|
|
137
|
-
"""
|
|
138
|
-
return
|
|
143
|
+
def separator(width: int = 52) -> str:
|
|
144
|
+
"""分隔线 — 最弱色"""
|
|
145
|
+
return p("─" * width, C.FAINT)
|
|
139
146
|
|
|
140
147
|
|
|
141
|
-
def
|
|
142
|
-
"""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
148
|
+
def prompt_symbol() -> str:
|
|
149
|
+
"""输入提示符"""
|
|
150
|
+
return p("❯", C.PINK)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def footer() -> str:
|
|
154
|
+
"""底部快捷键栏"""
|
|
155
|
+
keys = [
|
|
156
|
+
("↵", "Send"),
|
|
157
|
+
("↑↓", "History"),
|
|
158
|
+
("Tab", "Complete"),
|
|
159
|
+
("/help", "Commands"),
|
|
160
|
+
("Ctrl+C", "Exit"),
|
|
147
161
|
]
|
|
148
|
-
|
|
162
|
+
parts = []
|
|
163
|
+
for key, label in keys:
|
|
164
|
+
parts.append(f"{p(key, C.PURPLE)} {faint(label)}")
|
|
165
|
+
return faint(" ") + faint(" · ".join(parts))
|
|
149
166
|
|
|
150
167
|
|
|
151
|
-
def
|
|
152
|
-
"""
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
paint(t, Theme.MINT_DARK) for t in tools
|
|
158
|
-
)
|
|
159
|
-
lines = [
|
|
160
|
-
paint("━" * 56, Theme.SAKURA, Theme.DIM),
|
|
161
|
-
f" {paint('Agent', Theme.DIM)} {agent_badge(agent_display)}",
|
|
162
|
-
f" {paint('Model', Theme.DIM)} {model_str}",
|
|
163
|
-
f" {paint('Tools', Theme.DIM)} {tools_str}",
|
|
164
|
-
paint("━" * 56, Theme.SAKURA, Theme.DIM),
|
|
168
|
+
def usage_line(seconds: float, iterations: int, tools: int) -> str:
|
|
169
|
+
"""用量条"""
|
|
170
|
+
parts = [
|
|
171
|
+
p(f"{seconds:.1f}s", C.MINT_D),
|
|
172
|
+
faint(f"iter {iterations}"),
|
|
173
|
+
faint(f"tools {tools}"),
|
|
165
174
|
]
|
|
166
|
-
return "
|
|
175
|
+
return " " + faint(" · ").join(parts)
|
|
167
176
|
|
|
168
177
|
|
|
169
|
-
def
|
|
170
|
-
"""
|
|
171
|
-
|
|
172
|
-
return f"\n {paint('⟡', Theme.SAKURA)} {paint(f'iter {iteration}', Theme.BOLD, Theme.SAKURA_DARK)}{paint(f'/{max_iterations}', Theme.DIM)}{phase_str}"
|
|
178
|
+
def result_text(content: str) -> str:
|
|
179
|
+
"""最终结果"""
|
|
180
|
+
return p(content, C.TEXT)
|
|
173
181
|
|
|
174
182
|
|
|
175
|
-
def
|
|
176
|
-
"""
|
|
177
|
-
return
|
|
183
|
+
def error_text(content: str) -> str:
|
|
184
|
+
"""错误"""
|
|
185
|
+
return p(f"✕ {content}", C.ERR)
|
|
178
186
|
|
|
179
187
|
|
|
180
|
-
def
|
|
181
|
-
"""
|
|
182
|
-
return
|
|
188
|
+
def agent_tag(name: str) -> str:
|
|
189
|
+
"""Agent 标签"""
|
|
190
|
+
return p(f"◐ {name}", C.PURPLE)
|
|
183
191
|
|
|
184
192
|
|
|
185
|
-
def
|
|
186
|
-
"""
|
|
187
|
-
return
|
|
193
|
+
def model_tag(model: str) -> str:
|
|
194
|
+
"""模型标签"""
|
|
195
|
+
return p(f"✦ {model}", C.PINK)
|
|
188
196
|
|
|
189
197
|
|
|
190
|
-
def
|
|
191
|
-
"""
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
f" {
|
|
197
|
-
f" {
|
|
198
|
-
f" {
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
def react_header(agent_display: str, model_chain: list[str], tools: list[str]) -> str:
|
|
199
|
+
"""ReAct 任务头 — 极简留白"""
|
|
200
|
+
model_str = faint(" → ").join(pink(m) for m in model_chain)
|
|
201
|
+
tools_str = faint(", ").join(mint(t) for t in tools)
|
|
202
|
+
return "\n".join([
|
|
203
|
+
separator(),
|
|
204
|
+
f" {agent_tag(agent_display)}",
|
|
205
|
+
f" {model_str}",
|
|
206
|
+
f" {faint('tools')} {tools_str}" if tools_str else "",
|
|
207
|
+
separator(),
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def react_iter(iteration: int) -> str:
|
|
212
|
+
"""迭代标记"""
|
|
213
|
+
return f"\n {p('⟡', C.PINK)} {p(f'iter {iteration}', C.BOLD, C.PINK)}"
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def thinking_block(content: str) -> str:
|
|
217
|
+
"""思考块"""
|
|
218
|
+
return p(content, C.ITALIC, C.MINT_D)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def tool_card(name: str, status: str, duration: str = "") -> str:
|
|
222
|
+
"""工具调用卡片"""
|
|
223
|
+
status_color = C.OK if status == "ok" else C.ERR
|
|
224
|
+
icon = "✓" if status == "ok" else "✕"
|
|
225
|
+
dur = f" {faint(duration)}" if duration else ""
|
|
226
|
+
return f" {p(icon, status_color)} {faint(name)}{dur}"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def timeline_item(timestamp: str, label: str, success: bool = True) -> str:
|
|
230
|
+
"""时间线条目"""
|
|
231
|
+
icon = "✓" if success else "✕"
|
|
232
|
+
color = C.OK if success else C.ERR
|
|
233
|
+
return f" {faint(timestamp)} {p(icon, color)} {dim(label)}"
|