jarvis-ai-assistant 0.1.111__py3-none-any.whl → 0.1.112__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 (46) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +40 -34
  3. jarvis/jarvis_code_agent/code_agent.py +23 -5
  4. jarvis/jarvis_code_agent/file_select.py +16 -16
  5. jarvis/jarvis_code_agent/patch.py +17 -11
  6. jarvis/jarvis_code_agent/relevant_files.py +33 -40
  7. jarvis/jarvis_codebase/main.py +57 -48
  8. jarvis/jarvis_lsp/cpp.py +1 -1
  9. jarvis/jarvis_lsp/go.py +1 -1
  10. jarvis/jarvis_lsp/python.py +0 -2
  11. jarvis/jarvis_lsp/registry.py +13 -13
  12. jarvis/jarvis_lsp/rust.py +1 -1
  13. jarvis/jarvis_platform/ai8.py +14 -14
  14. jarvis/jarvis_platform/base.py +1 -1
  15. jarvis/jarvis_platform/kimi.py +17 -17
  16. jarvis/jarvis_platform/ollama.py +14 -14
  17. jarvis/jarvis_platform/openai.py +8 -8
  18. jarvis/jarvis_platform/oyi.py +19 -19
  19. jarvis/jarvis_platform/registry.py +6 -6
  20. jarvis/jarvis_platform_manager/main.py +17 -17
  21. jarvis/jarvis_rag/main.py +25 -25
  22. jarvis/jarvis_smart_shell/main.py +6 -6
  23. jarvis/jarvis_tools/ask_codebase.py +3 -3
  24. jarvis/jarvis_tools/ask_user.py +2 -2
  25. jarvis/jarvis_tools/create_code_agent.py +8 -8
  26. jarvis/jarvis_tools/create_sub_agent.py +2 -2
  27. jarvis/jarvis_tools/execute_shell.py +2 -2
  28. jarvis/jarvis_tools/file_operation.py +1 -1
  29. jarvis/jarvis_tools/git_commiter.py +4 -4
  30. jarvis/jarvis_tools/methodology.py +3 -3
  31. jarvis/jarvis_tools/rag.py +3 -3
  32. jarvis/jarvis_tools/read_code.py +1 -1
  33. jarvis/jarvis_tools/read_webpage.py +19 -6
  34. jarvis/jarvis_tools/registry.py +11 -11
  35. jarvis/jarvis_tools/search.py +88 -27
  36. jarvis/jarvis_tools/select_code_files.py +1 -1
  37. jarvis/jarvis_tools/tool_generator.py +182 -0
  38. jarvis/utils.py +18 -20
  39. jarvis_ai_assistant-0.1.112.dist-info/METADATA +460 -0
  40. jarvis_ai_assistant-0.1.112.dist-info/RECORD +64 -0
  41. jarvis_ai_assistant-0.1.111.dist-info/METADATA +0 -461
  42. jarvis_ai_assistant-0.1.111.dist-info/RECORD +0 -63
  43. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/LICENSE +0 -0
  44. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/WHEEL +0 -0
  45. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/entry_points.txt +0 -0
  46. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,182 @@
