jarvis-ai-assistant 0.1.115__py3-none-any.whl → 0.1.116__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 (51) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/{agent.py → jarvis_agent/__init__.py} +35 -159
  3. jarvis/jarvis_agent/output_handler.py +23 -0
  4. jarvis/jarvis_code_agent/code_agent.py +11 -11
  5. jarvis/jarvis_code_agent/file_select.py +28 -7
  6. jarvis/jarvis_code_agent/patch.py +25 -2
  7. jarvis/jarvis_code_agent/relevant_files.py +1 -1
  8. jarvis/jarvis_codebase/main.py +2 -2
  9. jarvis/jarvis_lsp/cpp.py +1 -1
  10. jarvis/jarvis_lsp/go.py +1 -1
  11. jarvis/jarvis_lsp/registry.py +1 -1
  12. jarvis/jarvis_lsp/rust.py +1 -1
  13. jarvis/jarvis_multi_agent/__init__.py +147 -0
  14. jarvis/jarvis_platform/ai8.py +2 -2
  15. jarvis/jarvis_platform/base.py +14 -4
  16. jarvis/jarvis_platform/kimi.py +2 -2
  17. jarvis/jarvis_platform/ollama.py +1 -1
  18. jarvis/jarvis_platform/openai.py +1 -1
  19. jarvis/jarvis_platform/oyi.py +1 -1
  20. jarvis/jarvis_platform/registry.py +1 -1
  21. jarvis/jarvis_platform_manager/main.py +422 -6
  22. jarvis/jarvis_platform_manager/openai_test.py +139 -0
  23. jarvis/jarvis_rag/main.py +2 -2
  24. jarvis/jarvis_smart_shell/main.py +17 -16
  25. jarvis/jarvis_tools/ask_codebase.py +1 -1
  26. jarvis/jarvis_tools/ask_user.py +1 -1
  27. jarvis/jarvis_tools/chdir.py +1 -1
  28. jarvis/jarvis_tools/code_review.py +3 -3
  29. jarvis/jarvis_tools/create_code_agent.py +1 -1
  30. jarvis/jarvis_tools/create_sub_agent.py +2 -2
  31. jarvis/jarvis_tools/execute_shell.py +1 -1
  32. jarvis/jarvis_tools/file_operation.py +16 -14
  33. jarvis/jarvis_tools/git_commiter.py +2 -2
  34. jarvis/jarvis_tools/methodology.py +1 -1
  35. jarvis/jarvis_tools/rag.py +1 -1
  36. jarvis/jarvis_tools/read_code.py +19 -8
  37. jarvis/jarvis_tools/read_webpage.py +1 -1
  38. jarvis/jarvis_tools/registry.py +53 -6
  39. jarvis/jarvis_tools/search.py +1 -1
  40. jarvis/jarvis_tools/select_code_files.py +1 -1
  41. jarvis/{utils.py → jarvis_utils/__init__.py} +69 -53
  42. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/METADATA +1 -1
  43. jarvis_ai_assistant-0.1.116.dist-info/RECORD +64 -0
  44. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/WHEEL +1 -1
  45. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/entry_points.txt +1 -2
  46. jarvis/jarvis_dev/main.py +0 -664
  47. jarvis/multi_agent.py +0 -76
  48. jarvis/utils/date_utils.py +0 -19
  49. jarvis_ai_assistant-0.1.115.dist-info/RECORD +0 -64
  50. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/LICENSE +0 -0
  51. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,147 @@
