jarvis-ai-assistant 0.2.1__py3-none-any.whl → 0.2.3__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 (41) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/jarvis.py +61 -59
  3. jarvis/jarvis_agent/main.py +42 -40
  4. jarvis/jarvis_agent/prompts.py +26 -4
  5. jarvis/jarvis_code_agent/code_agent.py +35 -31
  6. jarvis/jarvis_code_analysis/code_review.py +73 -39
  7. jarvis/jarvis_data/config_schema.json +67 -12
  8. jarvis/jarvis_git_squash/main.py +16 -12
  9. jarvis/jarvis_git_utils/git_commiter.py +25 -20
  10. jarvis/jarvis_methodology/main.py +34 -49
  11. jarvis/jarvis_multi_agent/main.py +28 -23
  12. jarvis/jarvis_platform/ai8.py +31 -22
  13. jarvis/jarvis_platform/kimi.py +31 -61
  14. jarvis/jarvis_platform/tongyi.py +71 -85
  15. jarvis/jarvis_platform/yuanbao.py +44 -50
  16. jarvis/jarvis_platform_manager/main.py +55 -90
  17. jarvis/jarvis_rag/cli.py +79 -23
  18. jarvis/jarvis_rag/query_rewriter.py +61 -12
  19. jarvis/jarvis_rag/rag_pipeline.py +143 -34
  20. jarvis/jarvis_rag/retriever.py +5 -5
  21. jarvis/jarvis_smart_shell/main.py +58 -87
  22. jarvis/jarvis_tools/cli/main.py +120 -153
  23. jarvis/jarvis_tools/generate_new_tool.py +22 -1
  24. jarvis/jarvis_tools/registry.py +1 -7
  25. jarvis/jarvis_tools/search_web.py +12 -10
  26. jarvis/jarvis_utils/config.py +92 -11
  27. jarvis/jarvis_utils/globals.py +29 -8
  28. jarvis/jarvis_utils/http.py +58 -79
  29. jarvis/jarvis_utils/input.py +114 -121
  30. jarvis/jarvis_utils/output.py +1 -1
  31. jarvis/jarvis_utils/utils.py +3 -0
  32. jarvis_ai_assistant-0.2.3.dist-info/METADATA +301 -0
  33. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/RECORD +37 -40
  34. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/entry_points.txt +0 -2
  35. jarvis/jarvis_git_details/__init__.py +0 -0
  36. jarvis/jarvis_git_details/main.py +0 -265
  37. jarvis/jarvis_platform/oyi.py +0 -357
  38. jarvis_ai_assistant-0.2.1.dist-info/METADATA +0 -845
  39. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/WHEEL +0 -0
  40. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/licenses/LICENSE +0 -0
  41. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/top_level.txt +0 -0
@@ -115,22 +115,26 @@ def get_shell_name() -> str:
115
115
  return os.path.basename(shell_path).lower()
116
116
 
117
117
 
118
- def _get_resolved_model_config(model_group_override: Optional[str] = None) -> Dict[str, Any]:
118
+ def _get_resolved_model_config(
119
+ model_group_override: Optional[str] = None,
120
+ ) -> Dict[str, Any]:
119
121
  """
120
122
  解析并合并模型配置,处理模型组。
121
123
 
122
124
  优先级顺序:
123
125
  1. 单独的环境变量 (JARVIS_PLATFORM, JARVIS_MODEL, etc.)
124
- 2. JARVIS_MODEL_GROUP 中定义的组配置
126
+ 2. JARVIS_LLM_GROUP 中定义的组配置
125
127
  3. 代码中的默认值
126
128
 
127
129
  返回:
128
130
  Dict[str, Any]: 解析后的模型配置字典
129
131
  """
130
132
  group_config = {}
131
- model_group_name = model_group_override or GLOBAL_CONFIG_DATA.get("JARVIS_MODEL_GROUP")
133
+ model_group_name = model_group_override or GLOBAL_CONFIG_DATA.get(
134
+ "JARVIS_LLM_GROUP"
135
+ )
132
136
  # The format is a list of single-key dicts: [{'group_name': {...}}, ...]