1
+ """
2
+ Tool Generator Tool - Automatically creates new tools using LLM
3
+ """
4
+ from pathlib import Path
5
+ import re
6
+ from typing import Dict, Any
7
+ from jarvis.jarvis_platform.registry import PlatformRegistry
8
+
9
+ class ToolGenerator:
10
+ name = "tool_generator"
11
+ description = "Generates new tools using LLM that integrate with the system"
12
+ parameters = {
13
+ "type": "object",
14
+ "properties": {
15
+ "tool_name": {
16
+ "type": "string",
17
+ "description": "Name of the new tool"
18
+ },
19
+ "description": {
20
+ "type": "string",
21
+ "description": "Description of the tool's purpose"
22
+ },
23
+ "input_spec": {
24
+ "type": "string",
25
+ "description": "Specification of required inputs and functionality"
26
+ }
27
+ },
28
+ "required": ["tool_name", "description", "input_spec"]
29
+ }
30
+
31
+ def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
32
+ """Generate and save a new tool using LLM"""
33
+ # Get fresh model instance for each execution
34
+ model = PlatformRegistry.get_global_platform_registry().get_codegen_platform()
35
+
36
+ try:
37
+ tool_name = arguments["tool_name"]
38
+ description = arguments["description"]
39
+ input_spec = arguments["input_spec"]
40
+
41
+ # Generate tool implementation using LLM
42
+ prompt = self._create_prompt(tool_name, description, input_spec)
43
+ llm_response = model.chat_until_success(prompt)
44
+
45
+ # Extract implementation with more flexible parsing
46
+ implementation = self._extract_code(llm_response)
47
+ if not implementation:
48
+ return {
49
+ "success": False,
50
+ "stdout": "",
51
+ "stderr": "Could not extract valid Python code from LLM response"
52
+ }
53
+
54
+ # Validate return value format
55
+ if not self._validate_return_value_format(implementation):
56
+ return {
57
+ "success": False,
58
+ "stdout": "",
59
+ "stderr": "Generated tool does not follow required return value format"
60
+ }
61
+
62
+ # Save the new tool
63
+ tools_dir = Path.home() / ".jarvis" / "tools"
64
+ tools_dir.mkdir(parents=True, exist_ok=True)
65
+ tool_file = tools_dir / f"{tool_name}.py"
66
+
67
+ with open(tool_file, "w") as f:
68
+ f.write(implementation)
69
+
70
+ return {
71
+ "success": True,
72
+ "stdout": f"Tool successfully generated at: {tool_file}",
73
+ "stderr": ""
74
+ }
75
+
76
+ except Exception as e:
77
+ return {
78
+ "success": False,
79
+ "stdout": "",
80
+ "stderr": f"Tool generation failed: {str(e)}"
81
+ }
82
+
83
+ def _create_prompt(self, tool_name: str, description: str, input_spec: str) -> str:
84
+ """Create the LLM prompt for tool generation"""
85
+ example_code = '''
86
+ <TOOL>
87
+ from typing import Dict, Any
88
+ from jarvis.utils import OutputType, PrettyOutput
89
+ from jarvis.jarvis_platform.registry import PlatformRegistry
90
+
91
+ class CustomTool:
92
+ name = "Tool name" # Tool name used when calling
93
+ description = "Tool description" # Tool purpose
94
+ parameters = { # Parameters JSON Schema
95
+ "type": "object",
96
+ "properties": {
97
+ "param1": {
98
+ "type": "string",
99
+ "description": "Parameter description"
100
+ }
101
+ },
102
+ "required": ["param1"]
103
+ }
104
+
105
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
106
+ """Execute the tool functionality
107
+
108
+ Args:
109
+ args: Parameters passed to the tool
110
+
111
+ Returns:
112
+ {
113
+ "success": bool,
114
+ "stdout": str,
115
+ "stderr": str,
116
+ }
117
+ """
118
+ try:
119
+ # Implement the tool logic here
120
+ # Use LLM
121
+ # model = PlatformRegistry.get_global_platform_registry().get_codegen_platform()
122
+ # result = model.chat_until_success(prompt)
123
+
124
+ result = "Tool result"
125
+ return {
126
+ "success": True,
127
+ "stdout": result,
128
+ "stderr": ""
129
+ }
130
+ except Exception as e:
131
+ return {
132
+ "success": False,
133
+ "stdout": "",
134
+ "stderr": str(e)
135
+ }
136
+ </TOOL>
137
+ '''
138
+
139
+
140
+ return f'''Create a Python tool class that integrates with the Jarvis system. Follow these requirements:
141
+ 1. Class name: {tool_name.capitalize()}Tool
142
+ 2. Description: {description}
143
+ 3. Input specification: {input_spec}
144
+ 4. Must include these class attributes:
145
+ - name: str (tool identifier)
146
+ - description: str (tool purpose)
147
+ - parameters: dict (JSON schema for inputs)
148
+ 5. Must implement execute(self, args: Dict) -> Dict method
149
+ 6. The execute method MUST return a dictionary with these exact fields:
150
+ - success: bool (indicating operation success)
151
+ - stdout: str (primary output/result)
152
+ - stderr: str (error message if any)
153
+ 7. Must handle errors gracefully
154
+ 8. Return ONLY the Python implementation code
155
+ 9. The code should be complete and ready to use.
156
+ 10. Output the code in the following format:
157
+ <TOOL>
158
+ {example_code}
159
+ </TOOL>
160
+
161
+ Example:
162
+ {example_code}
163
+ '''
164
+
165
+ def _extract_code(self, response: str) -> str:
166
+ """Flexibly extract Python code from LLM response"""
167
+ # Find the first occurrence of <TOOL> and </TOOL>
168
+ sm = re.search(r'<TOOL>(.*?)</TOOL>', response, re.DOTALL)
169
+ if sm:
170
+ return sm.group(1)
171
+ return ""
172
+
173
+ def _validate_return_value_format(self, code: str) -> bool:
174
+ """Validate that execute method returns correct format"""
175
+ required_fields = ["success", "stdout", "stderr"]
176
+ # Look for execute method
177
+ if "def execute(self, args: Dict) -> Dict:" not in code and \
178
+ "def execute(self, args: Dict) -> Dict[str, Any]:" not in code:
179
+ return False
180
+
181
+ # Check for required fields in return statement
182
+ return all(field in code for field in required_fields)
jarvis/utils.py CHANGED
@@ -322,7 +322,7 @@ def get_multiline_input(tip: str) -> str:
322
322
  lines.append(line)
