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

jarvis/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.5"
Binary file
Binary file
Binary file
Binary file
jarvis/agent.py CHANGED
@@ -3,21 +3,32 @@ import subprocess
3
3
  from typing import Dict, Any, List, Optional
4
4
  from .tools import ToolRegistry
5
5
  from .utils import Spinner, PrettyOutput, OutputType, get_multiline_input
6
- from .models import BaseModel, OllamaModel
6
+ from .models import BaseModel
7
7
  import re
8
8
  import os
9
9
  from datetime import datetime
10
10
 
11
11
  class Agent:
12
- def __init__(self, model: BaseModel, tool_registry: ToolRegistry):
12
+ def __init__(self, model: BaseModel, tool_registry: ToolRegistry, name: str = "Jarvis"):
13
+ """Initialize Agent with a model, optional tool registry and name"""
13
14
  self.model = model
14
- self.tool_registry = tool_registry
15
+ self.tool_registry = tool_registry or ToolRegistry(model)
16
+ self.name = name
15
17
  # 编译正则表达式
16
18
  self.tool_call_pattern = re.compile(r'<tool_call>\s*({[^}]+})\s*</tool_call>')
17
19
  self.messages = [
18
20
  {
19
21
  "role": "system",
20
- "content": """You are a rigorous AI assistant, all data must be obtained through tools, and no fabrication or speculation is allowed. """ + "\n" + self.tool_registry.tool_help_text()
22
+ "content": f"""You are {name}, a rigorous AI assistant that executes tasks step by step.
23
+
24
+ Key Principles:
25
+ 1. Execute ONE step at a time
26
+ 2. Wait for each step's result before planning the next
27
+ 3. Use tools to obtain all data, no fabrication
28
+ 4. Create sub-agents for independent subtasks
29
+ 5. Think carefully before each action
30
+
31
+ """ + self.tool_registry.tool_help_text()
21
32
  }
22
33
  ]
23
34
  self.spinner = Spinner()
@@ -28,44 +39,38 @@ class Agent:
28
39
  try:
29
40
  return self.model.chat(
30
41
  messages=messages,
31
- tools=self.tool_registry.get_all_tools() if use_tools else None
42
+ tools=self.tool_registry.get_all_tools() if use_tools else []
32
43
  )
33
44
  except Exception as e:
34
- raise Exception(f"模型调用失败: {str(e)}")
45
+ raise Exception(f"{self.name}: 模型调用失败: {str(e)}")
35
46
  finally:
36
47
  self.spinner.stop()
37
48
 
38
-
39
- def run(self, user_input: str) :
40
- """处理用户输入并返回响应"""
41
- # 检查是否是结束命令
49
+ def run(self, user_input: str) -> str:
50
+ """处理用户输入并返回响应,返回任务总结报告"""
42
51
  self.clear_history()
43
52
  self.messages.append({
44
53
  "role": "user",
45
54
  "content": user_input
46
55
  })
56
+
47
57
  while True:
48
58
  try:
49
- # 获取初始响应
50
59
  response = self._call_model(self.messages)
51
60
  current_response = response
52
61
 
53
- # 将工具执行结果添加到对话
54
62
  self.messages.append({
55
63
  "role": "assistant",
56
64
  "content": response["message"].get("content", ""),
57
65
  "tool_calls": current_response["message"]["tool_calls"]
58
66
  })
59
67
 
60
- # 处理可能的多轮工具调用
61
68
  if len(current_response["message"]["tool_calls"]) > 0:
62
- # 添加当前助手响应到输出(如果有内容)
63
69
  if current_response["message"].get("content"):
64
- PrettyOutput.print(current_response["message"]["content"], OutputType.SYSTEM)
70
+ PrettyOutput.print(f"{self.name}: {current_response['message']['content']}", OutputType.SYSTEM)
65
71
 
66
- # 使用 ToolRegistry 的 handle_tool_calls 方法处理工具调用
67
72
  tool_result = self.tool_registry.handle_tool_calls(current_response["message"]["tool_calls"])
68
- PrettyOutput.print(tool_result, OutputType.RESULT)
73
+ PrettyOutput.print(f"{self.name} Tool Result: {tool_result}", OutputType.RESULT)
69
74
 
70
75
  self.messages.append({
71
76
  "role": "tool",
@@ -73,18 +78,46 @@ class Agent:
73
78
  })
74
79
  continue
75
80
 
76
- # 添加最终响应到对话历史和输出
77
81
  final_content = current_response["message"].get("content", "")
78
-
79
82
  if final_content:
80
- PrettyOutput.print(final_content, OutputType.SYSTEM)
81
-
83
+ PrettyOutput.print(f"{self.name}: {final_content}", OutputType.SYSTEM)
82
84
 
83
- # 如果没有工具调用且响应很短,可能需要继续对话
84
- user_input = get_multiline_input("您可以继续输入,或输入空行结束当前任务")
85
- if not user_input:
86
- PrettyOutput.print("===============任务结束===============", OutputType.INFO)
87
- break
85
+ user_input = get_multiline_input(f"{self.name}: 您可以继续输入,或输入空行结束当前任务")
86
+ if not user_input:
87
+ PrettyOutput.print(f"{self.name}: 正在生成任务总结...", OutputType.INFO)
88
+
89
+ # 优化后的任务总结提示语
90
+ summary_prompt = {
91
+ "role": "user",
92
+ "content": """The task has been completed. Based on the previous analysis and execution results, provide a task summary including:
93
+
94
+ 1. Key Information:
95
+ - Essential findings from analysis
96
+ - Important results from tool executions
97
+ - Critical data discovered
98
+
99
+ 2. Task Results:
100
+ - Final outcome
101
+ - Actual achievements
102
+ - Concrete results
103
+
104
+ Focus only on facts and actual results. Be direct and concise."""
105
+ }
106
+ while True:
107
+ try:
108
+ summary_response = self._call_model(self.messages + [summary_prompt], use_tools=False)
109
+ summary = summary_response["message"].get("content", "")
110
+
111
+ PrettyOutput.print(f"==============={self.name} 任务总结===============", OutputType.INFO)
112
+ PrettyOutput.print(summary, OutputType.SYSTEM)
113
+ PrettyOutput.print("=" * (len(self.name) + 16), OutputType.INFO)
114
+
115
+ return summary
116
+
117
+ except Exception as e:
118
+ error_msg = f"{self.name}: 生成任务总结时出错: {str(e)}"
119
+ PrettyOutput.print(error_msg, OutputType.ERROR)
120
+
88
121
 
89
122
  self.messages.append({
90
123
  "role": "user",
@@ -92,7 +125,7 @@ class Agent:
92
125
  })
93
126
 
94
127
  except Exception as e:
95
- error_msg = f"处理响应时出错: {str(e)}"
128
+ error_msg = f"{self.name}: 处理响应时出错: {str(e)}"
96
129
  PrettyOutput.print(error_msg, OutputType.ERROR)
97
130
 
98
131
  def clear_history(self):