133
- model_groups = GLOBAL_CONFIG_DATA.get("JARVIS_MODEL_GROUPS", [])
137
+ model_groups = GLOBAL_CONFIG_DATA.get("JARVIS_LLM_GROUPS", [])
134
138
 
135
139
  if model_group_name and isinstance(model_groups, list):
136
140
  for group_item in model_groups:
@@ -202,7 +206,9 @@ def get_thinking_model_name(model_group_override: Optional[str] = None) -> str:
202
206
  """
203
207
  config = _get_resolved_model_config(model_group_override)
204
208
  # Fallback to normal model if thinking model is not specified
205
- return config.get("JARVIS_THINKING_MODEL", get_normal_model_name(model_group_override))
209
+ return config.get(
210
+ "JARVIS_THINKING_MODEL", get_normal_model_name(model_group_override)
211
+ )
206
212
 
207
213
 
208
214
  def is_execute_tool_confirm() -> bool:
@@ -334,14 +340,65 @@ def get_mcp_config() -> List[Dict[str, Any]]:
334
340
  # ==============================================================================
335
341
 
336
342
 
337
- def get_rag_config() -> Dict[str, Any]:
343
+ DEFAULT_RAG_GROUPS = [
344
+ {
345
+ "text": {
346
+ "embedding_model": "BAAI/bge-m3",
347
+ "rerank_model": "BAAI/bge-reranker-v2-m3",
348
+ "use_bm25": True,
349
+ "use_rerank": True,
350
+ }
351
+ },
352
+ {
353
+ "code": {
354
+ "embedding_model": "Qodo/Qodo-Embed-1-7B",
355
+ "use_bm25": False,
356
+ "use_rerank": False,
357
+ }
358
+ },
359
+ ]
360
+
361
+
362
+ def _get_resolved_rag_config(
363
+ rag_group_override: Optional[str] = None,
364
+ ) -> Dict[str, Any]:
338
365
  """
339
- 获取RAG框架的配置。
366
+ 解析并合并RAG配置,处理RAG组。
367
+
368
+ 优先级顺序:
369
+ 1. JARVIS_RAG 中的顶级设置 (embedding_model, etc.)
370
+ 2. JARVIS_RAG_GROUP 中定义的组配置
371
+ 3. 代码中的默认值
340
372
 
341
373
  返回:
342
- Dict[str, Any]: RAG配置字典
374
+ Dict[str, Any]: 解析后的RAG配置字典
343
375
  """
344
- return GLOBAL_CONFIG_DATA.get("JARVIS_RAG", {})
376
+ group_config = {}
377
+ rag_group_name = rag_group_override or GLOBAL_CONFIG_DATA.get("JARVIS_RAG_GROUP")
378
+ rag_groups = GLOBAL_CONFIG_DATA.get("JARVIS_RAG_GROUPS", DEFAULT_RAG_GROUPS)
379
+
380
+ if rag_group_name and isinstance(rag_groups, list):
381
+ for group_item in rag_groups:
382
+ if isinstance(group_item, dict) and rag_group_name in group_item:
383
+ group_config = group_item[rag_group_name]
384
+ break
385
+
386
+ # Start with group config
387
+ resolved_config = group_config.copy()
388
+
389
+ # Override with specific settings from the top-level JARVIS_RAG dict
390
+ top_level_rag_config = GLOBAL_CONFIG_DATA.get("JARVIS_RAG", {})
391
+ if isinstance(top_level_rag_config, dict):
392
+ for key in [
393
+ "embedding_model",
394
+ "rerank_model",
395
+ "use_bm25",
396
+ "use_rerank",
397
+ ]:
398
+ if key in top_level_rag_config:
399
+ resolved_config[key] = top_level_rag_config[key]
400
+
401
+ return resolved_config
345
402
 
346
403
 
347
404
  def get_rag_embedding_model() -> str:
@@ -351,7 +408,8 @@ def get_rag_embedding_model() -> str:
351
408
  返回:
352
409
  str: 嵌入模型的名称
353
410
  """
