jarvis-ai-assistant 0.1.182__tar.gz → 0.1.184__tar.gz

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 (106) hide show
  1. {jarvis_ai_assistant-0.1.182/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.184}/PKG-INFO +30 -1
  2. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/README.md +29 -0
  3. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/pyproject.toml +1 -1
  4. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/setup.py +1 -1
  5. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/__init__.py +1 -1
  6. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform/kimi.py +1 -1
  7. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform/registry.py +0 -1
  8. jarvis_ai_assistant-0.1.184/src/jarvis/jarvis_platform/tongyi.py +473 -0
  9. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform/yuanbao.py +8 -0
  10. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/generate_new_tool.py +2 -94
  11. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184/src/jarvis_ai_assistant.egg-info}/PKG-INFO +30 -1
  12. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +1 -0
  13. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/LICENSE +0 -0
  14. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/MANIFEST.in +0 -0
  15. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/setup.cfg +0 -0
  16. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_agent/__init__.py +0 -0
  17. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_agent/builtin_input_handler.py +0 -0
  18. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_agent/file_input_handler.py +0 -0
  19. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_agent/jarvis.py +0 -0
  20. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_agent/main.py +0 -0
  21. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_agent/output_handler.py +0 -0
  22. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_agent/shell_input_handler.py +0 -0
  23. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
  24. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_agent/code_agent.py +0 -0
  25. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_agent/lint.py +0 -0
  26. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/__init__.py +0 -0
  27. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/c_cpp.py +0 -0
  28. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/csharp.py +0 -0
  29. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/data_format.py +0 -0
  30. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/devops.py +0 -0
  31. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/docs.py +0 -0
  32. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/go.py +0 -0
  33. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/infrastructure.py +0 -0
  34. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/java.py +0 -0
  35. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/javascript.py +0 -0
  36. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/kotlin.py +0 -0
  37. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/loader.py +0 -0
  38. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/php.py +0 -0
  39. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/python.py +0 -0
  40. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/ruby.py +0 -0
  41. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/rust.py +0 -0
  42. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/shell.py +0 -0
  43. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/sql.py +0 -0
  44. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/swift.py +0 -0
  45. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/checklists/web.py +0 -0
  46. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_code_analysis/code_review.py +0 -0
  47. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_data/config_schema.json +0 -0
  48. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_data/huggingface.tar.gz +0 -0
  49. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_dev/main.py +0 -0
  50. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_event/__init__.py +0 -0
  51. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_git_details/__init__.py +0 -0
  52. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_git_details/main.py +0 -0
  53. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_git_squash/__init__.py +0 -0
  54. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_git_squash/main.py +0 -0
  55. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_git_utils/git_commiter.py +0 -0
  56. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_mcp/__init__.py +0 -0
  57. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_mcp/sse_mcp_client.py +0 -0
  58. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_mcp/stdio_mcp_client.py +0 -0
  59. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_mcp/streamable_mcp_client.py +0 -0
  60. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_methodology/main.py +0 -0
  61. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_multi_agent/__init__.py +0 -0
  62. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_multi_agent/main.py +0 -0
  63. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform/__init__.py +0 -0
  64. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform/base.py +0 -0
  65. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform/human.py +0 -0
  66. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform/openai.py +0 -0
  67. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
  68. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_platform_manager/main.py +0 -0
  69. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
  70. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_smart_shell/main.py +0 -0
  71. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/__init__.py +0 -0
  72. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/ask_user.py +0 -0
  73. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/base.py +0 -0
  74. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/chdir.py +0 -0
  75. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/cli/__init__.py +0 -0
  76. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/cli/main.py +0 -0
  77. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/code_plan.py +0 -0
  78. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/create_code_agent.py +0 -0
  79. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/create_sub_agent.py +0 -0
  80. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/edit_file.py +0 -0
  81. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/execute_script.py +0 -0
  82. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/file_analyzer.py +0 -0
  83. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/file_operation.py +0 -0
  84. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/methodology.py +0 -0
  85. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/read_code.py +0 -0
  86. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
  87. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/registry.py +0 -0
  88. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/rewrite_file.py +0 -0
  89. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/search_web.py +0 -0
  90. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_tools/virtual_tty.py +0 -0
  91. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/__init__.py +0 -0
  92. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/builtin_replace_map.py +0 -0
  93. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/config.py +0 -0
  94. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/embedding.py +0 -0
  95. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/file_processors.py +0 -0
  96. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/git_utils.py +0 -0
  97. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/globals.py +0 -0
  98. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/input.py +0 -0
  99. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/methodology.py +0 -0
  100. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/output.py +0 -0
  101. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/tag.py +0 -0
  102. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis/jarvis_utils/utils.py +0 -0
  103. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
  104. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
  105. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
  106. {jarvis_ai_assistant-0.1.182 → jarvis_ai_assistant-0.1.184}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.182