323
323
 
324
324
  except KeyboardInterrupt:
325
- PrettyOutput.print("Input cancelled", OutputType.INFO)
325
+ PrettyOutput.print("输入已取消", OutputType.INFO)
326
326
  return ""
327
327
 
328
328
  return "\n".join(lines)
@@ -348,7 +348,7 @@ def init_env():
348
348
  except ValueError:
349
349
  continue
350
350
  except Exception as e:
351
- PrettyOutput.print(f"Warning: Failed to read {env_file}: {e}", OutputType.WARNING)
351
+ PrettyOutput.print(f"警告: 读取 {env_file} 失败: {e}", OutputType.WARNING)
352
352
 
353
353
 
354
354
  def while_success(func, sleep_time: float = 0.1):
@@ -356,7 +356,7 @@ def while_success(func, sleep_time: float = 0.1):
356
356
  try:
357
357
  return func()
358
358
  except Exception as e:
359
- PrettyOutput.print(f"Execution failed: {str(e)}, retry in {sleep_time}s...", OutputType.ERROR)
359
+ PrettyOutput.print(f"执行失败: {str(e)}, 等待 {sleep_time}s...", OutputType.ERROR)
360
360
  time.sleep(sleep_time)
361
361
  continue
362
362
 
@@ -366,7 +366,7 @@ def while_true(func, sleep_time: float = 0.1):
366
366
  ret = func()
367
367
  if ret:
368
368
  break
369
- PrettyOutput.print(f"Execution failed, retry in {sleep_time}s...", OutputType.WARNING)
369
+ PrettyOutput.print(f"执行失败, 等待 {sleep_time}s...", OutputType.WARNING)
370
370
  time.sleep(sleep_time)
371
371
  return ret
372
372
 
@@ -433,7 +433,7 @@ def load_rerank_model():
433
433
  model_name = "BAAI/bge-reranker-v2-m3"
434
434
  cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
435
435
 
436
- PrettyOutput.print(f"Loading reranking model: {model_name}...", OutputType.INFO)
436
+ PrettyOutput.print(f"加载重排序模型: {model_name}...", OutputType.INFO)
437
437
 
438
438
  try:
439
439
  # Load model and tokenizer
@@ -484,7 +484,7 @@ def is_long_context(files: list) -> bool:
484
484
  if total_tokens > threshold:
485
485
  return True
486
486
  except Exception as e:
487
- PrettyOutput.print(f"Failed to read file {file_path}: {e}", OutputType.WARNING)
487
+ PrettyOutput.print(f"读取文件 {file_path} 失败: {e}", OutputType.WARNING)
488
488
  continue
489
489
 
490
490
  return total_tokens > threshold
@@ -511,13 +511,13 @@ def _create_methodology_embedding(embedding_model: Any, methodology_text: str) -
511
511
  vector = np.array(embedding.cpu().numpy(), dtype=np.float32)
512
512
  return vector[0] # Return first vector, because we only encoded one text
513
513
  except Exception as e:
514
- PrettyOutput.print(f"Failed to create methodology embedding vector: {str(e)}", OutputType.ERROR)
514
+ PrettyOutput.print(f"创建方法论嵌入向量失败: {str(e)}", OutputType.ERROR)
515
515
  return np.zeros(1536, dtype=np.float32)
516
516
 
517
517
 