354
- return get_rag_config().get("embedding_model", "BAAI/bge-base-zh-v1.5")
411
+ config = _get_resolved_rag_config()
412
+ return config.get("embedding_model", "BAAI/bge-m3")
355
413
 
356
414
 
357
415
  def get_rag_rerank_model() -> str:
@@ -361,7 +419,8 @@ def get_rag_rerank_model() -> str:
361
419
  返回:
362
420
  str: rerank模型的名称
363
421
  """
364
- return get_rag_config().get("rerank_model", "BAAI/bge-reranker-base")
422
+ config = _get_resolved_rag_config()
423
+ return config.get("rerank_model", "BAAI/bge-reranker-v2-m3")
365
424
 
366
425
 
367
426
  def get_rag_embedding_cache_path() -> str:
@@ -382,3 +441,25 @@ def get_rag_vector_db_path() -> str:
382
441
  str: 数据库路径
383
442
  """
384
443
  return ".jarvis/rag/vectordb"
444
+
445
+
446
+ def get_rag_use_bm25() -> bool:
447
+ """
448
+ 获取RAG是否使用BM25。
449
+
450
+ 返回:
451
+ bool: 如果使用BM25则返回True,默认为True
452
+ """
453
+ config = _get_resolved_rag_config()
454
+ return config.get("use_bm25", True) is True
455
+
456
+
457
+ def get_rag_use_rerank() -> bool:
458
+ """
459
+ 获取RAG是否使用rerank。
460
+
461
+ 返回:
462
+ bool: 如果使用rerank则返回True,默认为True
463
+ """
464
+ config = _get_resolved_rag_config()
465
+ return config.get("use_rerank", True) is True
@@ -9,9 +9,11 @@
9
9
  """
10
10
  import os
11
11
 
12
- # 全局变量:保存最后一条消息
13
- last_message: str = ""
14
- from typing import Any, Dict, Set
12
+ # 全局变量:保存消息历史
13
+ from typing import Any, Dict, Set, List
14
+
15
+ message_history: List[str] = []
16
+ MAX_HISTORY_SIZE = 50
15
17
 
16
18
  import colorama
17
19
  from rich.console import Console
@@ -169,13 +171,18 @@ def get_interrupt() -> int:
169
171
 
170
172
  def set_last_message(message: str) -> None:
171
173
  """
172
- 设置最后一条消息。
174
+ 将消息添加到历史记录中。
173
175
 
174
176
  参数:
175
177
  message: 要保存的消息
176
178
  """
177
- global last_message
178
- last_message = message
179
+ global message_history
180
+ if message:
181
+ # 避免重复添加
182
+ if not message_history or message_history[-1] != message:
183
+ message_history.append(message)
184
+ if len(message_history) > MAX_HISTORY_SIZE:
185
+ message_history.pop(0)
179
186
 
180
187
 
181
188
  def get_last_message() -> str:
@@ -183,6 +190,20 @@ def get_last_message() -> str:
183
190
  获取最后一条消息。
184
191
 
185
192
  返回:
186
- str: 最后一条消息
193
+ str: 最后一条消息,如果历史记录为空则返回空字符串
194
+ """
195
+ global message_history
196
+ if message_history:
197
+ return message_history[-1]
198
+ return ""
199
+
200
+
201
+ def get_message_history() -> List[str]:
202
+ """
203
+ 获取完整的消息历史记录。
204
+
205
+ 返回:
206
+ List[str]: 消息历史列表
187
207
  """
188
- return last_message
208
+ global message_history
209
+ return message_history
@@ -1,140 +1,120 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- import httpx
4
- from typing import Any, Dict, Optional, Union, AsyncGenerator, Generator
3
+ import requests
4
+ from typing import Any, Dict, Optional, Generator
5
5
 
6
6
 
7
- def get_httpx_client() -> httpx.Client:
7
+ def get_requests_session() -> requests.Session:
8
8
  """
9
- 获取一个配置好的 httpx.Client 对象
9
+ 获取一个配置好的 requests.Session 对象
10
10
 
11
11
  返回:
12
- httpx.Client 对象
12
+ requests.Session 对象
13
13
  """