3
+ Version: 0.1.184
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
@@ -153,6 +153,35 @@ Kimi API Key获取方式:
153
153
  删除Bearer前缀,剩下的内容就是Kimi API Key。
154
154
 
155
155
 
156
+ #### 通义千问
157
+ ```yaml
158
+ JARVIS_PLATFORM: tongyi
159
+ JARVIS_MODEL: Normal # 可选模型:Normal, Thinking, Deep-Research, Code-Chat
160
+ JARVIS_THINKING_PLATFORM: tongyi
161
+ JARVIS_THINKING_MODEL: Thinking
162
+
163
+ ENV:
164
+ TONGYI_COOKIES: <通义千问cookies>
165
+ ```
166
+
167
+ 通义千问cookies获取方式:
168
+
169
+ ![通义千问cookies获取方式](docs/images/tongyi.png)
170
+
171
+ 1. 登录[通义千问](https://www.tongyi.com/qianwen)
172
+ 2. 打开浏览器开发者工具(F12)
173
+ 3. 在Network标签页中找到任意请求
174
+ 4. 在请求头中找到Cookie字段,复制其值
175
+
176
+ 配置说明:
177
+ 1. `TONGYI_COOKIES`: 必填,用于身份验证
178
+ 2. 支持的模型:
179
+ - `Normal`: 标准对话模型
180
+ - `Thinking`: 深度思考模型
181
+ - `Deep-Research`: 深度研究模型
182
+ - `Code-Chat`: 代码对话模型
183
+
184
+
156
185
  #### OpenAI
157
186
  ```yaml
158
187
  JARVIS_PLATFORM: openai
@@ -83,6 +83,35 @@ Kimi API Key获取方式:
83
83
  删除Bearer前缀,剩下的内容就是Kimi API Key。
84
84
 
85
85
 
86
+ #### 通义千问
87
+ ```yaml
88
+ JARVIS_PLATFORM: tongyi
89
+ JARVIS_MODEL: Normal # 可选模型:Normal, Thinking, Deep-Research, Code-Chat
90
+ JARVIS_THINKING_PLATFORM: tongyi
91
+ JARVIS_THINKING_MODEL: Thinking
92
+
93
+ ENV:
94
+ TONGYI_COOKIES: <通义千问cookies>
95
+ ```
96
+
97
+ 通义千问cookies获取方式:
98
+
99
+ ![通义千问cookies获取方式](docs/images/tongyi.png)
100
+
101
+ 1. 登录[通义千问](https://www.tongyi.com/qianwen)
102
+ 2. 打开浏览器开发者工具(F12)
103
+ 3. 在Network标签页中找到任意请求
104
+ 4. 在请求头中找到Cookie字段,复制其值
105
+
106
+ 配置说明:
107
+ 1. `TONGYI_COOKIES`: 必填,用于身份验证
108
+ 2. 支持的模型:
109
+ - `Normal`: 标准对话模型
110
+ - `Thinking`: 深度思考模型
111
+ - `Deep-Research`: 深度研究模型
112
+ - `Code-Chat`: 代码对话模型
113
+
114
+
86
115
  #### OpenAI
87
116
  ```yaml
88
117
  JARVIS_PLATFORM: openai
@@ -8,7 +8,7 @@ default = true
8
8
 
9
9
  [project]
10
10
  name = "jarvis-ai-assistant"
11
- version = "0.1.182"
11
+ version = "0.1.184"
12
12
  description = "Jarvis: An AI assistant that uses tools to interact with the system"
13
13
  readme = "README.md"
14
14
  authors = [{ name = "skyfire", email = "skyfireitdiy@hotmail.com" }]
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name="jarvis-ai-assistant",
6
- version="0.1.182",
6
+ version="0.1.184",
7
7
  author="skyfire",
8
8
  author_email="skyfireitdiy@hotmail.com",
9
9
  description="An AI assistant that uses various tools to interact with the system",
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI Assistant"""
3
3
 
4
- __version__ = "0.1.182"
4
+ __version__ = "0.1.184"
@@ -315,7 +315,7 @@ class KimiModel(BasePlatform):
315
315
 
316
316
  def name(self) -> str:
317
317
  """Model name"""
318
- return "kimi"
318
+ return self.model_name
319
319
 
320
320
  def support_web(self) -> bool:
321
321
  """Kimi平台支持web功能"""
@@ -19,7 +19,6 @@ REQUIRED_METHODS = [
19
19
  ('set_system_message', ['message']),
20
20
  ('set_model_name', ['model_name']),
21
21
  ('get_model_list', []),
22
- ('set_suppress_output', ['suppress']),
23
22
  ('upload_files', ['file_list']),
24
23
  ]
25
24
 
@@ -0,0 +1,473 @@
1
+ # -*- coding: utf-8 -*-
2
+ import json
3
+ import os
4
+ from typing import Any, Dict, Generator, List, Tuple
5
+ import uuid
6
+ import time
7
+
8
+ import requests
9
+ from yaspin import yaspin
10
+ from yaspin.spinners import Spinners
11
+
12
+ from jarvis.jarvis_platform.base import BasePlatform
13
+ from jarvis.jarvis_utils.output import PrettyOutput, OutputType
14
+ from jarvis.jarvis_utils.utils import while_success
15
+
16
+
17
+ class TongyiPlatform(BasePlatform):
18
+ """Tongyi platform implementation"""
19
+
20
+ platform_name = "tongyi"
21
+
22
+ def __init__(self):
23
+ """Initialize Tongyi platform"""
24
+ super().__init__()
25
+ self.session_id = ""
26
+ self.cookies = os.getenv("TONGYI_COOKIES", "")
27
+ self.request_id = ""
28
+ self.msg_id = ""
29
+ self.model_name = ""
30
+ self.uploaded_file_info = []
31
+ self.system_message = "" # System message for initialization
32
+ self.first_chat = True # Flag for first chat
33
+
34
+
35
+ def _get_base_headers(self):
36
+ return {
37
+ "Host": "api.tongyi.com",
38
+ "Connection": "keep-alive",
39
+ "X-Platform": "pc_tongyi",
40
+ "sec-ch-ua-platform": "Windows",
41
+ "sec-ch-ua": '"Chromium";v="136", "Microsoft Edge";v="136", "Not.A/Brand";v="99"',
42
+ "sec-ch-ua-mobile": "?0",
43
+ "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 Edg/136.0.0.0",
44
+ "accept": "application/json, text/plain, */*",
45
+ "DNT": "1",
46
+ "Content-Type": "application/json",
47
+ "Origin": "https://www.tongyi.com",
48
+ "Sec-Fetch-Site": "same-site",
49
+ "Sec-Fetch-Mode": "cors",
50
+ "Sec-Fetch-Dest": "empty",
51
+ "Referer": "https://www.tongyi.com/qianwen",
52
+ "Accept-Encoding": "gzip, deflate, br, zstd",
53
+ "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
54
+ "Cookie": self.cookies
55
+ }
56
+
57
+ def set_model_name(self, model_name: str):
58
+ """Set model name
59
+
60
+ Args:
61
+ model_name: Model name to use
62
+ """
63
+ self.model_name = model_name
64
+
65
+ def _generate_request_id(self):
66
+ self.request_id = str(uuid.uuid4()).replace("-", "")
67
+
68
+ def chat(self, message: str) -> Generator[str, None, None]:
69
+ if not self.request_id:
70
+ self._generate_request_id()
71
+ url = "https://api.tongyi.com/dialog/conversation"
72
+ headers = self._get_base_headers()
73
+
74
+ headers["accept"] = "text/event-stream"
75
+
76
+ # Prepare contents array with message
77
+ contents = [{
78
+ "content": message,
79
+ "contentType": "text",
80
+ "role": "user",
81
+ "ext": {
82
+ "searchType": "",
83
+ "pptGenerate": False,
84
+ "deepThink": False,
85
+ "deepResearch": False
86
+ }
87
+ }]
88
+
89
+ # Add system message if it's first chat
90
+ if self.first_chat and self.system_message:
91
+ contents.insert(0, {
92
+ "content": self.system_message,
93
+ "contentType": "text",
94
+ "role": "system",
95
+ "ext": {
96
+ "searchType": "",
97
+ "pptGenerate": False,
98
+ "deepThink": False,
99
+ "deepResearch": False
100
+ }
101
+ })
102
+ self.first_chat = False
103
+
104
+ # Add uploaded files to contents if available and clear after use
105
+ if self.uploaded_file_info:
106
+ for file_info in self.uploaded_file_info:
107
+ contents.append({
108
+ "role": "user",
109
+ "contentType": "file",
110
+ "content": file_info["url"],
111
+ "ext": {
112
+ "fileSize": file_info.get("fileSize", 0),
113
+ "batchId": file_info.get("batchId", ""),
114
+ "docId": file_info.get("docId", "")
115
+ }
116
+ })
117
+ # Clear uploaded file info after using it
118
+ self.uploaded_file_info = []
119
+
120
+ payload = {
121
+ "model": "",
122
+ "action": "next",
123
+ "mode": "chat",
124
+ "userAction": "new_top",
125
+ "requestId": self.request_id,
126
+ "sessionId": self.session_id,
127
+ "sessionType": "text_chat",
128
+ "parentMsgId": self.msg_id,
129
+ "params": {
130
+ "agentId": "",
131
+ "searchType": "",
132
+ "pptGenerate": False,
133
+ "bizScene": "code_chat" if self.model_name == "Code-Chat" else "",
134
+ "bizSceneInfo": {},
135
+ "specifiedModel": "",
136
+ "deepThink": True if self.model_name == "Thinking" else False,
137
+ "deepResearch": False,
138
+ "fileUploadBatchId": self.uploaded_file_info[0]["batchId"] if self.uploaded_file_info else ""
139
+ },
140
+ "contents": contents
141
+ }
142
+
143
+ try:
144
+ response = while_success(lambda: requests.post(url, headers=headers, json=payload, stream=True), sleep_time=5)
145
+ if response.status_code != 200:
146
+ raise Exception(f"HTTP {response.status_code}: {response.text}")
147
+ msg_id = ""
148
+ session_id = ""
149
+ thinking_content = ""
150
+ text_content = ""
151
+ in_thinking = False
152
+ for line in response.iter_lines():
153
+ if not line:
154
+ continue
155
+ line_str = line.decode('utf-8')
156
+ if not line_str.startswith("data: "):
157
+ continue
158
+
159
+ try:
160
+ data = json.loads(line_str[6:])
161
+ # 记录消息ID和会话ID
162
+ if "msgId" in data:
163
+ msg_id = data["msgId"]
164
+ if "sessionId" in data:
165
+ session_id = data["sessionId"]
166
+
167
+ if "contents" in data and len(data["contents"]) > 0:
168
+ for content in data["contents"]:
169
+ if content.get("contentType") == "think":
170
+ if not in_thinking:
171
+ yield "<think>\n\n"
172
+ in_thinking = True
173
+ if content.get("incremental"):
174
+ tmp_content = json.loads(content.get("content"))["content"]
175
+ thinking_content += tmp_content
176
+ yield tmp_content
177
+ else:
178
+ tmp_content = json.loads(content.get("content"))["content"]
179
+ if len(thinking_content) < len(tmp_content):
180
+ yield tmp_content[len(thinking_content):]
181
+ thinking_content = tmp_content
182
+ else:
183
+ # thinking_content = "aaa</thi"
184
+ # tmp_content = "aaa"
185
+ # 应该yield nk>
186
+ # print("\n")
187
+ # print(len(thinking_content))
188
+ # print(len(tmp_content))
189
+ # print("--------------------------------")
190
+ # print(thinking_content)
191
+ # print("--------------------------------")
192
+ # print(tmp_content)
193
+ # print("--------------------------------")
194
+ yield "\r\n</think>\n"[len(thinking_content)-len(tmp_content):]
195
+ thinking_content = tmp_content
196
+ in_thinking = False
197
+ elif content.get("contentType") == "text":
198
+ if in_thinking:
199
+ continue
200
+ if content.get("incremental"):
201
+ tmp_content = content.get("content")
202
+ text_content += tmp_content
203
+ yield tmp_content
204
+ else:
205
+ tmp_content = content.get("content")
206
+ if len(text_content) < len(tmp_content):
207
+ yield tmp_content[len(text_content):]
208
+ text_content = tmp_content
209
+
210
+
211
+ except json.JSONDecodeError:
212
+ continue
213
+
214
+ self.msg_id = msg_id
215
+ self.session_id = session_id
216
+
217
+ return None
218
+
219
+ except Exception as e:
220
+ raise Exception(f"Chat failed: {str(e)}")
221
+
222
+ def _get_upload_token(self) -> Dict[str, Any]:
223
+ """Get upload token from Tongyi API
224
+
225
+ Returns:
226
+ Dict[str, Any]: Upload token information including accessId, bucketName, etc.
227
+ """
228
+ url = "https://api.tongyi.com/dialog/uploadToken"
229
+ headers = self._get_base_headers()
230
+ payload = {}
231
+
232
+ try:
233
+ response = while_success(lambda: requests.post(url, headers=headers, json=payload), sleep_time=5)
234
+ if response.status_code != 200:
235
+ raise Exception(f"HTTP {response.status_code}: {response.text}")
236
+
237
+ result = response.json()
238
+ if not result.get("success"):
239
+ raise Exception(f"Failed to get upload token: {result.get('errorMsg')}")
240
+
241
+ return result.get("data", {})
242
+
243
+ except Exception as e:
244
+ raise Exception(f"Failed to get upload token: {str(e)}")
245
+
246
+
247
+ def upload_files(self, file_list: List[str]) -> bool:
248
+ """Upload files to Tongyi platform and get download links
249
+
250
+ Args:
251
+ file_list: List of file paths to upload
252
+
253
+ Returns:
254
+ List[Dict[str, str]]: List of dictionaries containing file info and download URLs
255
+ """
256
+ try:
257
+ upload_token = self._get_upload_token()
258
+ uploaded_files = []
259
+
260
+ for file_path in file_list:
261
+ file_name = os.path.basename(file_path)
262
+ with yaspin(Spinners.dots, text=f"上传文件 {file_name}") as spinner:
263
+ try:
264
+ if not os.path.exists(file_path):
265
+ spinner.text = f"文件不存在: {file_path}"
266
+ spinner.fail("❌")
267
+ return False
268
+
269
+ # Get file name and content type
270
+ content_type = self._get_content_type(file_path)
271
+
272
+ spinner.text = f"准备上传文件: {file_name}"
273
+
274
+ # Prepare form data
275
+ form_data = {
276
+ 'OSSAccessKeyId': upload_token['accessId'],
277
+ 'policy': upload_token['policy'],
278
+ 'signature': upload_token['signature'],
279
+ 'key': f"{upload_token['dir']}{file_name}",
280
+ 'dir': upload_token['dir'],
281
+ 'success_action_status': '200'
282
+ }
283
+
284
+ # Prepare files
285
+ files = {
286
+ 'file': (file_name, open(file_path, 'rb'), content_type)
287
+ }
288
+
289
+ spinner.text = f"正在上传文件: {file_name}"
290
+
291
+ # Upload file
292
+ response = requests.post(
293
+ upload_token['host'],
294
+ data=form_data,
295
+ files=files
296
+ )
297
+
298
+ if response.status_code != 200:
299
+ spinner.text = f"上传失败 {file_name}: HTTP {response.status_code}"
300
+ spinner.fail("❌")
301
+ return False
302
+
303
+ uploaded_files.append({
304
+ 'fileKey': file_name,
305
+ 'fileType': 'file',
306
+ 'dir': upload_token['dir']
307
+ })
308
+
309
+ spinner.text = f"获取下载链接: {file_name}"
310
+
311
+ # Get download links for uploaded files
312
+ url = "https://api.tongyi.com/dialog/downloadLink/batch"
313
+ headers = self._get_base_headers()
314
+ payload = {
315
+ "fileKeys": [f['fileKey'] for f in uploaded_files],
316
+ "fileType": "file",
317
+ "dir": upload_token['dir']
318
+ }
319
+
320
+ response = requests.post(url, headers=headers, json=payload)
321
+ if response.status_code != 200:
322
+ spinner.text = f"获取下载链接失败: HTTP {response.status_code}"
323
+ spinner.fail("❌")
324
+ return False
325
+
326
+ result = response.json()
327
+ if not result.get("success"):
328
+ spinner.text = f"获取下载链接失败: {result.get('errorMsg')}"
329
+ spinner.fail("❌")
330
+ return False
331
+
332
+ # Add files to chat
333
+ self.uploaded_file_info = result.get("data", {}).get("results", [])
334
+ for file_info in self.uploaded_file_info:
335
+ spinner.text = f"添加文件到对话: {file_name}"
336
+ add_url = "https://api.tongyi.com/assistant/api/chat/file/add"
337
+ add_payload = {
338
+ "workSource": "chat",
339
+ "terminal": "web",
340
+ "workCode": "0",
341
+ "channel": "home",
342
+ "workType": "file",
343
+ "module": "uploadhistory",
344
+ "workName": file_info["fileKey"],
345
+ "workId": file_info["docId"],
346
+ "workResourcePath": file_info["url"],
347
+ "sessionId": "",
348
+ "batchId": str(uuid.uuid4()).replace('-', '')[:32], # Generate random batchId
349
+ "fileSize": os.path.getsize(file_path)
350
+ }
351
+
352
+ add_response = requests.post(add_url, headers=headers, json=add_payload)
353
+ if add_response.status_code != 200:
354
+ spinner.text = f"添加文件到对话失败: HTTP {add_response.status_code}"
355
+ spinner.fail("❌")
356
+ continue
357
+
358
+ add_result = add_response.json()
359
+ if not add_result.get("success"):
360
+ spinner.text = f"添加文件到对话失败: {add_result.get('errorMsg')}"
361
+ spinner.fail("❌")
362
+ continue
363
+
364
+ file_info.update(add_result.get("data", {}))
365
+
366
+ spinner.text = f"文件 {file_name} 上传成功"
367
+ spinner.ok("✅")
368
+ time.sleep(1) # 短暂暂停以便用户看到成功状态
369
+
370
+ except Exception as e:
371
+ spinner.text = f"上传文件 {file_name} 时出错: {str(e)}"
372
+ spinner.fail("❌")
373
+ return False
374
+
375
+ return True
376
+
377
+ except Exception as e:
378
+ PrettyOutput.print(f"Error uploading files: {str(e)}", OutputType.ERROR)
379
+ return False
380
+
381
+ def _get_content_type(self, file_path: str) -> str:
382
+ """Get content type for file
383
+
384
+ Args:
385
+ file_path: Path to file
386
+
387
+ Returns:
388
+ str: Content type
389
+ """
390
+ ext = os.path.splitext(file_path)[1].lower()
391
+ content_types = {
392
+ '.txt': 'text/plain',
393
+ '.md': 'text/markdown',
394
+ '.doc': 'application/msword',
395
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
396
+ '.xls': 'application/vnd.ms-excel',
397
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
398
+ '.pdf': 'application/pdf',
399
+ '.png': 'image/png',
400
+ '.jpg': 'image/jpeg',
401
+ '.jpeg': 'image/jpeg',
402
+ '.gif': 'image/gif',
403
+ '.mp4': 'video/mp4',
404
+ '.mp3': 'audio/mpeg',
405
+ '.wav': 'audio/wav'
406
+ }
407
+ return content_types.get(ext, 'application/octet-stream')
408
+
409
+ def name(self) -> str:
410
+ """Get platform name
411
+
412
+ Returns:
413
+ str: Platform name
414
+ """
415
+ return self.model_name
416
+
417
+ def delete_chat(self) -> bool:
418
+ """Delete chat history
419
+
420
+ Returns:
421
+ bool: True if deletion successful, False otherwise
422
+ """
423
+ if not self.session_id:
424
+ return True
425
+
426
+ url = "https://api.tongyi.com/dialog/session/delete"
427
+ headers = self._get_base_headers()
428
+ payload = {
429
+ "sessionId": self.session_id
430
+ }
431
+
432
+ try:
433
+ response = while_success(lambda: requests.post(url, headers=headers, json=payload), sleep_time=5)
434
+ if response.status_code != 200:
435
+ PrettyOutput.print(f"Failed to delete chat: HTTP {response.status_code}", OutputType.ERROR)
436
+ return False
437
+ self.request_id = ""
438
+ self.session_id = ""
439
+ self.msg_id = ""
440
+ self.first_chat = True # Reset first_chat flag
441
+ return True
442
+ except Exception as e:
443
+ PrettyOutput.print(f"Error deleting chat: {str(e)}", OutputType.ERROR)
444
+ return False
445
+
446
+ def set_system_message(self, message: str):
447
+ """Set system message
448
+
449
+ Args:
450
+ message: System message to set
451
+ """
452
+ self.system_message = message
453
+
454
+ def get_model_list(self) -> List[Tuple[str, str]]:
455
+ """Get available model list
456
+
457
+ Returns:
458
+ List[Tuple[str, str]]: List of (model_id, model_name) tuples
459
+ """
460
+ return [
461
+ ("Normal", "Normal"),
462
+ ("Thinking", "Thinking"),
463
+ ("Deep-Research", "Deep-Research"),
464
+ ("Code-Chat", "Code-Chat"),
465
+ ]
466
+
467
+ def support_web(self) -> bool:
468
+ """Check if platform supports web functionality
469
+
470
+ Returns:
471
+ bool: True if web is supported, False otherwise
472
+ """
473
+ return True
@@ -430,6 +430,8 @@ class YuanbaoPlatform(BasePlatform):
430
430
  if hasattr(response, 'text'):
431
431
  error_msg += f", 响应: {response.text}"
432
432
  raise Exception(error_msg)
433
+
434
+ in_thinking = False
433
435
 
434
436
  # 处理SSE流响应
435
437
  for line in response.iter_lines():
@@ -446,12 +448,18 @@ class YuanbaoPlatform(BasePlatform):
446
448
 
447
449
  # 处理文本类型的消息
448
450
  if data.get("type") == "text":
451
+ if in_thinking:
452
+ yield "</think>\n"
453
+ in_thinking = False
449
454
  msg = data.get("msg", "")
450
455
  if msg:
451
456
  yield msg
452
457
 
453
458
  # 处理思考中的消息
454
459
  elif data.get("type") == "think":
460
+ if not in_thinking:
461
+ yield "<think>\n"
462
+ in_thinking = True
455
463
  think_content = data.get("content", "")
456
464
  if think_content:
457
465
  yield think_content
@@ -88,18 +88,9 @@ class generate_new_tool:
88
88
  "stderr": f"工具 '{tool_name}' 已经存在于 {tool_file_path}"
89
89
  }
90
90
 
91
- # 验证并处理工具代码
92
- processed_code, error_msg = self._validate_and_process_code(tool_name, tool_code)
93
- if error_msg:
94
- return {
95
- "success": False,
96
- "stdout": "",
97
- "stderr": error_msg
98
- }
99
-
100
91
  # 写入工具文件
101
92
  with open(tool_file_path, "w", encoding="utf-8") as f:
102
- f.write(processed_code)
93
+ f.write(tool_code)
103
94
 
104
95
  # 注册新工具到当前的工具注册表
105
96
  success_message = f"工具 '{tool_name}' 已成功生成在 {tool_file_path}"
@@ -152,87 +143,4 @@ class generate_new_tool:
152
143
  "success": False,
153
144
  "stdout": "",
154
145
  "stderr": error_msg
155
- }
156
-
157
- def _validate_and_process_code(self, tool_name: str, tool_code: str) -> Tuple[str, str]:
158
- """
159
- 验证并处理工具代码
160
-
161
- 参数:
162
- tool_name: 工具名称
163
- tool_code: 工具代码
164
-
165
- 返回:
166
- Tuple[str, str]: (处理后的代码, 错误信息)
167
- """
168
- # 检查工具代码中是否包含类定义
169
- if f"class {tool_name}" not in tool_code:
170
- # 尝试找到任何类定义
171
- class_match = re.search(r"class\s+(\w+)", tool_code)
172
- if class_match:
173
- old_class_name = class_match.group(1)
174
- # 替换类名为工具名
175
- tool_code = tool_code.replace(f"class {old_class_name}", f"class {tool_name}")
176
- tool_code = tool_code.replace(f'name = "{old_class_name}"', f'name = "{tool_name}"')
177
- else:
178
- # 没有找到类定义,返回错误
179
- return "", f"工具代码中缺少类定义 'class {tool_name}'"
180
-
181
- # 检查工具代码中是否包含必要的属性和方法
182
- missing_components = []
183
-
184
- if f'name = "{tool_name}"' not in tool_code and f"name = '{tool_name}'" not in tool_code:
185
- # 尝试查找任何name属性并修复
186
- name_match = re.search(r'name\s*=\s*["\'](\w+)["\']', tool_code)
187
- if name_match:
188
- old_name = name_match.group(1)
189
- tool_code = re.sub(r'name\s*=\s*["\'](\w+)["\']', f'name = "{tool_name}"', tool_code)
190
- else:
191
- missing_components.append(f"name = \"{tool_name}\"")
192
-
193
- if "description = " not in tool_code:
194
- missing_components.append("description 属性")
195
-
196
- if "parameters = " not in tool_code:
197
- missing_components.append("parameters 属性")
198
-
199
- if "def execute(self, args:" not in tool_code:
200
- missing_components.append("execute 方法")
201
-
202
- if "def check(" not in tool_code:
203
- # 添加默认的check方法
204
- class_match = re.search(r"class\s+(\w+).*?:", tool_code, re.DOTALL)
205
- if class_match:
206
- indent = " " # 默认缩进
207
- # 找到类定义后的第一个属性
208
- first_attr_match = re.search(r"class\s+(\w+).*?:(.*?)(\w+\s*=)", tool_code, re.DOTALL)
209
- if first_attr_match:
210
- # 获取属性前的缩进
211
- attr_indent = re.search(r"\n([ \t]*)\w+\s*=", first_attr_match.group(2))
212
- if attr_indent:
213
- indent = attr_indent.group(1)
214
-
215
- check_method = f"\n{indent}@staticmethod\n{indent}def check() -> bool:\n{indent} \"\"\"检查工具是否可用\"\"\"\n{indent} return True\n"
216
-
217
- # 在类定义后插入check方法
218
- pattern = r"(class\s+(\w+).*?:.*?)(\n\s*\w+\s*=|\n\s*@|\n\s*def)"
219
- replacement = r"\1" + check_method + r"\3"
220
- tool_code = re.sub(pattern, replacement, tool_code, 1, re.DOTALL)
221
-
222
- # 如果缺少必要组件,返回错误信息
223
- if missing_components:
224
- return "", f"工具代码中缺少以下必要组件: {', '.join(missing_components)}"
225
-
226
- # 确保代码有正确的Python文件头部
227
- if not tool_code.startswith("# -*- coding:") and not tool_code.startswith("# coding="):
228
- tool_code = "# -*- coding: utf-8 -*-\n" + tool_code
229
-
230
- # 确保导入了必要的模块
231
- if "from typing import Dict, Any" not in tool_code:
232
- imports_pos = tool_code.find("\n\n")
233
- if imports_pos > 0:
234
- tool_code = tool_code[:imports_pos] + "\nfrom typing import Dict, Any" + tool_code[imports_pos:]
235
- else:
236
- tool_code = "from typing import Dict, Any\n\n" + tool_code
237
-
238
- return tool_code, ""
146
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.182
3
+ Version: 0.1.184
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
@@ -153,6 +153,35 @@ Kimi API Key获取方式:
153
153
  删除Bearer前缀,剩下的内容就是Kimi API Key。
154
154
 
155
155
 
156
+ #### 通义千问
157
+ ```yaml
158
+ JARVIS_PLATFORM: tongyi
159
+ JARVIS_MODEL: Normal # 可选模型:Normal, Thinking, Deep-Research, Code-Chat
160
+ JARVIS_THINKING_PLATFORM: tongyi
161
+ JARVIS_THINKING_MODEL: Thinking
162
+
163
+ ENV:
164
+ TONGYI_COOKIES: <通义千问cookies>
165
+ ```
166
+
167
+ 通义千问cookies获取方式:
168
+
169
+ ![通义千问cookies获取方式](docs/images/tongyi.png)
170
+
171
+ 1. 登录[通义千问](https://www.tongyi.com/qianwen)
172
+ 2. 打开浏览器开发者工具(F12)
173
+ 3. 在Network标签页中找到任意请求
174
+ 4. 在请求头中找到Cookie字段,复制其值
175
+
176
+ 配置说明:
177
+ 1. `TONGYI_COOKIES`: 必填,用于身份验证
178
+ 2. 支持的模型:
179
+ - `Normal`: 标准对话模型
180
+ - `Thinking`: 深度思考模型
181
+ - `Deep-Research`: 深度研究模型
182
+ - `Code-Chat`: 代码对话模型
183
+
184
+
156
185
  #### OpenAI
157
186
  ```yaml
158
187
  JARVIS_PLATFORM: openai
@@ -57,6 +57,7 @@ src/jarvis/jarvis_platform/human.py
57
57
  src/jarvis/jarvis_platform/kimi.py
58
58
  src/jarvis/jarvis_platform/openai.py
59
59
  src/jarvis/jarvis_platform/registry.py
60
+ src/jarvis/jarvis_platform/tongyi.py
60
61
  src/jarvis/jarvis_platform/yuanbao.py
61
62
  src/jarvis/jarvis_platform_manager/__init__.py
62
63
  src/jarvis/jarvis_platform_manager/main.py