@baimingtao/lbs-agent 1.4.0 → 1.5.1

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,29 @@ 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
- print(f"\n{'='*60}")
82
- print("最终结果")
83
- print(f"{'='*60}")
84
- print(f"Agent: {result.agent_name}")
85
- print(f"成功: {'✓' if result.success else '✗'}")
86
- print(f"迭代: {result.iterations}")
87
- print(f"工具调用: {result.total_tool_calls}")
88
- print(f"耗时: {result.duration_seconds:.1f}s")
81
+ from runtime.orchestration.display import green, red, faint, pink, mint, bold
82
+ icon = green("") if result.success else red("✕")
83
+ print()
84
+ print(f" {icon} {bold(result.agent_name)}")
85
+ parts = [
86
+ faint(f"iter {result.iterations}"),
87
+ faint(f"tools {result.total_tool_calls}"),
88
+ mint(f"{result.duration_seconds:.1f}s"),
89
+ ]
90
+ print(f" {faint(' · ').join(parts)}")
89
91
  if result.error:
90
- print(f"错误: {result.error}")
91
- print("\n--- 输出 ---")
92
- print(result.content if result.content else "(无输出)")
92
+ print(f" {red(result.error[:200])}")
93
+ print()
94
+ if result.content:
95
+ print(result.content)
96
+ else:
97
+ print(faint("(无输出)"))
93
98
  print()
94
99
 
95
100
  if result.steps:
96
- print(f"--- 执行轨迹 ({len(result.steps)} 步) ---")
97
101
  for step in result.steps:
98
102
  tools = ", ".join(t.name for t in step.tool_execs) if step.tool_execs else "-"
99
- print(f" [{step.iteration:02d}] tools=[{tools}] {step.summary[:100]}")
103
+ print(f" {faint(f'{step.iteration:02d}')} {pink('·')} {faint(tools)}")
100
104
  print()
101
105
  finally:
102
106
  container.shutdown()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baimingtao/lbs-agent",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,13 +1,10 @@
1
- """
2
- Display — 格式化输出、颜色、标题生成。
3
-
4
- 对标 LBS display.py,精简实现:
5
- 1. Colors ANSI 颜色码(Windows 兼容)
6
- 2. format_title — 从任务文本生成简短标题
7
- 3. format_step 格式化迭代步骤输出
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 = "\033[0m"
26
- BOLD = "\033[1m"
27
- DIM = "\033[2m"
28
- RED = "\033[31m"
29
- GREEN = "\033[32m"
30
- YELLOW = "\033[33m"
31
- BLUE = "\033[34m"
32
- MAGENTA = "\033[35m"
33
- CYAN = "\033[36m"
34
- GRAY = "\033[90m"
35
-
36
- # Windows 兼容
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.CYAN)
91
+ return Colors.wrap(text, Colors.MINT_D)
77
92
 
78
93
  def gray(text: str) -> str:
79
- return Colors.wrap(text, Colors.GRAY)
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
- 1. 取第一行
92
- 2. 截断到 max_len
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
- print(f"\n{'=' * width}")
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"{'=' * width}\n")
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
- phase_str = f" [{phase}]" if phase else ""
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" {cyan('[工具]')} {bold(name)}({args_str})"
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" {green('[结果]')} {preview}"
158
+ return f" {green('')} {faint(preview)}"
140
159
  else:
141
- return f" {red('[错误]')} {preview}"
160
+ return f" {red('')} {faint(preview)}"
142
161
 
143
162
 
144
163
  def format_thought(content: str, max_preview: int = 300) -> str:
145
- """格式化 LLM 思考输出。"""
164
+ """思考过程 薄荷绿斜体"""
146
165
  preview = content[:max_preview]
147
- return f" {gray('[思考]')} {preview}"
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
- status = green("✓ 成功") if success else red("✗ 失败")
160
- lines = [f" 结果: {status}"]
161
- lines.append(f" 迭代: {iterations} 工具调用: {tool_calls} 耗时: {duration:.1f}s")
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
- lines.append(f" 模型: {model}")
186
+ parts.append(faint(model))
187
+ line1 = " " + faint(" · ").join(parts)
188
+ lines = [line1]
164
189
  if error:
165
- lines.append(f" {red('错误')}: {error[:200]}")
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 # 不支持 ANSI 就不显示 spinner
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{cyan(frame)} {self._message}")
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,18 @@ 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
- label = f"{self.config.display_name or self.config.name}"
256
- if mode == "react":
257
- label += " [ReAct]"
258
- self._print(f"\n{'='*60}")
259
- self._print(f"Agent: {label}")
255
+ from runtime.orchestration.display import pink, purple, mint, faint, bold
256
+ agent_label = self.config.display_name or self.config.name
257
+ self._print("")
258
+ self._print(f" {purple('')} {bold(agent_label)}")
260
259
  chain = [self.config.model] + self.config.fallback_models
261
- self._print(f"Model: {' -> '.join(chain)}")
262
- self._print(f"Tools: {self.config.tools or '(none)'}")
263
- self._print(f"Task: {task[:200]}")
264
- self._print(f"{'='*60}\n")
260
+ model_str = faint(" ").join(pink(m) for m in chain)
261
+ self._print(f" {model_str}")
262
+ tools_list = self.config.tools or []
263
+ if tools_list:
264
+ tools_str = faint(", ").join(mint(t) for t in tools_list)
265
+ self._print(f" {tools_str}")
266
+ self._print("")
265
267
 
266
268
  return tools_schema
267
269
 
@@ -1997,14 +1999,19 @@ class AgentLoop:
1997
1999
  compression_results=list(self.compression_results),
1998
2000
  )
1999
2001
 
2000
- self._print(f"\n{'='*60}")
2001
- self._print(f"Agent: {self.config.name}")
2002
- self._print(f"结果: {'✓ 成功' if success else '✗ 失败'}")
2003
- self._print(f"迭代: {self.current_iteration} 工具调用: {self._tool_call_count}")
2004
- self._print(f"耗时: {duration:.1f}s")
2002
+ from runtime.orchestration.display import green, red, faint, mint, bold
2003
+ icon = green("✓") if success else red("✕")
2004
+ self._print("")
2005
+ self._print(f" {icon} {bold(self.config.name)}")
2006
+ parts = [
2007
+ faint(f"iter {self.current_iteration}"),
2008
+ faint(f"tools {self._tool_call_count}"),
2009
+ mint(f"{duration:.1f}s"),
2010
+ ]
2011
+ self._print(f" {faint(' · ').join(parts)}")
2005
2012
  if error:
2006
- self._print(f"错误: {error}")
2007
- self._print(f"{'='*60}\n")
2013
+ self._print(f" {red(error[:200])}")
2014
+ self._print("")
2008
2015
 
2009
2016
  logger.info(
2010
2017
  "[%s] loop finished: success=%s iterations=%d tools=%d duration=%.1fs",