14
- client = httpx.Client(
15
- timeout=httpx.Timeout(None), # 永不超时
16
- headers={
14
+ session = requests.Session()
15
+ session.headers.update(
16
+ {
17
17
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
18
- },
18
+ }
19
19
  )
20
- return client
20
+ return session
21
21
 
22
22
 
23
- def get_async_httpx_client() -> httpx.AsyncClient:
24
- """
25
- 获取一个配置好的 httpx.AsyncClient 对象
26
-
27
- 返回:
28
- httpx.AsyncClient 对象
29
- """
30
- client = httpx.AsyncClient(
31
- timeout=httpx.Timeout(None), # 永不超时
32
- headers={
33
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
34
- },
35
- )
36
- return client
37
-
38
-
39
- # 增强版本的 HTTP 请求方法(使用 httpx 实现,带重试机制,解决连接中断问题)
23
+ # 增强版本的 HTTP 请求方法(使用 requests 实现)
40
24
  def post(
41
25
  url: str,
42
26
  data: Optional[Any] = None,
43
27
  json: Optional[Dict[str, Any]] = None,
44
28
  **kwargs,
45
- ) -> httpx.Response:
29
+ ) -> requests.Response:
46
30
  """
47
- 发送增强版永不超时的 POST 请求,使用 httpx 实现,包含重试机制
31
+ 发送增强版永不超时的 POST 请求,使用 requests 实现
48
32
 
49
33
  参数:
50
34
  url: 请求的 URL
51
35
  data: (可选) 请求体数据 (表单数据或原始数据)
52
36
  json: (可选) JSON 数据,会自动设置 Content-Type
53
- **kwargs: 其他传递给 httpx.post 的参数
37
+ **kwargs: 其他传递给 requests.post 的参数
54
38
 
55
39
  返回:
56
- httpx.Response 对象
40
+ requests.Response 对象
57
41
 
58
42
  注意:
59
- 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
43
+ 此方法使用 requests 实现。要实现重试,请考虑使用 Session 和 HTTPAdapter。
44
+ 永不超时通过 timeout=None 设置。
60
45
  """
61
- client = get_httpx_client()
62
- try:
63
- response = client.post(url=url, data=data, json=json, **kwargs)
46
+ kwargs.setdefault("timeout", None)
47
+ with get_requests_session() as session:
48
+ response = session.post(url=url, data=data, json=json, **kwargs)
64
49
  response.raise_for_status()
65
50
  return response
66
- finally:
67
- client.close()
68
51
 
69
52
 
70
- def get(url: str, **kwargs) -> httpx.Response:
53
+ def get(url: str, **kwargs) -> requests.Response:
71
54
  """
72
- 发送增强版永不超时的 GET 请求,使用 httpx 实现,包含重试机制
55
+ 发送增强版永不超时的 GET 请求,使用 requests 实现
73
56
 
74
57
  参数:
75
58
  url: 请求的 URL
76
- **kwargs: 其他传递给 httpx.get 的参数
59
+ **kwargs: 其他传递给 requests.get 的参数
77
60
 
78
61
  返回:
79
- httpx.Response 对象
62
+ requests.Response 对象
80
63
 
81
64
  注意:
82
- 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
65
+ 此方法使用 requests 实现。
66
+ 永不超时通过 timeout=None 设置。
83
67
  """
84
- client = get_httpx_client()
85
- try:
86
- response = client.get(url=url, **kwargs)
68
+ kwargs.setdefault("timeout", None)
69
+ with get_requests_session() as session:
70
+ response = session.get(url=url, **kwargs)
87
71
  response.raise_for_status()
88
72
  return response
89
- finally:
90
- client.close()
91
73
 
92
74
 
