@baimingtao/lbs-agent 1.4.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.
|
@@ -78,25 +78,32 @@ def cmd_run_agent(config: AppConfig, agent_name: str, task: str) -> None:
|
|
|
78
78
|
except Exception as e:
|
|
79
79
|
print(f" [WARN] session save failed: {e}")
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
print(f"
|
|
85
|
-
print(f"
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
from runtime.orchestration.display import green, red, faint, pink, bold, color, Colors
|
|
82
|
+
sep = color("─" * 52, Colors.FAINT)
|
|
83
|
+
icon = green("✓") if result.success else red("✕")
|
|
84
|
+
print(f"\n{sep}")
|
|
85
|
+
print(f" {icon} {bold(result.agent_name)}")
|
|
86
|
+
parts = [
|
|
87
|
+
faint(f"iter {result.iterations}"),
|
|
88
|
+
faint(f"tools {result.total_tool_calls}"),
|
|
89
|
+
color(f"{result.duration_seconds:.1f}s", Colors.MINT_D),
|
|
90
|
+
]
|
|
91
|
+
print(" " + faint(" · ").join(parts))
|
|
89
92
|
if result.error:
|
|
90
|
-
print(f"
|
|
91
|
-
print(
|
|
92
|
-
print(
|
|
93
|
+
print(f" {red(result.error[:200])}")
|
|
94
|
+
print(sep)
|
|
95
|
+
print()
|
|
96
|
+
if result.content:
|
|
97
|
+
print(result.content)
|
|
98
|
+
else:
|
|
99
|
+
print(faint("(无输出)"))
|
|
93
100
|
print()
|
|
94
101
|
|
|
95
102
|
if result.steps:
|
|
96
|
-
print(f"
|
|
103
|
+
print(f" {faint('trace')}")
|
|
97
104
|
for step in result.steps:
|
|
98
105
|
tools = ", ".join(t.name for t in step.tool_execs) if step.tool_execs else "-"
|
|
99
|
-
print(f"
|
|
106
|
+
print(f" {faint(f'{step.iteration:02d}')} {pink('·')} {faint(tools)}")
|
|
100
107
|
print()
|
|
101
108
|
finally:
|
|
102
109
|
container.shutdown()
|
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
4. format_result — 格式化最终结果
|
|
9
|
-
5. Spinner — 简易加载动画
|
|
10
|
-
6. print_box — 框线输出
|
|
1
|
+
"""LBS Display — Aurora Pink 现代终端输出。
|
|
2
|
+
|
|
3
|
+
重写 display.py 为 Aurora 主题:
|
|
4
|
+
旧: [工具] [结果] [思考] [迭代 N/M (ReAct)]
|
|
5
|
+
新: ⟡ iter N · 工具名(参数) · ✓ 结果 · ✦ 思考
|
|
6
|
+
|
|
7
|
+
所有颜色统一到 cli_theme 的 Aurora Pink 渐变体系。
|
|
11
8
|
"""
|
|
12
9
|
|
|
13
10
|
from __future__ import annotations
|
|
@@ -19,27 +16,44 @@ import time
|
|
|
19
16
|
from typing import Optional
|
|
20
17
|
|
|
21
18
|
|
|
22
|
-
# ── ANSI
|
|
19
|
+
# ── ANSI True Color (Aurora Pink) ──────────────────────────────
|
|
23
20
|
|
|
24
21
|
class Colors:
|
|
25
|
-
RESET
|
|
26
|
-
BOLD
|
|
27
|
-
DIM
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
#
|
|
22
|
+
RESET = "\033[0m"
|
|
23
|
+
BOLD = "\033[1m"
|
|
24
|
+
DIM = "\033[2m"
|
|
25
|
+
ITALIC = "\033[3m"
|
|
26
|
+
|
|
27
|
+
# Aurora 渐变
|
|
28
|
+
PINK = "\033[38;2;255;79;164m"
|
|
29
|
+
PINK_L = "\033[38;2;255;167;213m"
|
|
30
|
+
PURPLE = "\033[38;2;194;107;255m"
|
|
31
|
+
BLUE = "\033[38;2;110;139;255m"
|
|
32
|
+
|
|
33
|
+
# Mint
|
|
34
|
+
MINT = "\033[38;2;152;216;200m"
|
|
35
|
+
MINT_D = "\033[38;2;111;196;176m"
|
|
36
|
+
|
|
37
|
+
# 状态
|
|
38
|
+
GREEN = "\033[38;2;62;229;138m"
|
|
39
|
+
RED = "\033[38;2;255;107;129m"
|
|
40
|
+
YELLOW = "\033[38;2;255;179;71m"
|
|
41
|
+
|
|
42
|
+
# 文字
|
|
43
|
+
TEXT = "\033[38;2;235;235;245m"
|
|
44
|
+
SUBTLE = "\033[38;2;138;138;150m"
|
|
45
|
+
FAINT = "\033[38;2;90;90;102m"
|
|
46
|
+
|
|
47
|
+
# 兼容旧引用
|
|
48
|
+
CYAN = MINT_D
|
|
49
|
+
GRAY = SUBTLE
|
|
50
|
+
MAGENTA = PURPLE
|
|
51
|
+
|
|
37
52
|
_enabled: Optional[bool] = None
|
|
38
53
|
|
|
39
54
|
@classmethod
|
|
40
55
|
def _check(cls) -> bool:
|
|
41
56
|
if cls._enabled is None:
|
|
42
|
-
# Windows 10+ 支持 ANSI,但需要启用
|
|
43
57
|
if sys.platform == "win32":
|
|
44
58
|
try:
|
|
45
59
|
import ctypes
|
|
@@ -59,8 +73,9 @@ class Colors:
|
|
|
59
73
|
return text
|
|
60
74
|
|
|
61
75
|
|
|
76
|
+
# ── 快捷颜色函数 ───────────────────────────────────────────────
|
|
77
|
+
|
|
62
78
|
def color(text: str, c: str) -> str:
|
|
63
|
-
"""快捷函数:给文本加颜色。"""
|
|
64
79
|
return Colors.wrap(text, c)
|
|
65
80
|
|
|
66
81
|
def green(text: str) -> str:
|
|
@@ -73,78 +88,82 @@ def yellow(text: str) -> str:
|
|
|
73
88
|
return Colors.wrap(text, Colors.YELLOW)
|
|
74
89
|
|
|
75
90
|
def cyan(text: str) -> str:
|
|
76
|
-
return Colors.wrap(text, Colors.
|
|
91
|
+
return Colors.wrap(text, Colors.MINT_D)
|
|
77
92
|
|
|
78
93
|
def gray(text: str) -> str:
|
|
79
|
-
return Colors.wrap(text, Colors.
|
|
94
|
+
return Colors.wrap(text, Colors.SUBTLE)
|
|
80
95
|
|
|
81
96
|
def bold(text: str) -> str:
|
|
82
97
|
return Colors.wrap(text, Colors.BOLD)
|
|
83
98
|
|
|
99
|
+
def pink(text: str) -> str:
|
|
100
|
+
return Colors.wrap(text, Colors.PINK)
|
|
84
101
|
|
|
85
|
-
|
|
102
|
+
def purple(text: str) -> str:
|
|
103
|
+
return Colors.wrap(text, Colors.PURPLE)
|
|
104
|
+
|
|
105
|
+
def mint(text: str) -> str:
|
|
106
|
+
return Colors.wrap(text, Colors.MINT_D)
|
|
107
|
+
|
|
108
|
+
def faint(text: str) -> str:
|
|
109
|
+
return Colors.wrap(text, Colors.FAINT)
|
|
86
110
|
|
|
87
|
-
def format_title(task: str, max_len: int = 50) -> str:
|
|
88
|
-
"""从任务文本生成简短标题。
|
|
89
111
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
3. 去掉标点和特殊字符
|
|
94
|
-
"""
|
|
112
|
+
# ── 标题生成 ───────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
def format_title(task: str, max_len: int = 50) -> str:
|
|
95
115
|
if not task:
|
|
96
116
|
return "(no task)"
|
|
97
117
|
first_line = task.split("\n")[0].strip()
|
|
98
|
-
# 去掉 markdown 标记
|
|
99
118
|
first_line = re.sub(r"[*_`#>]", "", first_line)
|
|
100
119
|
if len(first_line) > max_len:
|
|
101
120
|
first_line = first_line[:max_len - 3] + "..."
|
|
102
121
|
return first_line
|
|
103
122
|
|
|
104
123
|
|
|
105
|
-
# ── 格式化输出
|
|
124
|
+
# ── 格式化输出 (Aurora 主题) ───────────────────────────────────
|
|
106
125
|
|
|
107
126
|
def print_box(title: str, content: str = "", color_str: str = ""):
|
|
108
|
-
"""
|
|
109
|
-
width = 60
|
|
127
|
+
"""框线输出 — Aurora 极简风格"""
|
|
110
128
|
if color_str:
|
|
111
129
|
title = color(title, color_str)
|
|
112
|
-
|
|
130
|
+
w = 52
|
|
131
|
+
sep = color("─" * w, Colors.FAINT)
|
|
132
|
+
print(f"\n{sep}")
|
|
113
133
|
if title:
|
|
114
134
|
print(f" {title}")
|
|
115
135
|
if content:
|
|
116
136
|
print()
|
|
117
137
|
for line in content.split("\n"):
|
|
118
138
|
print(f" {line}")
|
|
119
|
-
print(f"{
|
|
139
|
+
print(f"{sep}\n")
|
|
120
140
|
|
|
121
141
|
|
|
122
142
|
def format_step_header(iteration: int, max_iterations: int, phase: str = "") -> str:
|
|
123
|
-
"""
|
|
124
|
-
|
|
125
|
-
return f"--- 迭代 {iteration}/{max_iterations}{phase_str} ---"
|
|
143
|
+
"""迭代标题 — 极简"""
|
|
144
|
+
return f"\n {pink('⟡')} {bold(f'iter {iteration}')}{faint(f'/{max_iterations}')}"
|
|
126
145
|
|
|
127
146
|
|
|
128
147
|
def format_tool_call(name: str, args: dict, max_preview: int = 100) -> str:
|
|
129
|
-
"""
|
|
148
|
+
"""工具调用 — Aurora 风格"""
|
|
130
149
|
import json
|
|
131
150
|
args_str = json.dumps(args, ensure_ascii=False)[:max_preview]
|
|
132
|
-
return f" {
|
|
151
|
+
return f" {purple('▸')} {cyan(name)}{faint('(')}{faint(args_str)}{faint(')')}"
|
|
133
152
|
|
|
134
153
|
|
|
135
154
|
def format_tool_result(result: str, success: bool, max_preview: int = 200) -> str:
|
|
136
|
-
"""
|
|
155
|
+
"""工具结果"""
|
|
137
156
|
preview = result[:max_preview]
|
|
138
157
|
if success:
|
|
139
|
-
return f"
|
|
158
|
+
return f" {green('✓')} {faint(preview)}"
|
|
140
159
|
else:
|
|
141
|
-
return f"
|
|
160
|
+
return f" {red('✕')} {faint(preview)}"
|
|
142
161
|
|
|
143
162
|
|
|
144
163
|
def format_thought(content: str, max_preview: int = 300) -> str:
|
|
145
|
-
"""
|
|
164
|
+
"""思考过程 — 薄荷绿斜体"""
|
|
146
165
|
preview = content[:max_preview]
|
|
147
|
-
return f" {
|
|
166
|
+
return f" {pink('✦')} {Colors.wrap(preview, Colors.ITALIC + Colors.MINT_D)}"
|
|
148
167
|
|
|
149
168
|
|
|
150
169
|
def format_result_summary(
|
|
@@ -155,21 +174,27 @@ def format_result_summary(
|
|
|
155
174
|
model: str = "",
|
|
156
175
|
error: str = "",
|
|
157
176
|
) -> str:
|
|
158
|
-
"""
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
177
|
+
"""最终摘要 — 一行式"""
|
|
178
|
+
icon = green("✓") if success else red("✕")
|
|
179
|
+
parts = [
|
|
180
|
+
f"{icon}",
|
|
181
|
+
faint(f"iter {iterations}"),
|
|
182
|
+
faint(f"tools {tool_calls}"),
|
|
183
|
+
color(f"{duration:.1f}s", Colors.MINT_D),
|
|
184
|
+
]
|
|
162
185
|
if model:
|
|
163
|
-
|
|
186
|
+
parts.append(faint(model))
|
|
187
|
+
line1 = " " + faint(" · ").join(parts)
|
|
188
|
+
lines = [line1]
|
|
164
189
|
if error:
|
|
165
|
-
lines.append(f" {red(
|
|
190
|
+
lines.append(f" {red(error[:200])}")
|
|
166
191
|
return "\n".join(lines)
|
|
167
192
|
|
|
168
193
|
|
|
169
|
-
# ── Spinner
|
|
194
|
+
# ── Spinner — Aurora 风格 ──────────────────────────────────────
|
|
170
195
|
|
|
171
196
|
class Spinner:
|
|
172
|
-
"""
|
|
197
|
+
"""加载动画(后台线程)"""
|
|
173
198
|
|
|
174
199
|
_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
|
175
200
|
|
|
@@ -180,7 +205,7 @@ class Spinner:
|
|
|
180
205
|
|
|
181
206
|
def start(self):
|
|
182
207
|
if not Colors._check():
|
|
183
|
-
return
|
|
208
|
+
return
|
|
184
209
|
self._running = True
|
|
185
210
|
self._thread = threading.Thread(target=self._spin, daemon=True)
|
|
186
211
|
self._thread.start()
|
|
@@ -189,7 +214,6 @@ class Spinner:
|
|
|
189
214
|
self._running = False
|
|
190
215
|
if self._thread:
|
|
191
216
|
self._thread.join(timeout=1)
|
|
192
|
-
# 清除 spinner 行
|
|
193
217
|
if Colors._check():
|
|
194
218
|
sys.stdout.write("\r" + " " * (len(self._message) + 10) + "\r")
|
|
195
219
|
sys.stdout.flush()
|
|
@@ -200,7 +224,7 @@ class Spinner:
|
|
|
200
224
|
i = 0
|
|
201
225
|
while self._running:
|
|
202
226
|
frame = self._FRAMES[i % len(self._FRAMES)]
|
|
203
|
-
sys.stdout.write(f"\r{
|
|
227
|
+
sys.stdout.write(f"\r{pink(frame)} {faint(self._message)}")
|
|
204
228
|
sys.stdout.flush()
|
|
205
229
|
time.sleep(0.1)
|
|
206
230
|
i += 1
|
|
@@ -252,16 +252,19 @@ class AgentLoop:
|
|
|
252
252
|
|
|
253
253
|
logger.info("[%s] loop started (%s): %s", self.config.name, mode, task[:100])
|
|
254
254
|
if self.config.report_progress:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
self.
|
|
259
|
-
self._print(f"
|
|
255
|
+
from runtime.orchestration.display import pink, purple, mint, faint, bold, color, Colors
|
|
256
|
+
sep = color("─" * 52, Colors.FAINT)
|
|
257
|
+
self._print(f"\n{sep}")
|
|
258
|
+
agent_label = self.config.display_name or self.config.name
|
|
259
|
+
self._print(f" {purple('◐')} {bold(agent_label)}")
|
|
260
260
|
chain = [self.config.model] + self.config.fallback_models
|
|
261
|
-
|
|
262
|
-
self._print(f"
|
|
263
|
-
self.
|
|
264
|
-
|
|
261
|
+
model_str = faint(" → ").join(pink(m) for m in chain)
|
|
262
|
+
self._print(f" {model_str}")
|
|
263
|
+
tools_list = self.config.tools or []
|
|
264
|
+
if tools_list:
|
|
265
|
+
tools_str = faint(", ").join(mint(t) for t in tools_list)
|
|
266
|
+
self._print(f" {faint('tools')} {tools_str}")
|
|
267
|
+
self._print(f"{sep}")
|
|
265
268
|
|
|
266
269
|
return tools_schema
|
|
267
270
|
|
|
@@ -1997,14 +2000,20 @@ class AgentLoop:
|
|
|
1997
2000
|
compression_results=list(self.compression_results),
|
|
1998
2001
|
)
|
|
1999
2002
|
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
self._print(f"
|
|
2003
|
-
|
|
2004
|
-
self._print(f"
|
|
2003
|
+
from runtime.orchestration.display import green, red, faint, pink, purple, mint, color, Colors, bold
|
|
2004
|
+
sep = color("─" * 52, Colors.FAINT)
|
|
2005
|
+
self._print(f"\n{sep}")
|
|
2006
|
+
icon = green("✓") if success else red("✕")
|
|
2007
|
+
self._print(f" {icon} {bold(self.config.name)}")
|
|
2008
|
+
parts = [
|
|
2009
|
+
faint(f"iter {self.current_iteration}"),
|
|
2010
|
+
faint(f"tools {self._tool_call_count}"),
|
|
2011
|
+
color(f"{duration:.1f}s", Colors.MINT_D),
|
|
2012
|
+
]
|
|
2013
|
+
self._print(" " + faint(" · ").join(parts))
|
|
2005
2014
|
if error:
|
|
2006
|
-
self._print(f"
|
|
2007
|
-
self._print(f"{
|
|
2015
|
+
self._print(f" {red(error[:200])}")
|
|
2016
|
+
self._print(f"{sep}\n")
|
|
2008
2017
|
|
|
2009
2018
|
logger.info(
|
|
2010
2019
|
"[%s] loop finished: success=%s iterations=%d tools=%d duration=%.1fs",
|