jarvis/main.py CHANGED
@@ -13,7 +13,8 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
13
13
  from jarvis.agent import Agent
14
14
  from jarvis.tools import ToolRegistry
15
15
  from jarvis.models import DDGSModel, OllamaModel
16
- from jarvis.utils import PrettyOutput, OutputType, get_multiline_input
16
+ from jarvis.utils import PrettyOutput, OutputType, get_multiline_input, load_env_from_file
17
+ from jarvis.zte_llm import create_zte_llm
17
18
 
18
19
  # 定义支持的平台和模型
19
20
  SUPPORTED_PLATFORMS = {
@@ -24,35 +25,48 @@ SUPPORTED_PLATFORMS = {
24
25
  "ddgs": {
25
26
  "models": ["gpt-4o-mini", "claude-3-haiku", "llama-3.1-70b", "mixtral-8x7b"],
26
27
  "default": "gpt-4o-mini"
28
+ },
29
+ "zte": {
30
+ "models": ["NebulaBiz", "nebulacoder", "NTele-72B"],
31
+ "default": "NebulaBiz"
27
32
  }
28
33
  }
29
34
 
30
- def load_tasks() -> list:
35
+ def load_tasks() -> dict:
31
36
  """Load tasks from .jarvis file if it exists."""
32
37
  if not os.path.exists(".jarvis"):
33
- return []
38
+ return {}
34
39
 
35
40
  try:
36
41
  with open(".jarvis", "r", encoding="utf-8") as f:
37
42
  tasks = yaml.safe_load(f)
38
43
 
39
- if not isinstance(tasks, list):
40
- PrettyOutput.print("Warning: .jarvis file should contain a list of tasks", OutputType.ERROR)
41
- return []
44
+ if not isinstance(tasks, dict):
45
+ PrettyOutput.print("Warning: .jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
46
+ return {}
42
47
 
43
- return [str(task) for task in tasks if task] # Convert all tasks to strings and filter out empty ones
48
+ # Validate format and convert all values to strings
49
+ validated_tasks = {}
50
+ for name, desc in tasks.items():
51
+ if desc: # Ensure description is not empty
52
+ validated_tasks[str(name)] = str(desc)
53
+
54
+ return validated_tasks
44
55
  except Exception as e:
45
56
  PrettyOutput.print(f"Error loading .jarvis file: {str(e)}", OutputType.ERROR)
46
- return []
57
+ return {}
47
58
 
48
- def select_task(tasks: list) -> str:
49
- """Let user select a task from the list or skip."""
59
+ def select_task(tasks: dict) -> str:
60
+ """Let user select a task from the list or skip. Returns task description if selected."""
50
61
  if not tasks:
51
62
  return ""
52
63
 
53
- PrettyOutput.print("\nFound predefined tasks:", OutputType.INFO)
54
- for i, task in enumerate(tasks, 1):
55
- PrettyOutput.print(f"[{i}] {task}", OutputType.INFO)
64
+ # Convert tasks to list for ordered display
65
+ task_names = list(tasks.keys())
66
+
67
+ PrettyOutput.print("\nAvailable tasks:", OutputType.INFO)
68
+ for i, name in enumerate(task_names, 1):
69
+ PrettyOutput.print(f"[{i}] {name}", OutputType.INFO)
56
70
  PrettyOutput.print("[0] Skip predefined tasks", OutputType.INFO)
57
71
 
58
72
  while True:
@@ -64,8 +78,9 @@ def select_task(tasks: list) -> str:
64
78
  choice = int(choice)
65
79
  if choice == 0:
66
80
  return ""
67
- elif 1 <= choice <= len(tasks):
68
- return tasks[choice - 1]
81
+ elif 1 <= choice <= len(task_names):
82
+ selected_name = task_names[choice - 1]
83
+ return tasks[selected_name] # Return the task description
69
84
  else:
70
85
  PrettyOutput.print("Invalid choice. Please try again.", OutputType.ERROR)
71
86
  except ValueError:
@@ -79,7 +94,7 @@ def main():
79
94
  parser.add_argument(
80
95
  "--platform",
81
96
  choices=list(SUPPORTED_PLATFORMS.keys()),
82
- default="ollama",
97
+ default="ddgs",
83
98
  help="选择运行平台 (默认: ollama)"
84
99
  )
85
100
 
@@ -97,6 +112,8 @@ def main():
97
112
  )
98
113
 
99
114
  args = parser.parse_args()
115
+
116
+ load_env_from_file()
100
117
 
101
118
  # 验证并设置默认模型
102
119
  if args.model:
@@ -119,11 +136,14 @@ def main():
119
136
  api_base=args.api_base
120
137
  )
121
138
  platform_name = f"Ollama ({args.model})"
122
- else: # ddgs
139
+ elif args.platform == "ddgs": # ddgs
123
140
  model = DDGSModel(model_name=args.model)
124
141
  platform_name = f"DuckDuckGo Search ({args.model})"
142
+ elif args.platform == "zte": # zte
143
+ model = create_zte_llm(model_name=args.model)
144
+ platform_name = f"ZTE ({args.model})"
125
145
 
126
- tool_registry = ToolRegistry()
146
+ tool_registry = ToolRegistry(model)
127
147
  agent = Agent(model, tool_registry)
128
148
 
129
149
  # 欢迎信息
jarvis/models.py CHANGED
@@ -20,31 +20,29 @@ class BaseModel(ABC):
20
20
  def extract_tool_calls(content: str) -> List[Dict]:
21
21
  """从内容中提取工具调用"""
22
22
  tool_calls = []
23
- # 修改正则表达式以更好地处理多行内容
24
- pattern = re.compile(
25
- r'<tool_call>\s*({(?:[^{}]|(?:{[^{}]*})|(?:{(?:[^{}]|{[^{}]*})*}))*})\s*</tool_call>',
26
- re.DOTALL # 添加DOTALL标志以匹配跨行内容
27
- )
23
+ # 使用非贪婪匹配来获取标签之间的所有内容
24
+ pattern = re.compile(r'<tool_call>(.*?)</tool_call>', re.DOTALL)
28
25
 
29
26
  matches = pattern.finditer(content)
30
27
  for match in matches:
31
28
  try:
32
- tool_call_str = match.group(1).strip()
33
- tool_call = json.loads(tool_call_str)
34
- if isinstance(tool_call, dict) and "name" in tool_call and "arguments" in tool_call:
29
+ # 提取并解析 JSON
30
+ tool_call_text = match.group(1).strip()
31
+ tool_call_data = json.loads(tool_call_text)
32
+
33
+ # 验证必要的字段
34
+ if "name" in tool_call_data and "arguments" in tool_call_data:
35
35
  tool_calls.append({
36
36
  "function": {
37
- "name": tool_call["name"],
38
- "arguments": tool_call["arguments"]
37
+ "name": tool_call_data["name"],
38
+ "arguments": tool_call_data["arguments"]
39
39
  }
40
40
  })