93
- def put(url: str, data: Optional[Any] = None, **kwargs) -> httpx.Response:
75
+ def put(url: str, data: Optional[Any] = None, **kwargs) -> requests.Response:
94
76
  """
95
- 发送增强版永不超时的 PUT 请求,使用 httpx 实现,包含重试机制
77
+ 发送增强版永不超时的 PUT 请求,使用 requests 实现
96
78
 
97
79
  参数:
98
80
  url: 请求的 URL
99
81
  data: (可选) 请求体数据 (表单数据或原始数据)
100
- **kwargs: 其他传递给 httpx.put 的参数
82
+ **kwargs: 其他传递给 requests.put 的参数
101
83
 
102
84
  返回:
103
- httpx.Response 对象
85
+ requests.Response 对象
104
86
 
105
87
  注意:
106
- 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
88
+ 此方法使用 requests 实现。
89
+ 永不超时通过 timeout=None 设置。
107
90
  """
108
- client = get_httpx_client()
109
- try:
110
- response = client.put(url=url, data=data, **kwargs)
91
+ kwargs.setdefault("timeout", None)
92
+ with get_requests_session() as session:
93
+ response = session.put(url=url, data=data, **kwargs)
111
94
  response.raise_for_status()
112
95
  return response
113
- finally:
114
- client.close()
115
96
 
116
97
 
117
- def delete(url: str, **kwargs) -> httpx.Response:
98
+ def delete(url: str, **kwargs) -> requests.Response:
118
99
  """
119
- 发送增强版永不超时的 DELETE 请求,使用 httpx 实现,包含重试机制
100
+ 发送增强版永不超时的 DELETE 请求,使用 requests 实现
120
101
 
121
102
  参数:
122
103
  url: 请求的 URL
123
- **kwargs: 其他传递给 httpx.delete 的参数
104
+ **kwargs: 其他传递给 requests.delete 的参数
124
105
 
125
106
  返回:
126
- httpx.Response 对象
107
+ requests.Response 对象
127
108
 
128
109
  注意:
129
- 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
110
+ 此方法使用 requests 实现。
111
+ 永不超时通过 timeout=None 设置。
130
112
  """
131
- client = get_httpx_client()
132
- try:
133
- response = client.delete(url=url, **kwargs)
113
+ kwargs.setdefault("timeout", None)
114
+ with get_requests_session() as session:
115
+ response = session.delete(url=url, **kwargs)
134
116
  response.raise_for_status()
135
117
  return response
136
- finally:
137
- client.close()
138
118
 
139
119
 
140
120
  # 同步流式POST请求方法
@@ -143,27 +123,26 @@ def stream_post(
143
123
  data: Optional[Any] = None,
144
124
  json: Optional[Dict[str, Any]] = None,
145
125
  **kwargs,
146
- ) -> Generator[bytes, None, None]:
126
+ ) -> Generator[str, None, None]:
147
127
  """
148
- 发送流式 POST 请求,使用 httpx 实现,返回标准 Generator
128
+ 发送流式 POST 请求,使用 requests 实现,返回解码后的字符串行生成器
149
129
 
150
130
  参数:
151
131
  url: 请求的 URL
152
132
  data: (可选) 请求体数据 (表单数据或原始数据)
153
133
  json: (可选) JSON 数据,会自动设置 Content-Type
154
- **kwargs: 其他传递给 httpx.post 的参数
134
+ **kwargs: 其他传递给 requests.post 的参数
155
135
 
156
136
  返回:
157
- Generator[bytes, None, None]: 字节流生成器
137
+ Generator[str, None, None]: 字符串行生成器
158
138
 
159
139
  注意:
160
- 此方法使用 httpx 实现流式请求,适用于处理大文件下载或流式响应
140
+ 此方法使用 requests 实现流式请求,适用于处理大文件下载或流式响应
161
141
  """
162
- client = get_httpx_client()
163
- try:
164
- with client.stream("POST", url, data=data, json=json, **kwargs) as response:
142
+ kwargs.setdefault("timeout", None)
143
+ with get_requests_session() as session:
144
+ with session.post(url, data=data, json=json, stream=True, **kwargs) as response:
165
145
  response.raise_for_status()
166
- for chunk in response.iter_bytes():
167
- yield chunk
168
- finally:
169
- client.close()
146
+ for line in response.iter_lines(chunk_size=1):
147
+ if line:
148
+ yield line.decode("utf-8", errors="ignore")