jarvis-ai-assistant 0.3.19__py3-none-any.whl → 0.3.21__py3-none-any.whl

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.
Files changed (60) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +33 -5
  3. jarvis/jarvis_agent/config_editor.py +5 -1
  4. jarvis/jarvis_agent/edit_file_handler.py +15 -9
  5. jarvis/jarvis_agent/jarvis.py +99 -3
  6. jarvis/jarvis_agent/memory_manager.py +3 -3
  7. jarvis/jarvis_agent/share_manager.py +3 -1
  8. jarvis/jarvis_agent/shell_input_handler.py +17 -2
  9. jarvis/jarvis_agent/task_analyzer.py +0 -1
  10. jarvis/jarvis_agent/task_manager.py +15 -5
  11. jarvis/jarvis_agent/tool_executor.py +2 -2
  12. jarvis/jarvis_code_agent/code_agent.py +39 -16
  13. jarvis/jarvis_git_utils/git_commiter.py +3 -6
  14. jarvis/jarvis_mcp/sse_mcp_client.py +9 -3
  15. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -5
  16. jarvis/jarvis_memory_organizer/memory_organizer.py +1 -1
  17. jarvis/jarvis_methodology/main.py +4 -4
  18. jarvis/jarvis_multi_agent/__init__.py +3 -3
  19. jarvis/jarvis_platform/ai8.py +0 -4
  20. jarvis/jarvis_platform/base.py +12 -7
  21. jarvis/jarvis_platform/kimi.py +18 -6
  22. jarvis/jarvis_platform/tongyi.py +18 -5
  23. jarvis/jarvis_platform/yuanbao.py +10 -3
  24. jarvis/jarvis_platform_manager/main.py +21 -7
  25. jarvis/jarvis_platform_manager/service.py +4 -3
  26. jarvis/jarvis_rag/cli.py +61 -22
  27. jarvis/jarvis_rag/embedding_manager.py +10 -3
  28. jarvis/jarvis_rag/llm_interface.py +4 -1
  29. jarvis/jarvis_rag/query_rewriter.py +3 -1
  30. jarvis/jarvis_rag/rag_pipeline.py +11 -3
  31. jarvis/jarvis_rag/retriever.py +151 -2
  32. jarvis/jarvis_smart_shell/main.py +60 -19
  33. jarvis/jarvis_stats/cli.py +12 -9
  34. jarvis/jarvis_stats/stats.py +17 -11
  35. jarvis/jarvis_stats/storage.py +23 -6
  36. jarvis/jarvis_tools/cli/main.py +63 -29
  37. jarvis/jarvis_tools/edit_file.py +3 -4
  38. jarvis/jarvis_tools/file_analyzer.py +0 -1
  39. jarvis/jarvis_tools/generate_new_tool.py +3 -3
  40. jarvis/jarvis_tools/read_code.py +0 -1
  41. jarvis/jarvis_tools/read_webpage.py +14 -4
  42. jarvis/jarvis_tools/registry.py +0 -3
  43. jarvis/jarvis_tools/retrieve_memory.py +0 -1
  44. jarvis/jarvis_tools/save_memory.py +0 -1
  45. jarvis/jarvis_tools/search_web.py +0 -2
  46. jarvis/jarvis_tools/sub_agent.py +197 -0
  47. jarvis/jarvis_tools/sub_code_agent.py +194 -0
  48. jarvis/jarvis_tools/virtual_tty.py +21 -13
  49. jarvis/jarvis_utils/clipboard.py +1 -1
  50. jarvis/jarvis_utils/config.py +35 -5
  51. jarvis/jarvis_utils/input.py +528 -41
  52. jarvis/jarvis_utils/methodology.py +3 -1
  53. jarvis/jarvis_utils/output.py +218 -129
  54. jarvis/jarvis_utils/utils.py +480 -170
  55. {jarvis_ai_assistant-0.3.19.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/METADATA +10 -2
  56. {jarvis_ai_assistant-0.3.19.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/RECORD +60 -58
  57. {jarvis_ai_assistant-0.3.19.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/WHEEL +0 -0
  58. {jarvis_ai_assistant-0.3.19.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/entry_points.txt +0 -0
  59. {jarvis_ai_assistant-0.3.19.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/licenses/LICENSE +0 -0
  60. {jarvis_ai_assistant-0.3.19.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/top_level.txt +0 -0
@@ -208,7 +208,9 @@ def load_methodology(
208
208
  if not methodologies:
209
209
  PrettyOutput.print("没有找到方法论文件", OutputType.WARNING)
210
210
  return ""
211
- PrettyOutput.print(f"加载方法论文件完成 (共 {len(methodologies)} 个)", OutputType.SUCCESS)
211
+ PrettyOutput.print(
212
+ f"加载方法论文件完成 (共 {len(methodologies)} 个)", OutputType.SUCCESS
213
+ )
212
214
 
213
215
  if platform_name:
214
216
  platform = PlatformRegistry().create_platform(platform_name)
@@ -10,7 +10,7 @@
10
10
  """
11
11
  from datetime import datetime
12
12
  from enum import Enum
13
- from typing import Dict, Optional, Tuple, Any
13
+ from typing import Dict, Optional, Tuple, Any, List
14
14
 
15
15
  from pygments.lexers import guess_lexer
16
16
  from pygments.util import ClassNotFound
@@ -20,8 +20,10 @@ from rich.style import Style as RichStyle
20
20
  from rich.syntax import Syntax
21
21
  from rich.text import Text
22
22
 
23
- from jarvis.jarvis_utils.config import get_pretty_output
23
+ from jarvis.jarvis_utils.config import get_pretty_output, is_print_error_traceback
24
24
  from jarvis.jarvis_utils.globals import console, get_agent_list
25
+ from dataclasses import dataclass
26
+ from abc import ABC, abstractmethod
25
27
 
26
28
 
27
29
  class OutputType(Enum):
@@ -57,124 +59,60 @@ class OutputType(Enum):
57
59
  TOOL = "TOOL"
58
60
 
59
61
 
60
- class PrettyOutput:
62
+ @dataclass
63
+ class OutputEvent:
61
64
  """
62
- 使用rich库格式化和显示富文本输出的类。
63
-
64
- 提供以下方法:
65
- - 使用适当的样式格式化不同类型的输出
66
- - 代码块的语法高亮
67
- - 结构化内容的面板显示
68
- - 渐进显示的流式输出
65
+ 输出事件的通用结构,供不同输出后端(Sink)消费。
66
+ - text: 文本内容
67
+ - output_type: 输出类型
68
+ - timestamp: 是否显示时间戳
69
+ - lang: 语法高亮语言(可选,不提供则自动检测)
70
+ - traceback: 是否显示异常堆栈
71
+ - section: 若为章节标题输出,填入标题文本;否则为None
72
+ - context: 额外上下文(预留给TUI/日志等)
69
73
  """
70
74
 
71
- # 不同输出类型的图标
72
- _ICONS = {
73
- OutputType.SYSTEM: "🤖",
74
- OutputType.CODE: "📝",
75
- OutputType.RESULT: "✨",
76
- OutputType.ERROR: "❌",
77
- OutputType.INFO: "ℹ️",
78
- OutputType.PLANNING: "📋",
79
- OutputType.PROGRESS: "⏳",
80
- OutputType.SUCCESS: "✅",
81
- OutputType.WARNING: "⚠️",
82
- OutputType.DEBUG: "🔍",
83
- OutputType.USER: "👤",
84
- OutputType.TOOL: "🔧",
85
- }
86
- # 语法高亮的语言映射
87
- _lang_map = {
88
- "Python": "python",
89
- "JavaScript": "javascript",
90
- "TypeScript": "typescript",
91
- "Java": "java",
92
- "C++": "cpp",
93
- "C#": "csharp",
94
- "Ruby": "ruby",
95
- "PHP": "php",
96
- "Go": "go",
97
- "Rust": "rust",
98
- "Bash": "bash",
99
- "HTML": "html",
100
- "CSS": "css",
101
- "SQL": "sql",
102
- "R": "r",
103
- "Kotlin": "kotlin",
104
- "Swift": "swift",
105
- "Scala": "scala",
106
- "Perl": "perl",
107
- "Lua": "lua",
108
- "YAML": "yaml",
109
- "JSON": "json",
110
- "XML": "xml",
111
- "Markdown": "markdown",
112
- "Text": "text",
113
- "Shell": "bash",
114
- "Dockerfile": "dockerfile",
115
- "Makefile": "makefile",
116
- "INI": "ini",
117
- "TOML": "toml",
118
- }
75
+ text: str
76
+ output_type: OutputType
77
+ timestamp: bool = True
78
+ lang: Optional[str] = None
79
+ traceback: bool = False
80
+ section: Optional[str] = None
81
+ context: Optional[Dict[str, Any]] = None
119
82
 
120
- @staticmethod
121
- def _detect_language(text: str, default_lang: str = "markdown") -> str:
122
- """
123
- 检测给定文本的编程语言。
124
83
 
125
- 参数:
126
- text: 要分析的文本
127
- default_lang: 如果检测失败,默认返回的语言
84
+ class OutputSink(ABC):
85
+ """输出后端抽象接口,不同前端(控制台/TUI/SSE/日志)实现该接口以消费输出事件。"""
128
86
 
129
- 返回:
130
- str: 检测到的语言名称
131
- """
132
- try:
133
- lexer = guess_lexer(text)
134
- detected_lang = lexer.name # type: ignore[attr-defined]
135
- return PrettyOutput._lang_map.get(detected_lang, default_lang)
136
- except (ClassNotFound, Exception):
137
- return default_lang
87
+ @abstractmethod
88
+ def emit(self, event: OutputEvent) -> None: # pragma: no cover - 抽象方法
89
+ raise NotImplementedError
138
90
 
139
- @staticmethod
140
- def _format(output_type: OutputType, timestamp: bool = True) -> str:
141
- """
142
- 使用时间戳和图标格式化输出头。
143
91
 
144
- 参数:
145
- output_type: 输出类型
146
- timestamp: 是否包含时间戳
92
+ class ConsoleOutputSink(OutputSink):
93
+ """
94
+ 默认控制台输出实现,保持与原 PrettyOutput 行为一致。
95
+ """
147
96
 
148
- 返回:
149
- Text: 格式化后的rich Text对象
150
- """
151
- icon = PrettyOutput._ICONS.get(output_type, "")
152
- formatted = f"{icon} "
153
- if timestamp:
154
- formatted += f"[{datetime.now().strftime('%H:%M:%S')}][{output_type.value}]"
155
- agent_info = get_agent_list()
156
- if agent_info:
157
- formatted += f"[{agent_info}]"
158
- return formatted
97
+ def emit(self, event: OutputEvent) -> None:
98
+ # 章节输出
99
+ if event.section is not None:
100
+ text = Text(event.section, style=event.output_type.value, justify="center")
101
+ panel = Panel(text, border_style=event.output_type.value)
102
+ if get_pretty_output():
103
+ console.print(panel)
104
+ else:
105
+ console.print(text)
106
+ return
159
107
 
160
- @staticmethod
161
- def print(
162
- text: str,
163
- output_type: OutputType,
164
- timestamp: bool = True,
165
- lang: Optional[str] = None,
166
- traceback: bool = False,
167
- ):
168
- """
169
- 使用样式和语法高亮打印格式化输出。
108
+ # 普通内容输出
109
+ lang = (
110
+ event.lang
111
+ if event.lang is not None
112
+ else PrettyOutput._detect_language(event.text, default_lang="markdown")
113
+ )
170
114
 
171
- 参数:
172
- text: 要打印的文本内容
173
- output_type: 输出类型(影响样式)
174
- timestamp: 是否显示时间戳
175
- lang: 语法高亮的语言
176
- traceback: 是否显示错误的回溯信息
177
- """
115
+ # 与原实现保持一致的样式定义
178
116
  styles: Dict[OutputType, Dict[str, Any]] = {
179
117
  OutputType.SYSTEM: dict(bgcolor="#1e2b3c"),
180
118
  OutputType.CODE: dict(bgcolor="#1c2b1c"),
@@ -255,25 +193,20 @@ class PrettyOutput:
255
193
  ),
256
194
  }
257
195
 
258
- lang = (
259
- lang
260
- if lang is not None
261
- else PrettyOutput._detect_language(text, default_lang="markdown")
262
- )
263
196
  header = Text(
264
- PrettyOutput._format(output_type, timestamp),
265
- style=header_styles[output_type],
197
+ PrettyOutput._format(event.output_type, event.timestamp),
198
+ style=header_styles[event.output_type],
266
199
  )
267
200
  content = Syntax(
268
- text,
201
+ event.text,
269
202
  lang,
270
203
  theme="monokai",
271
204
  word_wrap=True,
272
- background_color=styles[output_type]["bgcolor"],
205
+ background_color=styles[event.output_type]["bgcolor"],
273
206
  )
274
207
  panel = Panel(
275
208
  content,
276
- border_style=header_styles[output_type],
209
+ border_style=header_styles[event.output_type],
277
210
  padding=(0, 0),
278
211
  highlight=True,
279
212
  )
@@ -281,27 +214,183 @@ class PrettyOutput:
281
214
  console.print(panel)
282
215
  else:
283
216
  console.print(content)
284
- if traceback or output_type == OutputType.ERROR:
217
+ if event.traceback or (
218
+ event.output_type == OutputType.ERROR and is_print_error_traceback()
219
+ ):
285
220
  try:
286
221
  console.print_exception()
287
222
  except Exception as e:
288
223
  console.print(f"Error: {e}")
289
224
 
225
+
226
+ # 模块级输出分发器(默认注册控制台后端)
227
+ _output_sinks: List[OutputSink] = [ConsoleOutputSink()]
228
+
229
+
230
+ def emit_output(event: OutputEvent) -> None:
231
+ """向所有已注册的输出后端广播事件。"""
232
+ for sink in list(_output_sinks):
233
+ try:
234
+ sink.emit(event)
235
+ except Exception as e:
236
+ # 后端故障不影响其他后端
237
+ console.print(f"[输出后端错误] {sink.__class__.__name__}: {e}")
238
+
239
+
240
+ class PrettyOutput:
241
+ """
242
+ 使用rich库格式化和显示富文本输出的类。
243
+
244
+ 提供以下方法:
245
+ - 使用适当的样式格式化不同类型的输出
246
+ - 代码块的语法高亮
247
+ - 结构化内容的面板显示
248
+ - 渐进显示的流式输出
249
+ """
250
+
251
+ # 不同输出类型的图标
252
+ _ICONS = {
253
+ OutputType.SYSTEM: "🤖",
254
+ OutputType.CODE: "📝",
255
+ OutputType.RESULT: "✨",
256
+ OutputType.ERROR: "❌",
257
+ OutputType.INFO: "ℹ️",
258
+ OutputType.PLANNING: "📋",
259
+ OutputType.PROGRESS: "⏳",
260
+ OutputType.SUCCESS: "✅",
261
+ OutputType.WARNING: "⚠️",
262
+ OutputType.DEBUG: "🔍",
263
+ OutputType.USER: "👤",
264
+ OutputType.TOOL: "🔧",
265
+ }
266
+ # 语法高亮的语言映射
267
+ _lang_map = {
268
+ "Python": "python",
269
+ "JavaScript": "javascript",
270
+ "TypeScript": "typescript",
271
+ "Java": "java",
272
+ "C++": "cpp",
273
+ "C#": "csharp",
274
+ "Ruby": "ruby",
275
+ "PHP": "php",
276
+ "Go": "go",
277
+ "Rust": "rust",
278
+ "Bash": "bash",
279
+ "HTML": "html",
280
+ "CSS": "css",
281
+ "SQL": "sql",
282
+ "R": "r",
283
+ "Kotlin": "kotlin",
284
+ "Swift": "swift",
285
+ "Scala": "scala",
286
+ "Perl": "perl",
287
+ "Lua": "lua",
288
+ "YAML": "yaml",
289
+ "JSON": "json",
290
+ "XML": "xml",
291
+ "Markdown": "markdown",
292
+ "Text": "text",
293
+ "Shell": "bash",
294
+ "Dockerfile": "dockerfile",
295
+ "Makefile": "makefile",
296
+ "INI": "ini",
297
+ "TOML": "toml",
298
+ }
299
+
290
300
  @staticmethod
291
- def section(title: str, output_type: OutputType = OutputType.INFO):
301
+ def _detect_language(text: str, default_lang: str = "markdown") -> str:
292
302
  """
293
- 在样式化面板中打印章节标题。
303
+ 检测给定文本的编程语言。
294
304
 
295
305
  参数:
296
- title: 章节标题文本
297
- output_type: 输出类型(影响样式)
306
+ text: 要分析的文本
307
+ default_lang: 如果检测失败,默认返回的语言
308
+
309
+ 返回:
310
+ str: 检测到的语言名称
298
311
  """
299
- text = Text(title, style=output_type.value, justify="center")
300
- panel = Panel(text, border_style=output_type.value)
301
- if get_pretty_output():
302
- console.print(panel)
312
+ try:
313
+ lexer = guess_lexer(text)
314
+ detected_lang = lexer.name # type: ignore[attr-defined]
315
+ return PrettyOutput._lang_map.get(detected_lang, default_lang)
316
+ except (ClassNotFound, Exception):
317
+ return default_lang
318
+
319
+ @staticmethod
320
+ def _format(output_type: OutputType, timestamp: bool = True) -> str:
321
+ """
322
+ 使用时间戳和图标格式化输出头。
323
+
324
+ 参数:
325
+ output_type: 输出类型
326
+ timestamp: 是否包含时间戳
327
+
328
+ 返回:
329
+ Text: 格式化后的rich Text对象
330
+ """
331
+ icon = PrettyOutput._ICONS.get(output_type, "")
332
+ formatted = f"{icon} "
333
+ if timestamp:
334
+ formatted += f"[{datetime.now().strftime('%H:%M:%S')}][{output_type.value}]"
335
+ agent_info = get_agent_list()
336
+ if agent_info:
337
+ formatted += f"[{agent_info}]"
338
+ return formatted
339
+
340
+ @staticmethod
341
+ def print(
342
+ text: str,
343
+ output_type: OutputType,
344
+ timestamp: bool = True,
345
+ lang: Optional[str] = None,
346
+ traceback: bool = False,
347
+ ):
348
+ """
349
+ 使用样式和语法高亮打印格式化输出(已抽象为事件 + Sink 机制)。
350
+ 保持对现有调用方的向后兼容,同时为TUI/日志等前端预留扩展点。
351
+ """
352
+ event = OutputEvent(
353
+ text=text,
354
+ output_type=output_type,
355
+ timestamp=timestamp,
356
+ lang=lang,
357
+ traceback=traceback,
358
+ )
359
+ emit_output(event)
360
+
361
+ @staticmethod
362
+ def section(title: str, output_type: OutputType = OutputType.INFO):
363
+ """
364
+ 在样式化面板中打印章节标题(通过事件 + Sink 机制分发)。
365
+ """
366
+ event = OutputEvent(
367
+ text="",
368
+ output_type=output_type,
369
+ section=title,
370
+ )
371
+ emit_output(event)
372
+
373
+ @staticmethod
374
+ # Sink管理(为外部注册自定义后端预留)
375
+ @staticmethod
376
+ def add_sink(sink: OutputSink) -> None:
377
+ """注册一个新的输出后端。"""
378
+ _output_sinks.append(sink)
379
+
380
+ @staticmethod
381
+ def clear_sinks(keep_default: bool = True) -> None:
382
+ """清空已注册的输出后端;可选择保留默认控制台后端。"""
383
+ if keep_default:
384
+ globals()["_output_sinks"] = [
385
+ s for s in _output_sinks if isinstance(s, ConsoleOutputSink)
386
+ ]
303
387
  else:
304
- console.print(text)
388
+ _output_sinks.clear()
389
+
390
+ @staticmethod
391
+ def get_sinks() -> List[OutputSink]:
392
+ """获取当前已注册的输出后端列表(副本)。"""
393
+ return list(_output_sinks)
305
394
 
306
395
  @staticmethod
307
396
  def print_gradient_text(