41
- else:
42
- PrettyOutput.print(f"无效的工具调用格式: {tool_call_str}", OutputType.ERROR)
43
- except json.JSONDecodeError as e:
44
- PrettyOutput.print(f"JSON解析错误: {str(e)}", OutputType.ERROR)
45
- PrettyOutput.print(f"解析内容: {tool_call_str}", OutputType.ERROR)
46
- continue
47
-
41
+ except json.JSONDecodeError:
42
+ continue # 跳过无效的 JSON
43
+ except Exception:
44
+ continue # 跳过其他错误
45
+
48
46
  return tool_calls
49
47
 
50
48
 
jarvis/tools/__init__.py CHANGED
@@ -3,9 +3,6 @@ from .python_script import PythonScript
3
3
  from .file_ops import FileOperationTool
4
4
  from .search import SearchTool
5
5
  from .shell import ShellTool
6
- from .user_interaction import UserInteractionTool
7
- from .user_confirmation import UserConfirmationTool
8
- from .rag import RAGTool
9
6
  from .webpage import WebpageTool
10
7
 
11
8
  __all__ = [
@@ -15,8 +12,5 @@ __all__ = [
15
12
  'FileOperationTool',
16
13
  'SearchTool',
17
14
  'ShellTool',
18
- 'UserInteractionTool',
19
- 'UserConfirmationTool',
20
- 'RAGTool',
21
15
  'WebpageTool',
22
16
  ]
jarvis/tools/base.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from typing import Dict, Any, List, Optional, Callable
2
2
  import json
3
3
  from ..utils import PrettyOutput, OutputType
4
+ from ..models import BaseModel
4
5
 
5
6
  class Tool:
6
7
  def __init__(self, name: str, description: str, parameters: Dict, func: Callable):
@@ -25,29 +26,25 @@ class Tool:
25
26
  return self.func(arguments)
26
27
 
27
28
  class ToolRegistry:
28
- def __init__(self):
29
+ def __init__(self, model: BaseModel):
29
30
  self.tools: Dict[str, Tool] = {}
31
+ self.model = model
30
32
  self._register_default_tools()
31
33
 
32
34
  def _register_default_tools(self):
33
35
  """注册所有默认工具"""
34
36
  from .search import SearchTool
35
37
  from .shell import ShellTool
36
- from .user_interaction import UserInteractionTool
37
- from .user_confirmation import UserConfirmationTool
38
38
  from .python_script import PythonScriptTool
39
39
  from .file_ops import FileOperationTool
40
- from .rag import RAGTool
41
40
  from .webpage import WebpageTool
41
+ from .sub_agent import SubAgentTool
42
42
 
43
43
  tools = [
44
44
  SearchTool(),
45
45
  ShellTool(),
46
- UserInteractionTool(),
47
- UserConfirmationTool(),
48
46
  PythonScriptTool(),
49
47
  FileOperationTool(),
50
- RAGTool(),
51
48
  WebpageTool(),
52
49
  ]
53
50
 
@@ -59,6 +56,14 @@ class ToolRegistry:
59
56
  func=tool.execute
60
57
  )
61
58
 
59
+ sub_agent_tool = SubAgentTool(self.model)
60
+ self.register_tool(
61
+ name=sub_agent_tool.name,
62
+ description=sub_agent_tool.description,
63
+ parameters=sub_agent_tool.parameters,
64
+ func=sub_agent_tool.execute
65
+ )
66
+
62
67
  def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
63
68
  """注册新工具"""
64
69
  self.tools[name] = Tool(name, description, parameters, func)
@@ -117,64 +122,77 @@ class ToolRegistry:
117
122
  def tool_help_text(self) -> str:
118
123
  """返回所有工具的帮助文本"""
