jarvis-ai-assistant 0.1.175__py3-none-any.whl → 0.1.177__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.

Potentially problematic release.


This version of jarvis-ai-assistant might be problematic. Click here for more details.

Files changed (34) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +22 -35
  3. jarvis/jarvis_agent/jarvis.py +14 -12
  4. jarvis/jarvis_agent/main.py +6 -6
  5. jarvis/jarvis_code_agent/code_agent.py +10 -8
  6. jarvis/jarvis_code_analysis/code_review.py +1 -1
  7. jarvis/jarvis_dev/main.py +1 -1
  8. jarvis/jarvis_git_details/main.py +1 -1
  9. jarvis/jarvis_git_squash/main.py +1 -1
  10. jarvis/jarvis_git_utils/git_commiter.py +1 -1
  11. jarvis/jarvis_multi_agent/main.py +1 -1
  12. jarvis/jarvis_platform/base.py +53 -32
  13. jarvis/jarvis_platform/human.py +4 -3
  14. jarvis/jarvis_platform/kimi.py +22 -170
  15. jarvis/jarvis_platform/openai.py +8 -30
  16. jarvis/jarvis_platform/yuanbao.py +35 -83
  17. jarvis/jarvis_platform_manager/main.py +1 -1
  18. jarvis/jarvis_smart_shell/main.py +4 -2
  19. jarvis/jarvis_tools/ask_codebase.py +8 -2
  20. jarvis/jarvis_tools/cli/main.py +28 -1
  21. jarvis/jarvis_tools/edit_file.py +163 -103
  22. jarvis/jarvis_tools/read_code.py +0 -2
  23. jarvis/jarvis_tools/registry.py +30 -0
  24. jarvis/jarvis_utils/config.py +12 -3
  25. jarvis/jarvis_utils/embedding.py +1 -10
  26. jarvis/jarvis_utils/output.py +78 -41
  27. jarvis/jarvis_utils/utils.py +19 -1
  28. {jarvis_ai_assistant-0.1.175.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/METADATA +5 -4
  29. {jarvis_ai_assistant-0.1.175.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/RECORD +33 -34
  30. {jarvis_ai_assistant-0.1.175.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/WHEEL +1 -1
  31. jarvis/jarvis_agent/file_input_handler.py +0 -108
  32. {jarvis_ai_assistant-0.1.175.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/entry_points.txt +0 -0
  33. {jarvis_ai_assistant-0.1.175.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/licenses/LICENSE +0 -0
  34. {jarvis_ai_assistant-0.1.175.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- from typing import Dict, List, Tuple
2
+ from typing import Dict, Generator, List, Tuple
3
3
  import requests # type: ignore
4
4
  import json
5
5
  import os
@@ -241,7 +241,7 @@ class KimiModel(BasePlatform):
241
241
  return True
242
242
 
243
243
 
244
- def chat(self, message: str) -> str:
244
+ def chat(self, message: str) -> Generator[str, None, None]:
245
245
  """Send message and get response"""
246
246
  if not self.chat_id:
247
247
  if not self._create_chat():
@@ -279,177 +279,29 @@ class KimiModel(BasePlatform):
279
279
 
280
280
  try:
281
281
  response = while_success(lambda: requests.post(url, headers=headers, json=payload, stream=True), sleep_time=5)
282
- full_response = ""
283
-
284
- # 收集搜索和引用结果
285
- search_results = []
286
- ref_sources = []
287
-
288
- # 使用Rich的Live组件来实时展示更新
289
- if not self.suppress_output:
290
- text_content = Text()
291
- panel = Panel(text_content,
292
- title=f"[bold magenta]{self.model_name}[/bold magenta]",
293
- subtitle="思考中...",
294
- border_style="magenta",
295
- box=box.ROUNDED)
296
-
297
- with Live(panel, refresh_per_second=3, transient=False) as live:
298
- for line in response.iter_lines():
299
- if not line:
300
- continue
301
-
302
- line = line.decode('utf-8')
303
- if not line.startswith("data: "):
304
- continue
305
-
306
- try:
307
- data = json.loads(line[6:])
308
- event = data.get("event")
309
-
310
- if event == "cmpl":
311
- # 处理补全文本
312
- text = data.get("text", "")
313
- if text:
314
- full_response += text
315
- text_content.append(text)
316
- panel.subtitle = "生成中..."
317
- live.update(panel)
318
-
319
- elif event == "search_plus":
320
- # 收集搜索结果
321
- msg = data.get("msg", {})
322
- if msg.get("type") == "get_res":
323
- search_results.append({
324
- "date": msg.get("date", ""),
325
- "site_name": msg.get("site_name", ""),
326
- "snippet": msg.get("snippet", ""),
327
- "title": msg.get("title", ""),
328
- "type": msg.get("type", ""),
329
- "url": msg.get("url", "")
330
- })
331
- panel.subtitle = f"搜索中: 找到 {len(search_results)} 个结果"
332
- live.update(panel)
333
-
334
- elif event == "ref_docs":
335
- # 收集引用来源
336
- ref_cards = data.get("ref_cards", [])
337
- for card in ref_cards:
338
- ref_sources.append({
339
- "idx_s": card.get("idx_s", ""),
340
- "idx_z": card.get("idx_z", ""),
341
- "ref_id": card.get("ref_id", ""),
342
- "url": card.get("url", ""),
343
- "title": card.get("title", ""),
344
- "abstract": card.get("abstract", ""),
345
- "source": card.get("source_label", ""),
346
- "rag_segments": card.get("rag_segments", []),
347
- "origin": card.get("origin", {})
348
- })
349
- panel.subtitle = f"分析引用: 找到 {len(ref_sources)} 个来源"
350
- live.update(panel)
351
-
352
- except json.JSONDecodeError:
353
- continue
354
-
355
- # 显示对话完成状态
356
- panel.subtitle = "[bold green]回答完成[/bold green]"
357
- live.update(panel)
358
- else:
359
- # 如果禁止输出,则静默处理
360
- for line in response.iter_lines():
361
- if not line:
362
- continue
363
-
364
- line = line.decode('utf-8')
365
- if not line.startswith("data: "):
366
- continue
367
-
368
- try:
369
- data = json.loads(line[6:])
370
- event = data.get("event")
371
-
372
- if event == "cmpl":
373
- # 处理补全文本
374
- text = data.get("text", "")
375
- if text:
376
- full_response += text
377
-
378
- elif event == "search_plus":
379
- # 收集搜索结果
380
- msg = data.get("msg", {})
381
- if msg.get("type") == "get_res":
382
- search_results.append({
383
- "date": msg.get("date", ""),
384
- "site_name": msg.get("site_name", ""),
385
- "snippet": msg.get("snippet", ""),
386
- "title": msg.get("title", ""),
387
- "type": msg.get("type", ""),
388
- "url": msg.get("url", "")
389
- })
390
-
391
- elif event == "ref_docs":
392
- # 收集引用来源
393
- ref_cards = data.get("ref_cards", [])
394
- for card in ref_cards:
395
- ref_sources.append({
396
- "idx_s": card.get("idx_s", ""),
397
- "idx_z": card.get("idx_z", ""),
398
- "ref_id": card.get("ref_id", ""),
399
- "url": card.get("url", ""),
400
- "title": card.get("title", ""),
401
- "abstract": card.get("abstract", ""),
402
- "source": card.get("source_label", ""),
403
- "rag_segments": card.get("rag_segments", []),
404
- "origin": card.get("origin", {})
405
- })
406
-
407
- except json.JSONDecodeError:
408
- continue
409
-
410
- # 显示搜索结果摘要
411
- if search_results and not self.suppress_output:
412
- output = ["搜索结果:"]
413
- for result in search_results:
414
- output.append(f"- {result['title']}")
415
- if result['date']:
416
- output.append(f" 日期: {result['date']}")
417
- output.append(f" 来源: {result['site_name']}")
418
- if result['snippet']:
419
- output.append(f" 摘要: {result['snippet']}")
420
- output.append(f" 链接: {result['url']}")
421
- output.append("")
422
- PrettyOutput.print("\n".join(output), OutputType.PROGRESS)
423
-
424
- # 显示引用来源
425
- if ref_sources and not self.suppress_output:
426
- output = ["引用来源:"]
427
- for source in ref_sources:
428
- output.append(f"- [{source['ref_id']}] {source['title']} ({source['source']})")
429
- output.append(f" 链接: {source['url']}")
430
- if source['abstract']:
431
- output.append(f" 摘要: {source['abstract']}")
432
-
433
- # 显示相关段落
434
- if source['rag_segments']:
435
- output.append(" 相关段落:")
436
- for segment in source['rag_segments']:
437
- text = segment.get('text', '').replace('\n', ' ').strip()
438
- if text:
439
- output.append(f" - {text}")
440
-
441
- # 显示原文引用
442
- origin = source['origin']
443
- if origin:
444
- text = origin.get('text', '')
445
- if text:
446
- output.append(f" 原文: {text}")
282
+ # 如果禁止输出,则静默处理
283
+ for line in response.iter_lines():
284
+ if not line:
285
+ continue
286
+
287
+ line = line.decode('utf-8')
288
+ if not line.startswith("data: "):
289
+ continue
290
+
291
+ try:
292
+ data = json.loads(line[6:])
293
+ event = data.get("event")
447
294
 
448
- output.append("")
295
+ if event == "cmpl":
296
+ # 处理补全文本
297
+ text = data.get("text", "")
298
+ if text:
299
+ yield text
300
+ except json.JSONDecodeError:
301
+ continue
449
302
 
450
- PrettyOutput.print("\n".join(output), OutputType.PROGRESS)
451
303
 
452
- return full_response
304
+ return None
453
305
 
454
306
  except Exception as e:
455
307
  raise Exception(f"Chat failed: {str(e)}")
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- from typing import Dict, List, Tuple
2
+ from typing import Dict, Generator, List, Tuple
3
3
  import os
4
4
  from openai import OpenAI
5
5
  from rich.live import Live
@@ -73,7 +73,7 @@ class OpenAIModel(BasePlatform):
73
73
  self.system_message = message
74
74
  self.messages.append({"role": "system", "content": self.system_message})
75
75
 
76
- def chat(self, message: str) -> str:
76
+ def chat(self, message: str) -> Generator[str, None, None]:
77
77
  """Execute conversation"""
78
78
  try:
79
79
 
@@ -87,38 +87,16 @@ class OpenAIModel(BasePlatform):
87
87
  ) # type: ignore
88
88
 
89
89
  full_response = ""
90
-
91
- # 使用Rich的Live组件来实时展示更新
92
- if not self.suppress_output:
93
- text_content = Text()
94
- panel = Panel(text_content,
95
- title=f"[bold blue]{self.model_name}[/bold blue]",
96
- subtitle="生成中...",
97
- border_style="cyan",
98
- box=box.ROUNDED)
99
-
100
- with Live(panel, refresh_per_second=3, transient=False) as live:
101
- for chunk in response:
102
- if chunk.choices and chunk.choices[0].delta.content:
103
- text = chunk.choices[0].delta.content
104
- full_response += text
105
- text_content.append(text)
106
- live.update(panel)
107
-
108
- # 显示对话完成状态
109
- panel.subtitle = "[bold green]对话完成[/bold green]"
110
- live.update(panel)
111
- else:
112
- # 如果禁止输出,则静默处理
113
- for chunk in response:
114
- if chunk.choices and chunk.choices[0].delta.content:
115
- text = chunk.choices[0].delta.content
116
- full_response += text
90
+ for chunk in response:
91
+ if chunk.choices and chunk.choices[0].delta.content:
92
+ text = chunk.choices[0].delta.content
93
+ full_response += text
94
+ yield text
117
95
 
118
96
  # Add assistant reply to history
119
97
  self.messages.append({"role": "assistant", "content": full_response})
120
98
 
121
- return full_response
99
+ return None
122
100
 
123
101
  except Exception as e:
124
102
  PrettyOutput.print(f"对话失败:{str(e)}", OutputType.ERROR)
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- from typing import Dict, List, Tuple
2
+ from typing import Dict, Generator, List, Tuple
3
3
  import requests
4
4
  import json
5
5
  import os
@@ -294,7 +294,7 @@ class YuanbaoPlatform(BasePlatform):
294
294
  with open(file_path, 'rb') as file:
295
295
  file_content = file.read()
296
296
 
297
- spinner.write(f"ℹ️ 上传文件大小: {len(file_content)}")
297
+ spinner.write(f"ℹ️ 上传文件大小: {len(file_content)}")
298
298
 
299
299
  # Prepare headers for PUT request
300
300
  host = f"{upload_info['bucketName']}.{upload_info.get('accelerateDomain', 'cos.accelerate.myqcloud.com')}"
@@ -386,7 +386,7 @@ class YuanbaoPlatform(BasePlatform):
386
386
  PrettyOutput.print(f"生成签名时出错: {str(e)}", OutputType.ERROR)
387
387
  raise e
388
388
 
389
- def chat(self, message: str) -> str:
389
+ def chat(self, message: str) -> Generator[str, None, None]:
390
390
  """发送消息并获取响应,可选文件附件
391
391
 
392
392
  参数:
@@ -452,86 +452,38 @@ class YuanbaoPlatform(BasePlatform):
452
452
  error_msg += f", 响应: {response.text}"
453
453
  raise Exception(error_msg)
454
454
 
455
- full_response = ""
456
- is_text_block = False
457
- thinking_content = ""
458
-
459
- # 使用Rich的Live组件来实时展示更新
460
- if not self.suppress_output:
461
- text_content = Text()
462
- panel = Panel(text_content, title=f"[bold blue]{self.model_name}[/bold blue]",
463
- subtitle="思考中...", border_style="blue", box=box.ROUNDED)
464
- with Live(panel, refresh_per_second=3, transient=False) as live:
465
- # 处理SSE流响应
466
- for line in response.iter_lines():
467
- if not line:
468
- continue
469
-
470
- line_str = line.decode('utf-8')
471
-
472
- # SSE格式的行通常以"data: "开头
473
- if line_str.startswith("data: "):
474
- try:
475
- data_str = line_str[6:] # 移除"data: "前缀
476
- data = json.loads(data_str)
477
-
478
- # 处理文本类型的消息
479
- if data.get("type") == "text":
480
- is_text_block = True
481
- msg = data.get("msg", "")
482
- if msg:
483
- full_response += msg
484
- text_content.append(msg)
485
- panel.subtitle = "正在回答..."
486
- live.update(panel)
487
-
488
- # 处理思考中的消息
489
- elif data.get("type") == "think":
490
- think_content = data.get("content", "")
491
- if think_content:
492
- thinking_content = think_content
493
- panel.subtitle = f"思考中: {thinking_content}"
494
- live.update(panel)
495
-
496
- except json.JSONDecodeError:
497
- pass
498
-
499
- # 检测结束标志
500
- elif line_str == "data: [DONE]":
501
- break
502
-
503
- # 显示对话完成状态
504
- panel.subtitle = "[bold green]对话完成[/bold green]"
505
- live.update(panel)
506
- else:
507
- # 如果禁止输出,则静默处理
508
- for line in response.iter_lines():
509
- if not line:
510
- continue
511
-
512
- line_str = line.decode('utf-8')
513
-
514
- # SSE格式的行通常以"data: "开头
515
- if line_str.startswith("data: "):
516
- try:
517
- data_str = line_str[6:] # 移除"data: "前缀
518
- data = json.loads(data_str)
519
-
520
- # 处理文本类型的消息
521
- if data.get("type") == "text":
522
- is_text_block = True
523
- msg = data.get("msg", "")
524
- if msg:
525
- full_response += msg
526
-
527
- except json.JSONDecodeError:
528
- pass
529
-
530
- # 检测结束标志
531
- elif line_str == "data: [DONE]":
532
- break
533
-
534
- return full_response
455
+ # 处理SSE流响应
456
+ for line in response.iter_lines():
457
+ if not line:
458
+ continue
459
+
460
+ line_str = line.decode('utf-8')
461
+
462
+ # SSE格式的行通常以"data: "开头
463
+ if line_str.startswith("data: "):
464
+ try:
465
+ data_str = line_str[6:] # 移除"data: "前缀
466
+ data = json.loads(data_str)
467
+
468
+ # 处理文本类型的消息
469
+ if data.get("type") == "text":
470
+ msg = data.get("msg", "")
471
+ if msg:
472
+ yield msg
473
+
474
+ # 处理思考中的消息
475
+ elif data.get("type") == "think":
476
+ think_content = data.get("content", "")
477
+ if think_content:
478
+ yield think_content
479
+
480
+ except json.JSONDecodeError:
481
+ pass
482
+
483
+ # 检测结束标志
484
+ elif line_str == "data: [DONE]":
485
+ return None
486
+ return None
535
487
 
536
488
  except Exception as e:
537
489
  raise Exception(f"对话失败: {str(e)}")
@@ -606,7 +606,7 @@ def main():
606
606
  """Main function"""
607
607
  import argparse
608
608
 
609
- init_env()
609
+ init_env("欢迎使用 Jarvis-PlatformManager,您的平台管理助手已准备就绪!")
610
610
 
611
611
  parser = argparse.ArgumentParser(description='Jarvis AI 平台')
612
612
  subparsers = parser.add_subparsers(dest='command', help='可用子命令')
@@ -5,6 +5,8 @@ import os
5
5
  import sys
6
6
  from typing import Optional
7
7
 
8
+ from sympy import false
9
+
8
10
  from jarvis.jarvis_platform.registry import PlatformRegistry
9
11
  from jarvis.jarvis_utils.config import get_shell_name
10
12
  from jarvis.jarvis_utils.input import get_multiline_input
@@ -113,8 +115,8 @@ def process_request(request: str) -> Optional[str]:
113
115
  return None
114
116
 
115
117
  def main() -> int:
116
- # 创建参数解析器
117
- init_env()
118
+ # 创建参数解析器s
119
+ init_env("")
118
120
  parser = argparse.ArgumentParser(
119
121
  description="将自然语言要求转换为shell命令",
120
122
  formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -253,20 +253,26 @@ def main():
253
253
  ```
254
254
  python -m jarvis.jarvis_tools.ask_codebase "登录功能在哪个文件实现?" --root_dir /path/to/codebase
255
255
  ```
256
+ 如果没有提供问题参数,则会进入交互式多行输入模式
256
257
  """
257
258
  import argparse
258
259
  import sys
260
+ from jarvis.jarvis_utils.input import get_multiline_input
259
261
 
260
- init_env()
262
+ init_env("欢迎使用 Jarvis-AskCodebase,您的智能代码库查询工具已准备就绪!")
261
263
 
262
264
  # 创建命令行参数解析器
263
265
  parser = argparse.ArgumentParser(description="智能代码库查询工具")
264
- parser.add_argument("question", help="关于代码库的问题")
266
+ parser.add_argument("question", nargs="?", help="关于代码库的问题")
265
267
  parser.add_argument("--root_dir", "-d", default=".", help="代码库根目录路径")
266
268
 
267
269
  # 解析命令行参数
268
270
  args = parser.parse_args()
269
271
 
272
+ # 如果没有提供问题参数,使用多行输入
273
+ if not args.question:
274
+ args.question = get_multiline_input("请输入关于代码库的问题:")
275
+
270
276
  # 创建并执行工具
271
277
  tool = AskCodebaseTool(auto_complete=False)
272
278
  result = tool.execute({
@@ -29,7 +29,7 @@ def main() -> int:
29
29
  import argparse
30
30
  import json
31
31
 
32
- init_env()
32
+ init_env("欢迎使用 Jarvis-Tools,您的工具系统已准备就绪!")
33
33
 
34
34
  parser = argparse.ArgumentParser(description="Jarvis 工具系统命令行界面")
35
35
  subparsers = parser.add_subparsers(dest="command", help="命令")
@@ -47,6 +47,10 @@ def main() -> int:
47
47
  "--args-file", type=str, help="从文件加载工具参数 (JSON格式)"
48
48
  )
49
49
 
50
+ # 统计子命令
51
+ stat_parser = subparsers.add_parser("stat", help="显示工具调用统计信息")
52
+ stat_parser.add_argument("--json", action="store_true", help="以JSON格式输出")
53
+
50
54
  args = parser.parse_args()
51
55
 
52
56
  # 初始化工具注册表
@@ -72,6 +76,29 @@ def main() -> int:
72
76
  print(f" 参数:")
73
77
  print(tool["parameters"]) # 显示详细参数信息
74
78
 
79
+ elif args.command == "stat":
80
+ from tabulate import tabulate
81
+ stats = registry._get_tool_stats()
82
+ tools = registry.get_all_tools()
83
+
84
+ # 构建统计表格数据
85
+ table_data = []
86
+ for tool in tools:
87
+ name = tool["name"]
88
+ count = stats.get(name, 0)
89
+ table_data.append([name, count])
90
+
91
+ # 按调用次数降序排序
92
+ table_data.sort(key=lambda x: x[1], reverse=True)
93
+
94
+ if args.json:
95
+ print(json.dumps(dict(table_data), indent=2))
96
+ else:
97
+ PrettyOutput.section("工具调用统计", OutputType.SYSTEM)
98
+ print(tabulate(table_data, headers=["工具名称", "调用次数"], tablefmt="grid"))
99
+
100
+ return 0
101
+
75
102
  elif args.command == "call":
76
103
  tool_name = args.tool_name
77
104
  tool_obj = registry.get_tool(tool_name)