1
+
2
+
3
+
4
+ import re
5
+ from typing import Any, Dict, List, Optional, Tuple
6
+
7
+ import yaml
8
+
9
+ from jarvis.jarvis_agent import Agent
10
+ from jarvis.jarvis_agent.output_handler import OutputHandler
11
+ from jarvis.jarvis_utils import OutputType, PrettyOutput
12
+
13
+
14
+ class AgentConfig:
15
+ def __init__(self, **config):
16
+ self.system_prompt = config.get('system_prompt', '')
17
+ self.name = config.get('name', 'Jarvis')
18
+ self.description = config.get('description', '')
19
+ self.is_sub_agent = config.get('is_sub_agent', False)
20
+ self.output_handler = config.get('output_handler', [])
21
+ self.platform = config.get('platform')
22
+ self.model_name = config.get('model_name')
23
+ self.summary_prompt = config.get('summary_prompt')
24
+ self.auto_complete = config.get('auto_complete', False)
25
+ self.input_handler = config.get('input_handler')
26
+ self.max_context_length = config.get('max_context_length')
27
+ self.execute_tool_confirm = config.get('execute_tool_confirm')
28
+
29
+ class MultiAgent(OutputHandler):
30
+ def __init__(self, configs: List[AgentConfig], main_agent_name: str):
31
+ self.agents_config = configs
32
+ self.agents = {}
33
+ self.init_agents()
34
+ self.main_agent_name = main_agent_name
35
+
36
+ def prompt(self) -> str:
37
+ return """
38
+ - Send Message Rules
39
+ !!! CRITICAL ACTION RULES !!!
40
+ You can ONLY perform ONE action per turn:
41
+ - ENSURE USE ONLY ONE TOOL EVERY TURN (file_operation, ask_user, etc.)
42
+ - OR SEND ONE MESSAGE TO ANOTHER AGENT
43
+ - NEVER DO BOTH IN THE SAME TURN
44
+
45
+ 2. Message Format:
46
+ <SEND_MESSAGE>
47
+ to: agent_name # Target agent name
48
+ content: |
49
+ message_content # Message content, multi-line must be separated by newlines
50
+ </SEND_MESSAGE>
51
+
52
+ 3. Message Handling:
53
+ - After sending a message, WAIT for response
54
+ - Process response before next action
55
+ - Never send multiple messages at once
56
+ - Never combine message with tool calls
57
+
58
+ 4. If Multiple Actions Needed:
59
+ a. Choose most important action first
60
+ b. Wait for response/result
61
+ c. Plan next action based on response
62
+ d. Execute next action in new turn
63
+
64
+ - Remember:
65
+ - First action will be executed
66
+ - Additional actions will be IGNORED
67
+ - Always process responses before new actions
68
+ - You should send message to other to continue the task if you are nothing to do
69
+ - If you receive a message from other agent, you should handle it and reply to sender
70
+
71
+ You can send message to following agents: """ + "\n".join([f"{c.name}: {c.description}" for c in self.agents_config])
72
+
73
+ def can_handle(self, response: str) -> bool:
74
+ return len(self._extract_send_msg(response)) > 0
75
+
76
+
77
+ def handle(self, response: str) -> Tuple[bool, Any]:
78
+ send_messages = self._extract_send_msg(response)
79
+ if len(send_messages) > 1:
80
+ return False, f"Send multiple messages, please only send one message at a time."
81
+ if len(send_messages) == 0:
82
+ return False, ""
83
+ return True, send_messages[0]
84
+
85
+ def name(self) -> str:
86
+ return "SEND_MESSAGE"
87
+
88
+
89
+ @staticmethod
90
+ def _extract_send_msg(content: str) -> List[Dict]:
91
+ """Extract send message from content.
92
+
93
+ Args:
94
+ content: The content containing send message
95
+ """
96
+ data = re.findall(r'<SEND_MESSAGE>(.*?)</SEND_MESSAGE>', content, re.DOTALL)
97
+ ret = []
98
+ for item in data:
99
+ try:
100
+ msg = yaml.safe_load(item)
101
+ if 'to' in msg and 'content' in msg:
102
+ ret.append(msg)
103
+ except Exception as e:
104
+ continue
105
+ return ret
106
+
107
+ def init_agents(self):
108
+ for agent_config in self.agents_config:
109
+ agent = Agent(system_prompt=agent_config.system_prompt,
110
+ name=agent_config.name,
111
+ description=agent_config.description,
112
+ model_name=agent_config.model_name,
113
+ platform=agent_config.platform,
114
+ max_context_length=agent_config.max_context_length,
115
+ execute_tool_confirm=agent_config.execute_tool_confirm,
116
+ input_handler=agent_config.input_handler,
117
+ use_methodology=False,
118
+ record_methodology=False,
119
+ need_summary=False,
120
+ auto_complete=agent_config.auto_complete,
121
+ summary_prompt=agent_config.summary_prompt,
122
+ is_sub_agent=agent_config.is_sub_agent,
123
+ output_handler=[*agent_config.output_handler, self],
124
+ )
125
+
126
+ self.agents[agent_config.name] = agent
127
+
128
+ def run(self, user_input: str, file_list: Optional[List[str]] = None) -> str:
129
+ last_agent = self.main_agent_name
130
+ msg = self.agents[self.main_agent_name].run(user_input, file_list)
131
+ while msg:
132
+ if isinstance(msg, str):
133
+ return msg
134
+ elif isinstance(msg, Dict):
135
+ prompt = f"""
136
+ Please handle this message:
137
+ from: {last_agent}
138
+ content: {msg['content']}
139
+ """
140
+ if msg['to'] not in self.agents:
141
+ PrettyOutput.print(f"没有找到{msg['to']},重试...", OutputType.WARNING)
142
+ msg = self.agents[last_agent].run(f"The agent {msg['to']} is not found, agent list: {self.agents.keys()}")
143
+ continue
144
+ PrettyOutput.print(f"{last_agent} 发送消息给 {msg['to']}...", OutputType.INFO)
145
+ last_agent = self.agents[msg['to']].name
146
+ msg = self.agents[msg['to']].run(prompt)
147
+ return ""
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from typing import Dict, List, Tuple
3
3
  from jarvis.jarvis_platform.base import BasePlatform