119
124
  return """Available Tools:
125
+
120
126
  1. search: Search for information using DuckDuckGo
121
127
  2. read_webpage: Extract content from webpages
122
128
  3. execute_python: Run Python code with dependency management
123
129
  4. execute_shell: Execute shell commands
124
- 5. ask_user: Get input from user with options support
125
- 6. ask_user_confirmation: Get yes/no confirmation from user
126
- 7. file_operation: Read/write files in workspace directory
127
- 8. rag_query: Query documents using RAG
128
-
129
- Output Guidelines:
130
- 1. Focus on Essential Information
131
- - Filter out irrelevant or redundant information
132
- - Only output the most relevant search results
133
- - Summarize long content when possible
134
-
135
- 2. Context Management
136
- - Avoid repeating information that's already known
137
- - Don't echo back the entire content of files
138
- - Use snippets instead of full documents
139
-
140
- 3. Error Handling
141
- - Only show relevant parts of error messages
142
- - Include troubleshooting steps when appropriate
143
- - Omit stack traces unless specifically requested
144
-
145
- 4. Search Results
146
- - Focus on the most relevant 2-3 results
147
- - Extract key information instead of full articles
148
- - Skip duplicate or similar content
149
-
150
- 5. RAG Queries
151
- - Return only the most relevant passages
152
- - Combine similar information
153
- - Skip redundant context
154
-
155
- Tool Usage Examples:
130
+ 5. file_operation: Read/write files in workspace directory
131
+ 6. create_sub_agent: Create a sub-agent to handle subtasks (ONLY for independent subtasks)
132
+
133
+ Core Rules:
134
+ 1. ONE Step at a Time
135
+ - Execute only one action per response
136
+ - Explain what you're going to do before doing it
137
+ - Wait for the result before planning next step
138
+ - No multiple actions or parallel execution
139
+
140
+ 2. Sub-Agent Usage (ONLY for Subtasks)
141
+ - Create sub-agents ONLY to handle independent subtasks
142
+ - Main task should be broken down into clear subtasks first
143
+ - Examples of good subtask delegation:
144
+ * Analyzing each Python file in a directory
145
+ * Processing each data file in a batch
146
+ * Researching different aspects of a topic
147
+ * Reviewing multiple code components
148
+ - Do NOT use for:
149
+ * Main task execution
150
+ * Single file operations
151
+ * Simple sequential steps
152
+ * Tasks requiring continuous context
153
+
154
+ 3. Output Guidelines
155
+ - Focus on essential information
156
+ - Clear step-by-step explanations
157
+ - Summarize results concisely
158
+
159
+ Tool Call Format:
160
+ <tool_call>
161
+ {
162
+ "name": "tool_name",
163
+ "arguments": {
164
+ "param1": "value1"
165
+ }
166
+ }
167
+ </tool_call>
168
+
169
+ Example (Correct - Subtask Delegation):
170
+ Assistant: I'll create a sub-agent to handle the code analysis subtask.
156
171
  <tool_call>
157
172
  {
158
- "name": "search",
173
+ "name": "create_sub_agent",
159
174
  "arguments": {
160
- "query": "Python GIL",
161
- "max_results": 2 # Limit results to save context
175
+ "name": "CodeAnalyzer",
176
+ "task": "Analyze the utils.py file structure and generate documentation",
177
+ "context": "This is part of the larger documentation task"
162
178
  }
163
179
  }
164
180
  </tool_call>
165
181
 
182
+ Example (Incorrect - Main Task):
183
+ ❌ Assistant: I'll create a sub-agent to handle the entire project analysis.
166
184
  <tool_call>
167
185
  {
168
- "name": "read_webpage",
186
+ "name": "create_sub_agent",
169
187
  "arguments": {
170
- "url": "https://example.com",
171
- "extract_type": "text" # Only get main content
188
+ "name": "ProjectAnalyzer",
189
+ "task": "Analyze and document the entire project"
172
190
  }
173
191
  }
174
192
  </tool_call>
175
193
 
176
194
  Remember:
177
- 1. Quality over quantity
178
- 2. Relevance over completeness
179
- 3. Conciseness over verbosity
180
- 4. Context efficiency is crucial"""
195
+ 1. ONE step at a time
196
+ 2. Create sub-agents ONLY for subtasks
197
+ 3. Explain before acting
198
+ 4. Wait for results"""
jarvis/tools/shell.py CHANGED
@@ -4,13 +4,27 @@ from ..utils import PrettyOutput, OutputType
4
4
 
5
5
  class ShellTool:
6
6
  name = "execute_shell"
7
- description = "Execute shell commands and return the results"
7
+ description = """Execute shell commands and return the results.
8
+ Guidelines for output optimization:
9
+ 1. Use grep/awk/sed to filter output when possible
10
+ 2. Avoid listing all files/dirs unless specifically needed
11
+ 3. Prefer -q/--quiet flags when status is all that's needed
12
+ 4. Use head/tail to limit long outputs
13
+ 5. Redirect stderr to /dev/null for noisy commands
14
+
15
+ Examples of optimized commands:
16
+ - 'ls -l file.txt' instead of 'ls -l'
17
+ - 'grep -c pattern file' instead of 'grep pattern file'
18
+ - 'ps aux | grep process | head -n 5' instead of 'ps aux'
19
+ - 'command 2>/dev/null' to suppress error messages
20
+ - 'df -h . ' instead of 'df -h'
21
+ """
8
22
  parameters = {
9
23
  "type": "object",
10
24
  "properties": {
11
25
  "command": {
12
26
  "type": "string",
13
- "description": "Shell command to execute"
27
+ "description": "Shell command to execute (use filters/limits for large outputs)"
14
28
  },
15
29
  "timeout": {
16
30
  "type": "integer",
@@ -0,0 +1,79 @@
1
+ from typing import Dict, Any
2
+ from ..agent import Agent
3
+ from ..models import BaseModel
4
+ from ..utils import PrettyOutput, OutputType
5
+ from .base import ToolRegistry
6
+
7
+ class SubAgentTool:
8
+ name = "create_sub_agent"
9
+ description = """Create a sub-agent to handle independent tasks.
10
+
11
+ Use this tool when:
12
+ 1. A subtask can be executed independently
13
+ 2. The task requires separate context management
14
+ 3. To optimize token usage of the main agent
15
+ 4. For parallel task processing
16
+
17
+ The sub-agent will:
18
+ 1. Inherit all tools from the parent agent
19
+ 2. Maintain its own conversation history
20
+ 3. Return a comprehensive task summary
21
+ """
22
+ parameters = {
23
+ "type": "object",
24
+ "properties": {
25
+ "name": {
26
+ "type": "string",
27
+ "description": "Name for the sub-agent (e.g., 'FileAnalyzer', 'CodeReviewer')"
28
+ },
29
+ "task": {
30
+ "type": "string",
31
+ "description": "Task description with complete context"
32
+ },
33
+ "context": {
34
+ "type": "string",
35
+ "description": "Additional context or background information",
36
+ "default": ""
37
+ }
38
+ },
39
+ "required": ["name", "task"]
40
+ }
41
+
42
+ def __init__(self, model: BaseModel):
43
+ """Initialize with the same model as parent agent"""
44
+ self.model = model
45
+
46
+ def execute(self, args: Dict) -> Dict[str, Any]:
47
+ """Create and run a sub-agent for the specified task"""
48
+ try:
49
+ name = args["name"]
50
+ task = args["task"]
51
+ context = args.get("context", "")
52
+
53
+ PrettyOutput.print(f"Creating sub-agent '{name}'...", OutputType.INFO)
54
+
55
+ # Create a new tool registry for the sub-agent
56
+ tool_registry = ToolRegistry(self.model)
57
+
58
+ # Create the sub-agent with the specified name
59
+ sub_agent = Agent(self.model, tool_registry, name=name)
60
+
61
+ # Prepare the task with context if provided
62
+ full_task = f"{context}\n\nTask: {task}" if context else task
63
+
64
+ PrettyOutput.print(f"Sub-agent '{name}' executing task...", OutputType.INFO)
65
+
66
+ # Execute the task and get the summary
67
+ summary = sub_agent.run(full_task)
68
+
69
+ return {
70
+ "success": True,
71
+ "stdout": f"Sub-agent '{name}' completed the task.\n\nSummary:\n{summary}",
72
+ "stderr": ""
73
+ }
74
+
75
+ except Exception as e:
76
+ return {
77
+ "success": False,
78
+ "error": f"Sub-agent execution failed: {str(e)}"
79
+ }
jarvis/utils.py CHANGED
@@ -1,11 +1,13 @@
1
+ from pathlib import Path
1
2
  import sys
2
3
  import time
3
4
  import threading
4
- from typing import Optional
5
+ from typing import Dict, Optional
5
6
  from enum import Enum
6
7
  from datetime import datetime
7
8
  import colorama
8
9
  from colorama import Fore, Style
10
+ import os
9
11
 
10
12
  # 初始化colorama
11
13
  colorama.init()
@@ -102,4 +104,25 @@ def get_multiline_input(tip: str) -> str:
102
104
  PrettyOutput.print("\n输入已取消", OutputType.ERROR)
103
105
  return ""
104
106
 
105
- return "\n".join(lines).strip()
107
+ return "\n".join(lines).strip()
108
+
109
+
110
+ def load_env_from_file():
111
+ """Load environment variables from ~/.jarvis_env file"""
112
+ env_file = Path.home() / ".jarvis_env"
113
+
114
+ if env_file.exists():
115
+ try:
116
+ with open(env_file, "r", encoding="utf-8") as f:
117
+ for line in f:
118
+ line = line.strip()
119
+ if line and not line.startswith("#"):
120
+ try:
121
+ key, value = line.split("=", 1)
122
+ os.environ[key.strip()] = value.strip().strip("'").strip('"')
123
+ except ValueError:
124
+ continue
125
+ except Exception as e:
126
+ print(f"Warning: Failed to read ~/.jarvis_env: {e}")
127
+
128
+
jarvis/zte_llm.py ADDED
@@ -0,0 +1,132 @@
1
+ import requests
2
+ import json
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Dict, Any, List, Optional
6
+ from .models import BaseModel
7
+
8
+ class ZteLLM(BaseModel):
9
+ """ZTE Nebula LLM implementation"""
10
+
11
+ def __init__(self,
12
+ app_id: str,
13
+ app_key: str,
14
+ emp_no: str,
15
+ auth_value: str,
16
+ model: str = "nebulacoder",
17
+ ):
18
+ """Initialize ZTE LLM with required credentials"""
19
+ self.app_id = str(app_id)
20
+ self.app_key = str(app_key)
21
+ self.emp_no = str(emp_no)
22
+ self.auth_value = str(auth_value)
23
+ self.model = model
24
+ self.base_url = "https://studio.zte.com.cn/zte-studio-ai-platform/openapi/v1"
25
+
26
+ def _make_request(self, endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]:
27
+ """Make request to ZTE API"""
28
+ headers = {
29
+ 'Content-Type': 'application/json',
30
+ 'Authorization': f'Bearer {self.app_id}-{self.app_key}',
31
+ 'X-Emp-No': self.emp_no,
32
+ 'X-Auth-Value': self.auth_value
33
+ }
34
+
35
+ response = requests.post(
36
+ f"{self.base_url}/{endpoint}",
37
+ headers=headers,
38
+ json=data
39
+ )
40
+
41
+ response.raise_for_status()
42
+ result = response.json()
43
+
44
+ if result["code"]["code"] != "0000":
45
+ raise Exception(f"API Error: {result['code']['msg']}")
46
+
47
+ return result["bo"]
48
+
49
+ def chat(self, messages: List[Dict[str, Any]], tools: Optional[List[Dict]] = None) -> Dict[str, Any]:
50
+ """Chat with ZTE LLM"""
51
+ # Convert messages to prompt
52
+ prompt = self._convert_messages_to_prompt(messages)
53
+
54
+ # Prepare data for API call
55
+ data = {
56
+ "chatUuid": "",
57
+ "chatName": "",
58
+ "stream": False,
59
+ "keep": False,
60
+ "text": prompt,
61
+ "model": self.model
62
+ }
63
+
64
+ # If tools are provided, add them to the prompt
65
+ if tools:
66
+ tools_desc = "Available tools:\n\n" + json.dumps(tools, indent=2, ensure_ascii=False)
67
+ data["text"] = tools_desc + "\n\n" + data["text"]
68
+
69
+ try:
70
+ result = self._make_request("chat", data)
71
+
72
+ # Parse the response to extract potential tool calls
73
+ response_text = result["result"]
74
+ tool_calls = BaseModel.extract_tool_calls(response_text)
75
+
76
+ return {
77
+ "message": {
78
+ "content": response_text,
79
+ "tool_calls": tool_calls
80
+ }
81
+ }
82
+
83
+ except Exception as e:
84
+ raise Exception(f"ZTE LLM chat failed: {str(e)}")
85
+
86
+ def _convert_messages_to_prompt(self, messages: List[Dict[str, Any]]) -> str:
87
+ """Convert message list to a single prompt string"""
88
+ prompt_parts = []
89
+
90
+ for message in messages:
91
+ role = message["role"]
92
+ content = message.get("content", "")
93
+
94
+ if role == "system":
95
+ prompt_parts.append(f"System: {content}")
96
+ elif role == "user":
97
+ prompt_parts.append(f"User: {content}")
98
+ elif role == "assistant":
99
+ prompt_parts.append(f"Assistant: {content}")
100
+ elif role == "tool":
101
+ prompt_parts.append(f"Tool Result: {content}")
102
+
103
+ return "\n\n".join(prompt_parts)
104
+
105
+
106
+ def create_zte_llm(model_name: str = "NebulaBiz") -> ZteLLM:
107
+ """Create ZTE LLM instance with provided parameters"""
108
+ # Load environment variables from file
109
+
110
+ # Get credentials from parameters, env file, or system environment variables
111
+ app_id = os.getenv('ZTE_APP_ID')
112
+ app_key = os.getenv('ZTE_APP_KEY')
113
+ emp_no = os.getenv('ZTE_EMP_NO')
114
+ auth_value = os.getenv('ZTE_AUTH_VALUE')
115
+
116
+ # Validate required credentials
117
+ if not all([app_id, app_key, emp_no, auth_value]):
118
+ raise ValueError(
119
+ "Missing required credentials. Please provide through either:\n"
120
+ "1. Function parameters\n"
121
+ "2. ~/.jarvis_env file\n"
122
+ "3. System environment variables\n\n"
123
+ "Required variables: ZTE_APP_ID, ZTE_APP_KEY, ZTE_EMP_NO, ZTE_AUTH_VALUE"
124
+ )
125
+
126
+ return ZteLLM(
127
+ app_id=app_id,
128
+ app_key=app_key,
129
+ emp_no=emp_no,
130
+ auth_value=auth_value,
131
+ model=model_name
132
+ )
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.2
3
+ Version: 0.1.5
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -21,13 +21,15 @@ Requires-Dist: beautifulsoup4>=4.9.3
21
21
  Requires-Dist: duckduckgo-search>=3.0.0
22
22
  Requires-Dist: pyyaml>=5.1
23
23
  Requires-Dist: ollama>=0.1.6
24
- Requires-Dist: sentence-transformers>=2.5.1
25
- Requires-Dist: chromadb>=0.4.24
24
+ Requires-Dist: colorama>=0.4.6
26
25
  Provides-Extra: dev
27
26
  Requires-Dist: pytest; extra == "dev"
28
27
  Requires-Dist: black; extra == "dev"
29
28
  Requires-Dist: isort; extra == "dev"
30
29
  Requires-Dist: mypy; extra == "dev"
30
+ Dynamic: author
31
+ Dynamic: home-page
32
+ Dynamic: requires-python
31
33
 
32
34
  <div align="center">
33
35
 
@@ -0,0 +1,38 @@
1
+ jarvis/.jarvis,sha256=S4ZMmLqlVLHAPmnwHFQ3vYt0gnDFp-KQRH4okBh8Hpw,209
2
+ jarvis/__init__.py,sha256=ArINt8uI8UveWy3H6iPntzn05IR-PEq6P7qb8dzmPjc,49
3
+ jarvis/agent.py,sha256=YdtSBqwGl8xKN9xWIqYcAgxsLmXKyXzLcJ1D-Oie9fE,5536
4
+ jarvis/main.py,sha256=egbfAhkHUGHI5J3j5ZMwb9EgOXE7ikJef-4lqFj0-mA,6063
5
+ jarvis/models.py,sha256=NWXMsgnw6AHkfk22tvmGOjcyVhC74Us-t3T6rUF4R20,4186
6
+ jarvis/utils.py,sha256=-5tugkGABZdi2QXVStVtCQfag9CRTfCsGUvReitmHUM,3816
7
+ jarvis/zte_llm.py,sha256=ygUeGd8WGm0qrnkt5TrCLnaf5ZFZ0tdfwrA7nrByt4g,4504
8
+ jarvis/__pycache__/__init__.cpython-313.pyc,sha256=viNe2ZOgBWfBtJpzh5J0oAhQphAwJi4m2ogxgBgCt6s,208
9
+ jarvis/__pycache__/agent.cpython-313.pyc,sha256=7Ae1sOwF6W2HCGjzDToWdCOYFiS47EUqDZVCz2OxH9Q,7125
10
+ jarvis/__pycache__/main.cpython-313.pyc,sha256=lNKrL5HZQahMGpv5cOVriWZoNOScMWRk_toYD7X-Xeo,7444
11
+ jarvis/__pycache__/models.cpython-313.pyc,sha256=fot2VOV0lgODg4b_WuD-kkq-g7uZGLuZlYXiljlW13U,6350
12
+ jarvis/__pycache__/tools.cpython-313.pyc,sha256=lAD4LrnnWzNZQmHXGfZ_2l7oskOpr2_2OC-gdFhxQY8,33933
13
+ jarvis/__pycache__/utils.cpython-313.pyc,sha256=m9l4R4U1vCG2WkXXNWCTbSASRiS6tWYEWK8pu29EtY4,7175
14
+ jarvis/__pycache__/zte_llm.cpython-313.pyc,sha256=PcS-P2H96EyelWcPleCIcu0lGYYoLrdi9VSZgg2cooA,5340
15
+ jarvis/tools/__init__.py,sha256=NZqKPfIbBxeM5FOrN1ssQQ4S9gVXNCSVXa3ov73AyEk,356
16
+ jarvis/tools/base.py,sha256=I_XIwxb6hCH82qCVPESbDNC93Dj0G3KVSZRXSh6mHIM,6516
17
+ jarvis/tools/file_ops.py,sha256=05Vc4u-NGMjLD15WI52eL_nt_RyYt-Z_cXJnnBepf-c,3781
18
+ jarvis/tools/python_script.py,sha256=_eK8LqNs-Mz50zdcgwbjdd8-qAeOl6kJ_qRDvWawGMw,5006
19
+ jarvis/tools/search.py,sha256=dyJmeP_s2tWv5KQejOl-TuVF12B6SXViiXEyTemD1Wo,1412
20
+ jarvis/tools/shell.py,sha256=VhEqEdoUGIRW6CT6F0YNMAlzJxpHcsKS9hSS0VC3ezw,2644
21
+ jarvis/tools/sub_agent.py,sha256=vC495JBAEMgHbAkHzGlYhIPA5scKekwhy1RViNcwqy8,2683
22
+ jarvis/tools/webpage.py,sha256=UTEomu5j7jbOw8c5az2jsjv5E7LeokWKj1QahvZO7xc,3077
23
+ jarvis/tools/__pycache__/__init__.cpython-313.pyc,sha256=Qng3CpxPy9R_1hTjSSr_qLXHtlI8GneyYX6JHwUtmHE,642
24
+ jarvis/tools/__pycache__/base.cpython-313.pyc,sha256=wXXQs94_MAEuHVhFx80q_IgWBRuo1I4Dc7wz3G9ZMo4,8544
25
+ jarvis/tools/__pycache__/file_ops.cpython-313.pyc,sha256=bawv11xhWSj5wCtW0QeJLI-InhUBUXaSkogq6rZzvTQ,3636
26
+ jarvis/tools/__pycache__/python_script.cpython-313.pyc,sha256=8JpryqTovEiTvBlWAK1KjZmPvHUuPc9GT9rTXBEQoJc,6693
27
+ jarvis/tools/__pycache__/rag.cpython-313.pyc,sha256=JH6-PSZRMKAvTZqCwlRXJGClxYXNMs-vetU0q7hBLz0,6064
28
+ jarvis/tools/__pycache__/search.cpython-313.pyc,sha256=VX9zztOwIsPCkYwev0A0XJGyu4Tr0PQcQkbbqx8vfB0,1870
29
+ jarvis/tools/__pycache__/shell.cpython-313.pyc,sha256=UUciwt3nW3mkHrMI7WvCASQ-YLwVx2N68RzQq97nL74,2972
30
+ jarvis/tools/__pycache__/sub_agent.cpython-313.pyc,sha256=p6vgjqdHW7ZAJYaiDh6F39CMndeA3tutbxXB9cwc6xY,3003
31
+ jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc,sha256=wK3Ev10lHSUSRvoYmi7A0GzxYkzU-C4Wfhs5qW_HBqs,2271
32
+ jarvis/tools/__pycache__/user_interaction.cpython-313.pyc,sha256=RuVZ-pmiPBDywY3efgXSfohMAciC1avMGPmBK5qlnew,3305
33
+ jarvis/tools/__pycache__/webpage.cpython-313.pyc,sha256=VcpkaV8IyOOtebedXjn8ybjr8AglU-3-Cs80yzE4FYo,3628
34
+ jarvis_ai_assistant-0.1.5.dist-info/METADATA,sha256=pZCtN2L3EmGQMvpbxA6vED4RHJIWdJqXC2JnaD0whEw,3690
35
+ jarvis_ai_assistant-0.1.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
36
+ jarvis_ai_assistant-0.1.5.dist-info/entry_points.txt,sha256=iKu7OMfew9dtfGhW71gIMTg4wvafuPqKb4wyQOnMAGU,44
37
+ jarvis_ai_assistant-0.1.5.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
38
+ jarvis_ai_assistant-0.1.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.7.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
jarvis/tools/rag.py DELETED
@@ -1,154 +0,0 @@
1
- from typing import Dict, Any, List
2
- import chromadb
3
- from chromadb.utils import embedding_functions
4
- import hashlib
5
- import re
6
- from ..utils import PrettyOutput, OutputType
7
-
8
- class RAGTool:
9
- name = "rag_query"
10
- description = """Execute RAG queries on documents.
11
- Features:
12
- 1. Auto-creates document embeddings
13
- 2. Returns relevant passages
14
- 3. Maintains embedding database
15
- """
16
- parameters = {
17
- "type": "object",
18
- "properties": {
19
- "files": {
20
- "type": "array",
21
- "items": {"type": "string"},
22
- "description": "Files to process"
23
- },
24
- "query": {
25
- "type": "string",
26
- "description": "Query text"
27
- },
28
- "num_passages": {
29
- "type": "integer",
30
- "description": "Number of passages",
31
- "default": 3
32
- },
33
- "chunk_size": {
34
- "type": "integer",
35
- "description": "Chunk size",
36
- "default": 500
37
- }
38
- },
39
- "required": ["files", "query"]
40
- }
41
-
42
- def _get_document_hash(self, content: str) -> str:
43
- return hashlib.md5(content.encode()).hexdigest()
44
-
45
- def _chunk_text(self, text: str, chunk_size: int = 500) -> List[str]:
46
- """将文本分割成适当大小的块"""
47
- # 按句子分割
48
- sentences = re.split(r'(?<=[.!?])\s+', text)
49
- chunks = []
50
- current_chunk = []
51
- current_length = 0
52
-
53
- for sentence in sentences:
54
- sentence_length = len(sentence)
55
- if current_length + sentence_length > chunk_size and current_chunk:
56
- chunks.append(" ".join(current_chunk))
57
- current_chunk = []
58
- current_length = 0
59
- current_chunk.append(sentence)
60
- current_length += sentence_length
61
-
62
- if current_chunk:
63
- chunks.append(" ".join(current_chunk))
64
-
65
- return chunks
66
-
67
- def execute(self, args: Dict) -> Dict[str, Any]:
68
- """执行RAG查询"""
69
- try:
70
- files = args["files"]
71
- query = args["query"]
72
- num_passages = args.get("num_passages", 3)
73
- chunk_size = args.get("chunk_size", 500)
74
-
75
- # 初始化ChromaDB
76
- chroma_client = chromadb.PersistentClient(path="./data/chromadb")
77
-
78
- # 使用sentence-transformers作为嵌入模型
79
- embedding_function = embedding_functions.SentenceTransformerEmbeddingFunction(
80
- model_name="all-MiniLM-L6-v2"
81
- )
82
-
83
- # 获取或创建集合
84
- collection = chroma_client.get_or_create_collection(
85
- name="document_store",
86
- embedding_function=embedding_function
87
- )
88
-
89
- # 处理每个文件
90
- for file_path in files:
91
- try:
92
- with open(file_path, 'r', encoding='utf-8') as f:
93
- content = f.read()
94
-
95
- # 计算文档哈希值
96
- doc_hash = self._get_document_hash(content)
97
-
98
- # 检查文档是否已经存在且未更改
99
- existing_ids = collection.get(
100
- where={"doc_hash": doc_hash}
101
- )
102
-
103
- if not existing_ids["ids"]:
104
- # 分块处理文档
105
- chunks = self._chunk_text(content, chunk_size)
106
-
107
- # 为每个块生成唯一ID
108
- chunk_ids = [f"{doc_hash}_{i}" for i in range(len(chunks))]
109
-
110
- # 添加到数据库
111
- collection.add(
112
- documents=chunks,
113
- ids=chunk_ids,
114
- metadatas=[{
115
- "file_path": file_path,
116
- "doc_hash": doc_hash,
117
- "chunk_index": i
118
- } for i in range(len(chunks))]
119
- )
120
-
121
- PrettyOutput.print(f"已添加文档: {file_path}", OutputType.INFO)
122
- else:
123
- PrettyOutput.print(f"文档已存在且未更改: {file_path}", OutputType.INFO)
124
-
125
- except Exception as e:
126
- PrettyOutput.print(f"处理文件 {file_path} 时出错: {str(e)}", OutputType.ERROR)
127
-
128
- # 执行查询
129
- results = collection.query(
130
- query_texts=[query],
131
- n_results=num_passages
132
- )
133
-
134
- # 格式化输出
135
- output = [f"查询: {query}\n"]
136
- output.append(f"找到 {len(results['documents'][0])} 个相关段落:\n")
137
-
138
- for i, (doc, metadata) in enumerate(zip(results['documents'][0], results['metadatas'][0]), 1):
139
- output.append(f"\n段落 {i}:")
140
- output.append(f"来源: {metadata['file_path']}")
141
- output.append(f"相关内容:\n{doc}\n")
142
- output.append("-" * 50)
143
-
144
- return {
145
- "success": True,
146
- "stdout": "\n".join(output),
147
- "stderr": ""
148
- }
149
-
150
- except Exception as e:
151
- return {
152
- "success": False,
153
- "error": f"RAG查询失败: {str(e)}"
154
- }
@@ -1,58 +0,0 @@
1
- from typing import Dict, Any
2
- from ..utils import PrettyOutput, OutputType
3
-
4
- class UserConfirmationTool:
5
- name = "ask_user_confirmation"
6
- description = "Request confirmation from user, returns yes/no"
7
- parameters = {
8
- "type": "object",
9
- "properties": {
10
- "question": {
11
- "type": "string",
12
- "description": "Question to ask for confirmation"
13
- },
14
- "details": {
15
- "type": "string",
16
- "description": "Additional details or context",
17
- "default": ""
18
- }
19
- },
20
- "required": ["question"]
21
- }
22
-
23
- def execute(self, args: Dict) -> Dict[str, Any]:
24
- """获取用户确认"""
25
- try:
26
- question = args["question"]
27
- details = args.get("details", "")
28
-
29
- # 打印详细信息
30
- if details:
31
- PrettyOutput.print(details, OutputType.INFO)
32
- PrettyOutput.print("", OutputType.INFO) # 空行
33
-
34
- # 打印问题
35
- PrettyOutput.print(f"{question} (y/n)", OutputType.INFO)
36
-
37
- while True:
38
- response = input(">>> ").strip().lower()
39
- if response in ['y', 'yes']:
40
- result = True
41
- break
42
- elif response in ['n', 'no']:
43
- result = False
44
- break
45
- else:
46
- PrettyOutput.print("请输入 y/yes 或 n/no", OutputType.ERROR)
47
-
48
- return {
49
- "success": True,
50
- "stdout": str(result),
51
- "stderr": ""
52
- }
53
-
54
- except Exception as e:
55
- return {
56
- "success": False,
57
- "error": f"获取用户确认失败: {str(e)}"
58
- }
@@ -1,86 +0,0 @@
1
- from typing import Dict, Any, List
2
- from ..utils import PrettyOutput, OutputType, get_multiline_input
3
-
4
- class UserInteractionTool:
5
- name = "ask_user"
6
- description = "Ask user for information, supports option selection and multiline input"
7
- parameters = {
8
- "type": "object",
9
- "properties": {
10
- "question": {
11
- "type": "string",
12
- "description": "Question to ask the user"
13
- },
14
- "options": {
15
- "type": "array",
16
- "items": {"type": "string"},
17
- "description": "List of options for user to choose from",
18
- "default": []
19
- },
20
- "multiline": {
21
- "type": "boolean",
22
- "description": "Allow multiline input",
23
- "default": False
24
- },
25
- "description": {
26
- "type": "string",
27
- "description": "Additional description or context",
28
- "default": ""
29
- }
30
- },
31
- "required": ["question"]
32
- }
33
-
34
- def execute(self, args: Dict) -> Dict[str, Any]:
35
- """获取用户输入"""
36
- try:
37
- question = args["question"]
38
- options = args.get("options", [])
39
- multiline = args.get("multiline", False)
40
- description = args.get("description", "")
41
-
42
- # 打印问题描述
43
- if description:
44
- PrettyOutput.print(description, OutputType.INFO)
45
-
46
- # 如果有选项,显示选项列表
47
- if options:
48
- PrettyOutput.print("\n可选项:", OutputType.INFO)
49
- for i, option in enumerate(options, 1):
50
- PrettyOutput.print(f"[{i}] {option}", OutputType.INFO)
51
-
52
- while True:
53
- try:
54
- choice = input("\n请选择 (输入数字): ").strip()
55
- if not choice:
56
- continue
57
-
58
- choice = int(choice)
59
- if 1 <= choice <= len(options):
60
- response = options[choice - 1]
61
- break
62
- else:
63
- PrettyOutput.print("无效选择,请重试", OutputType.ERROR)
64
- except ValueError:
65
- PrettyOutput.print("请输入有效数字", OutputType.ERROR)
66
-
67
- # 多行输入
68
- elif multiline:
69
- response = get_multiline_input(question)
70
-
71
- # 单行输入
72
- else:
73
- PrettyOutput.print(question, OutputType.INFO)
74
- response = input(">>> ").strip()
75
-
76
- return {
77
- "success": True,
78
- "stdout": response,
79
- "stderr": ""
80
- }
81
-
82
- except Exception as e:
83
- return {
84
- "success": False,
85
- "error": f"获取用户输入失败: {str(e)}"
86
- }
@@ -1,36 +0,0 @@
1
- jarvis/.jarvis,sha256=S4ZMmLqlVLHAPmnwHFQ3vYt0gnDFp-KQRH4okBh8Hpw,209
2
- jarvis/__init__.py,sha256=V3Qwm3k_WFeGUNccLbLJuCyWQyXYnRUkY5-KlBUm4UU,49
3
- jarvis/agent.py,sha256=hEatrIothG6C_RuOsygZz4ez1aF1EycnUPwY2Krwiwk,4092
4
- jarvis/main.py,sha256=wAeeGoRq8fFiTWUCQ31MYVeU9o6SZ48ORUow0jlMJJE,5259
5
- jarvis/models.py,sha256=ZQAyc39e_UsNmHkME6ATp6053safQ7Gog-oWwETsrMM,4415
6
- jarvis/utils.py,sha256=-fOPAgiKVPC6DevHM7A7IJvvIzvvFlGM0pHBKyBXDcA,3044
7
- jarvis/__pycache__/__init__.cpython-313.pyc,sha256=u64PLu4KyOPrirhIqNXZSkj9B6yB1L_ohFYhPX8p334,208
8
- jarvis/__pycache__/agent.cpython-313.pyc,sha256=I1JYUKC-zedURwuxQQjd9saj_yQKUhpdbb1KNWlY6Ss,4940
9
- jarvis/__pycache__/models.cpython-313.pyc,sha256=fot2VOV0lgODg4b_WuD-kkq-g7uZGLuZlYXiljlW13U,6350
10
- jarvis/__pycache__/tools.cpython-313.pyc,sha256=lAD4LrnnWzNZQmHXGfZ_2l7oskOpr2_2OC-gdFhxQY8,33933
11
- jarvis/__pycache__/utils.cpython-313.pyc,sha256=o8Fubq8Dcrvv3ATzQ9BnZoZjQmU3_FNPrfTt0ANdKdI,5804
12
- jarvis/tools/__init__.py,sha256=FNF5X32UzKvlT08-hPz7-7vcIyqqMngQYj36LXyNbV0,553
13
- jarvis/tools/base.py,sha256=xdZaoqxCOYVAwBmof_zqICg5ixb5-ksX-XbNXJw1O7k,5938
14
- jarvis/tools/file_ops.py,sha256=05Vc4u-NGMjLD15WI52eL_nt_RyYt-Z_cXJnnBepf-c,3781
15
- jarvis/tools/python_script.py,sha256=_eK8LqNs-Mz50zdcgwbjdd8-qAeOl6kJ_qRDvWawGMw,5006
16
- jarvis/tools/rag.py,sha256=eBrn1fdqy-nd2nR0b4oH1EQpthTYVen-sYDhC5Ypl38,5647
17
- jarvis/tools/search.py,sha256=dyJmeP_s2tWv5KQejOl-TuVF12B6SXViiXEyTemD1Wo,1412
18
- jarvis/tools/shell.py,sha256=uGqwUGmqFg1cJkyTg7zyPk3jRwEr-woKTmqcTKdbbg8,1979
19
- jarvis/tools/user_confirmation.py,sha256=p0JverifHJfnALeIhtKtaVBBVEGkgSpUzT-PSycG4NY,1850
20
- jarvis/tools/user_interaction.py,sha256=xOaoYsCKTa9-K3mg5tsu1zegn1HKcO40k2aJ3VygZqM,3073
21
- jarvis/tools/webpage.py,sha256=UTEomu5j7jbOw8c5az2jsjv5E7LeokWKj1QahvZO7xc,3077
22
- jarvis/tools/__pycache__/__init__.cpython-313.pyc,sha256=wktmOMuGMwQjQ--eRzooUNsL5YjY0bS_CbcSFUWze54,674
23
- jarvis/tools/__pycache__/base.cpython-313.pyc,sha256=hqhRtxwQwWLnBEzNqZ1FqcWYuyX87iu89SgHxu10Gho,8192
24
- jarvis/tools/__pycache__/file_ops.cpython-313.pyc,sha256=bawv11xhWSj5wCtW0QeJLI-InhUBUXaSkogq6rZzvTQ,3636
25
- jarvis/tools/__pycache__/python_script.cpython-313.pyc,sha256=8JpryqTovEiTvBlWAK1KjZmPvHUuPc9GT9rTXBEQoJc,6693
26
- jarvis/tools/__pycache__/rag.cpython-313.pyc,sha256=JH6-PSZRMKAvTZqCwlRXJGClxYXNMs-vetU0q7hBLz0,6064
27
- jarvis/tools/__pycache__/search.cpython-313.pyc,sha256=VX9zztOwIsPCkYwev0A0XJGyu4Tr0PQcQkbbqx8vfB0,1870
28
- jarvis/tools/__pycache__/shell.cpython-313.pyc,sha256=Xtqt-LzMRfsCXeCE7QxFY8TR8XEeQG_jic73YLkhXQw,2302
29
- jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc,sha256=wK3Ev10lHSUSRvoYmi7A0GzxYkzU-C4Wfhs5qW_HBqs,2271
30
- jarvis/tools/__pycache__/user_interaction.cpython-313.pyc,sha256=RuVZ-pmiPBDywY3efgXSfohMAciC1avMGPmBK5qlnew,3305
31
- jarvis/tools/__pycache__/webpage.cpython-313.pyc,sha256=VcpkaV8IyOOtebedXjn8ybjr8AglU-3-Cs80yzE4FYo,3628
32
- jarvis_ai_assistant-0.1.2.dist-info/METADATA,sha256=0EX8k3LdrzeEWHqRTHlguT80fPxHLbVtpY65f1kMhOk,3675
33
- jarvis_ai_assistant-0.1.2.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
34
- jarvis_ai_assistant-0.1.2.dist-info/entry_points.txt,sha256=iKu7OMfew9dtfGhW71gIMTg4wvafuPqKb4wyQOnMAGU,44
35
- jarvis_ai_assistant-0.1.2.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
36
- jarvis_ai_assistant-0.1.2.dist-info/RECORD,,