518
518
  def load_methodology(user_input: str) -> str:
519
519
  """Load methodology and build vector index"""
520
- PrettyOutput.print("Loading methodology...", OutputType.PROGRESS)
520
+ PrettyOutput.print("加载方法论...", OutputType.PROGRESS)
521
521
  user_jarvis_methodology = os.path.expanduser("~/.jarvis/methodology")
522
522
  if not os.path.exists(user_jarvis_methodology):
523
523
  return ""
@@ -565,7 +565,7 @@ def load_methodology(user_input: str) -> str:
565
565
  methodology_index.add_with_ids(vectors_array, np.array(ids)) # type: ignore
566
566
  query_embedding = _create_methodology_embedding(embedding_model, user_input)
567
567
  k = min(3, len(methodology_data))
568
- PrettyOutput.print(f"Retrieving methodology...", OutputType.INFO)
568
+ PrettyOutput.print(f"检索方法论...", OutputType.INFO)
569
569
  distances, indices = methodology_index.search(
570
570
  query_embedding.reshape(1, -1), k
571
571
  ) # type: ignore
@@ -590,9 +590,7 @@ def load_methodology(user_input: str) -> str:
590
590
  return make_methodology_prompt(data)
591
591
 
592
592
  except Exception as e:
593
- PrettyOutput.print(f"Error loading methodology: {str(e)}", OutputType.ERROR)
594
- import traceback
595
- PrettyOutput.print(f"Error trace: {traceback.format_exc()}", OutputType.INFO)
593
+ PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
596
594
  return ""
597
595
 
598
596
 
@@ -648,15 +646,15 @@ def init_gpu_config() -> Dict:
648
646
  torch.cuda.empty_cache()
649
647
 
650
648
  PrettyOutput.print(
651
- f"GPU initialized: {torch.cuda.get_device_name(0)}\n"
652
- f"Device Memory: {gpu_mem / 1024**3:.1f}GB\n"
653
- f"Shared Memory: {config['shared_memory'] / 1024**3:.1f}GB",
649
+ f"GPU已初始化: {torch.cuda.get_device_name(0)}\n"
650
+ f"设备内存: {gpu_mem / 1024**3:.1f}GB\n"
651
+ f"共享内存: {config['shared_memory'] / 1024**3:.1f}GB",
654
652
  output_type=OutputType.SUCCESS
655
653
  )
656
654
  else:
657
- PrettyOutput.print("No GPU available, using CPU mode", output_type=OutputType.WARNING)
655
+ PrettyOutput.print("没有GPU可用, 使用CPU模式", output_type=OutputType.WARNING)
658
656
  except Exception as e:
659
- PrettyOutput.print(f"GPU initialization failed: {str(e)}", output_type=OutputType.WARNING)
657
+ PrettyOutput.print(f"GPU初始化失败: {str(e)}", output_type=OutputType.WARNING)
660
658
 
661
659
  return config
662
660
 
@@ -677,7 +675,7 @@ def get_embedding_batch(embedding_model: Any, texts: List[str]) -> np.ndarray:
677
675
  all_vectors.extend(vectors)
678
676
  return np.vstack(all_vectors)
679
677
  except Exception as e:
680
- PrettyOutput.print(f"Batch embedding failed: {str(e)}", OutputType.ERROR)
678
+ PrettyOutput.print(f"批量嵌入失败: {str(e)}", OutputType.ERROR)
681
679
  return np.zeros((0, embedding_model.get_sentence_embedding_dimension()), dtype=np.float32)
682
680
 
683
681
 
@@ -782,11 +780,11 @@ def get_context_token_count(text: str) -> int:
782
780
  try:
783
781
  # Use a fast tokenizer that's good at general text
784
782
  tokenizer = load_tokenizer()
785
- chunks = split_text_into_chunks(text, 1024)
783
+ chunks = split_text_into_chunks(text, 512)
786
784
  return sum([len(tokenizer.encode(chunk)) for chunk in chunks])
787
785
 
788
786
  except Exception as e:
789
- PrettyOutput.print(f"Error counting tokens: {str(e)}", OutputType.WARNING)
787
+ PrettyOutput.print(f"计算token失败: {str(e)}", OutputType.WARNING)
790
788
  # Fallback to rough character-based estimate
791
789
  return len(text) // 4 # Rough estimate of 4 chars per token
792
790