4
- from jarvis.utils import PrettyOutput, OutputType
4
+ from jarvis.jarvis_utils import PrettyOutput, OutputType
5
5
  import requests
6
6
  import json
7
7
  import base64
@@ -260,7 +260,7 @@ class AI8Model(BasePlatform):
260
260
  }
261
261
 
262
262
  response = requests.get(
263
- f"{self.BASE_URL}/api/chat/template",
263
+ f"{self.BASE_URL}/api/chat/tmpl",
264
264
  headers=headers
265
265
  )
266
266
 
@@ -2,7 +2,9 @@ from abc import ABC, abstractmethod
2
2
  import re
3
3
  from typing import Dict, List, Tuple
4
4
 
5
- from jarvis.utils import while_success, while_true
5
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, while_success, while_true
6
+ from yaspin import yaspin
7
+ from yaspin.spinners import Spinners
6
8
 
7
9
 
8
10
  class BasePlatform(ABC):
@@ -28,9 +30,17 @@ class BasePlatform(ABC):
28
30
 
29
31
  def chat_until_success(self, message: str) -> str:
30
32
  def _chat():
31
- response = self.chat(message)
32
- response = re.sub(r'<think>(.*?)</think>', '', response, flags=re.DOTALL)
33
- return response
33
+ if self.suppress_output:
34
+ with yaspin(Spinners.dots, text="Thinking", color="yellow") as spinner:
35
+ response = self.chat(message)
36
+ response = re.sub(r'<think>(.*?)</think>', '', response, flags=re.DOTALL)
37
+ spinner.ok("✓")
38
+ return response
39
+ else:
40
+ response = self.chat(message)
41
+ response = re.sub(r'<think>(.*?)</think>', '', response, flags=re.DOTALL)
42
+ return response
43
+
34
44
  return while_true(lambda: while_success(lambda: _chat(), 5), 5)
35
45
 
36
46
  @abstractmethod
@@ -5,8 +5,8 @@ import os
5
5
  import mimetypes
6
6
  import time
7
7
  from jarvis.jarvis_platform.base import BasePlatform
8
- from jarvis.utils import PrettyOutput, OutputType
9
- from jarvis.utils import while_success
8
+ from jarvis.jarvis_utils import PrettyOutput, OutputType
9
+ from jarvis.jarvis_utils import while_success
10
10
 
11
11
  class KimiModel(BasePlatform):
12
12
  """Kimi model implementation"""
@@ -1,7 +1,7 @@
1
1
  import requests
2
2
  from typing import List, Dict, Tuple
3
3
  from jarvis.jarvis_platform.base import BasePlatform
4
- from jarvis.utils import OutputType, PrettyOutput, get_single_line_input
4
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, get_single_line_input
5
5
  import os
6
6
  import json
7
7
 
@@ -2,7 +2,7 @@ from typing import Dict, List, Tuple
2
2
  import os
3
3
  from openai import OpenAI
4
4
  from jarvis.jarvis_platform.base import BasePlatform
5
- from jarvis.utils import PrettyOutput, OutputType
5
+ from jarvis.jarvis_utils import PrettyOutput, OutputType
6
6
 
7
7
  class OpenAIModel(BasePlatform):
8
8
  platform_name = "openai"
@@ -2,7 +2,7 @@ import mimetypes
2
2
  import os
3
3
  from typing import Dict, List, Tuple
4
4
  from jarvis.jarvis_platform.base import BasePlatform
5
- from jarvis.utils import PrettyOutput, OutputType
5
+ from jarvis.jarvis_utils import PrettyOutput, OutputType
6
6
  import requests
7
7
  import json
8
8
 
@@ -4,7 +4,7 @@ import os
4
4
  import sys
5
5
  from typing import Dict, Type, Optional, List
6
6
  from jarvis.jarvis_platform.base import BasePlatform
7
- from jarvis.utils import PrettyOutput, OutputType, get_cheap_model_name, get_cheap_platform_name, get_codegen_model_name, get_codegen_platform_name, get_normal_model_name, get_normal_platform_name, get_thinking_model_name, get_thinking_platform_name
7
+ from jarvis.jarvis_utils import PrettyOutput, OutputType, get_cheap_model_name, get_cheap_platform_name, get_codegen_model_name, get_codegen_platform_name, get_normal_model_name, get_normal_platform_name, get_thinking_model_name, get_thinking_platform_name
8
8
 
9
9
  REQUIRED_METHODS = [
10
10
  ('chat', ['message']), # 方法名和参数列表