pycoze 0.1.409__tar.gz → 0.1.410__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 (43) hide show
  1. {pycoze-0.1.409 → pycoze-0.1.410}/PKG-INFO +1 -1
  2. pycoze-0.1.410/pycoze/bot/chat_base.py +280 -0
  3. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze.egg-info/PKG-INFO +1 -1
  4. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze.egg-info/SOURCES.txt +1 -0
  5. {pycoze-0.1.409 → pycoze-0.1.410}/setup.py +1 -1
  6. {pycoze-0.1.409 → pycoze-0.1.410}/LICENSE +0 -0
  7. {pycoze-0.1.409 → pycoze-0.1.410}/README.md +0 -0
  8. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/__init__.py +0 -0
  9. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ai/__init__.py +0 -0
  10. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ai/llm/__init__.py +0 -0
  11. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ai/llm/chat.py +0 -0
  12. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ai/llm/text_to_image_prompt.py +0 -0
  13. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/api/__init__.py +0 -0
  14. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/api/lib/__init__.py +0 -0
  15. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/api/lib/tab.py +0 -0
  16. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/api/lib/view.py +0 -0
  17. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/api/lib/web.py +0 -0
  18. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/api/lib/window.py +0 -0
  19. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/bot/__init__.py +0 -0
  20. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/bot/chat.py +0 -0
  21. /pycoze-0.1.409/pycoze/bot/chat_base.py → /pycoze-0.1.410/pycoze/bot/chat_base copy.py +0 -0
  22. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/bot/lib.py +0 -0
  23. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/bot/message.py +0 -0
  24. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/bot/prompt.md +0 -0
  25. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/bot/tools.py +0 -0
  26. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/reference/__init__.py +0 -0
  27. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/reference/bot.py +0 -0
  28. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/reference/lib.py +0 -0
  29. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/reference/tool.py +0 -0
  30. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/reference/workflow.py +0 -0
  31. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ui/__init__.py +0 -0
  32. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ui/base.py +0 -0
  33. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ui/color.py +0 -0
  34. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ui/typ.py +0 -0
  35. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/ui/ui_def.py +0 -0
  36. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/utils/__init__.py +0 -0
  37. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/utils/arg.py +0 -0
  38. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/utils/env.py +0 -0
  39. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/utils/socket.py +0 -0
  40. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze/utils/text_or_file.py +0 -0
  41. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze.egg-info/dependency_links.txt +0 -0
  42. {pycoze-0.1.409 → pycoze-0.1.410}/pycoze.egg-info/top_level.txt +0 -0
  43. {pycoze-0.1.409 → pycoze-0.1.410}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pycoze
3
- Version: 0.1.409
3
+ Version: 0.1.410
4
4
  Summary: Package for pycoze only!
5
5
  Author: Yuan Jie Xiong
6
6
  Author-email: aiqqqqqqq@qq.com
@@ -0,0 +1,280 @@
1
+ import json
2
+ import os
3
+ from .lib import get_formatted_filelist_str, read_local_file, resolve_relative_path
4
+ from .message import info
5
+ from pycoze.ai import chat_stream_async, extract
6
+ from .tools import ToolExecutor
7
+ from typing import List
8
+
9
+ def guess_files_in_message(cwd: str, user_message: str) -> List[str]:
10
+ try:
11
+ value = extract(
12
+ {"includedFiles": ["relative path format", "relative path format", "..."]},
13
+ 'Please find the files mentioned in the text. If none, return {"includedFiles": []}:\n'
14
+ + user_message,
15
+ )
16
+ return [resolve_relative_path(cwd, p) for p in value["includedFiles"]]
17
+ except:
18
+ print("Failed to guess files in message")
19
+ return []
20
+
21
+
22
+ def format_content(cwd, potential_paths, conversation_history):
23
+ content = []
24
+ for file_path in potential_paths:
25
+ file_path = resolve_relative_path(cwd, file_path)
26
+ if os.path.isfile(file_path):
27
+ file_marker = f"[[{file_path}]]'"
28
+ file_content = read_local_file(file_path)
29
+ if not any(
30
+ file_marker in msg["content"] for msg in conversation_history
31
+ ):
32
+ content.append(f"{file_marker}\n{file_content}")
33
+ return (
34
+ "Partial contents of files are as follows:" + "\n".join(content)
35
+ if content
36
+ else ""
37
+ )
38
+
39
+ def generate_user_task_prompt(conversation_history, cwd, user_input: str, bot_setting_file:str):
40
+ # 需要重新读取openedFiles和activeFile
41
+ with open(bot_setting_file, encoding="utf-8") as f:
42
+ bot_setting = json.load(f)
43
+ folder_context = bot_setting["folderContext"]
44
+ opened_files = bot_setting["openedFiles"]
45
+ active_file = bot_setting["activeFile"]
46
+
47
+ if folder_context:
48
+ potential_paths = guess_files_in_message(cwd, user_input)
49
+
50
+ existing_files = get_formatted_filelist_str(cwd, True, 200)
51
+
52
+ active_file_str = f"Currently viewing: {active_file}" if active_file else ""
53
+
54
+ opened_files_str = (
55
+ f"Open tabs:\n{'\n'.join(opened_files)}" if opened_files else ""
56
+ )
57
+ existing_files_str = f"Files in directory:\n{existing_files}" if existing_files else ""
58
+ return f"""<task>
59
+ {user_input}
60
+ </task>
61
+
62
+ <environment_details>
63
+ Current working directory: {cwd}
64
+
65
+ {active_file_str}
66
+
67
+ {opened_files_str}
68
+
69
+ {existing_files_str}
70
+
71
+ {format_content(cwd, potential_paths, conversation_history)}
72
+
73
+ </environment_details>
74
+ """
75
+
76
+ else:
77
+ return f"""<task>
78
+ {user_input}
79
+ </task>
80
+ """
81
+
82
+
83
+ def dumps_markdown_json(data):
84
+ json_str = json.dumps(data, indent=4, ensure_ascii=False)
85
+ return f"\n```json\n{json_str}\n```\n"
86
+
87
+
88
+
89
+ async def stream_openai_response(conversation_history, start_new_stream):
90
+ """
91
+ 异步流式传输 OpenAI 聊天完成响应并处理结构化输出
92
+ """
93
+ stream = None
94
+ buffer = ""
95
+ in_json_block = False
96
+ json_block_content = ""
97
+ text_content = ""
98
+
99
+ while True:
100
+ # 检查是否需要重新创建流
101
+ if stream is None or start_new_stream["value"]:
102
+ if stream is not None:
103
+ await stream.aclose() # 关闭之前的流
104
+ stream = chat_stream_async(conversation_history) # 获取新的异步生成器
105
+ start_new_stream["value"] = False # 重置标志
106
+ buffer = ""
107
+ in_json_block = False
108
+ json_block_content = ""
109
+ text_content = ""
110
+
111
+ # 使用 async for 迭代异步生成器
112
+ try:
113
+ async for chunk in stream:
114
+ info("assistant", chunk)
115
+ buffer += chunk
116
+
117
+ # 检查是否需要重新创建流
118
+ if start_new_stream["value"]:
119
+ break # 退出当前的 async for 循环,进入下一次 while 循环
120
+
121
+ # 处理 buffer 中的每一行
122
+ while "\n" in buffer:
123
+ line, buffer = buffer.split("\n", 1)
124
+ if not in_json_block:
125
+ if line.strip().lower().startswith("```json"):
126
+ if text_content:
127
+ yield ("text", text_content.strip())
128
+ text_content = ""
129
+ in_json_block = True
130
+ else:
131
+ text_content += line + "\n"
132
+ else:
133
+ if line.strip().lower().startswith("```") and in_json_block:
134
+ yield ("json", json_block_content.strip())
135
+ json_block_content = ""
136
+ in_json_block = False
137
+ else:
138
+ json_block_content += line + "\n"
139
+
140
+ # 如果流正常结束,退出 while 循环
141
+ break
142
+
143
+ except Exception as e:
144
+ # 捕获其他异常(如网络错误)
145
+ print(f"Error: {e}", style="bold red")
146
+ break
147
+
148
+ # 处理 buffer 中剩余的内容
149
+ if buffer:
150
+ if in_json_block:
151
+ buffer = buffer.split("```")[0]
152
+ json_block_content += buffer
153
+ yield ("json", json_block_content.strip())
154
+ else:
155
+ text_content += buffer
156
+ if text_content:
157
+ yield ("text", text_content.strip())
158
+
159
+
160
+ async def handle_user_inputs(
161
+ conversation_history, user_input, cwd, abilities, has_any_tool, bot_setting, bot_setting_file:str
162
+ ):
163
+ no_exit_if_incomplete = bot_setting["systemAbility"]["no_exit_if_incomplete"]
164
+ show_tool_results = bot_setting["showToolResults"]
165
+
166
+ start_new_stream = {
167
+ "value": False
168
+ } # 当遇到AI准备执行JSON,即需要新信息的时候,用于强制停止当前stream,减少后续无效的tokens
169
+
170
+ print("Processing user command", user_input)
171
+ if user_input.lower() in ["exit", "quit"]:
172
+ exit(0)
173
+ # 将用户消息添加到对话历史
174
+ conversation_history.append(
175
+ {
176
+ "role": "user",
177
+ "content": generate_user_task_prompt(
178
+ conversation_history, cwd, user_input, bot_setting_file
179
+ ),
180
+ }
181
+ )
182
+ need_break = False
183
+
184
+ if no_exit_if_incomplete:
185
+ okay_str = 'Okay, please continue. If the tasks within <task>...task content...</task> have been completed, execute the tool "complete_all_tasks". If you have a question, use "ask_follow_up_question".'
186
+ else:
187
+ okay_str = "Okay"
188
+ while True:
189
+ async for response in stream_openai_response(
190
+ conversation_history, start_new_stream
191
+ ):
192
+ if len(response) == 2:
193
+ if (
194
+ response[0] == "text"
195
+ and response[1].strip() != ""
196
+ or (response[0] == "json" and not has_any_tool)
197
+ ):
198
+ if response[0] == 'text':
199
+ conversation_history.append(
200
+ {"role": "assistant", "content": response[1]}
201
+ )
202
+ else:
203
+ conversation_history.append(
204
+ {"role": "assistant", "content": "\n```" + response[0] + "\n" + response[1] + "\n```\n"}
205
+ )
206
+
207
+ conversation_history.append(
208
+ {
209
+ "role": "user",
210
+ "content": okay_str,
211
+ }
212
+ )
213
+ continue
214
+ elif response[0] == "json":
215
+ info("assistant", "\n")
216
+ cleaned_content = response[1]
217
+ try:
218
+ tool_request = json.loads(cleaned_content)
219
+ tool_name = list(tool_request.keys())[0]
220
+ except json.JSONDecodeError as e:
221
+ conversation_history.append(
222
+ {
223
+ "role": "assistant",
224
+ "content": f"\n```json\n{cleaned_content}\n```\n",
225
+ }
226
+ )
227
+ conversation_history.append(
228
+ {
229
+ "role": "user",
230
+ "content": "Invalid JSON content:" + str(e),
231
+ }
232
+ )
233
+ continue
234
+
235
+ ok, is_json_dumps, result = ToolExecutor.execute_tool(
236
+ cwd, tool_request, abilities
237
+ )
238
+
239
+ assistant_content = (
240
+ "Executing tool: \n"
241
+ + dumps_markdown_json(tool_request)
242
+ + "\n\n[Tool Result Begin]\n"
243
+ + result
244
+ + "\n[Tool Result End]\n"
245
+ )
246
+ lang = "json" if is_json_dumps else "text"
247
+
248
+ if show_tool_results:
249
+ status_str = "✅\n" if ok else "❌\n"
250
+ info("assistant", status_str + f"\n```{lang}\n" + result + "\n```\n\n")
251
+
252
+ conversation_history.append(
253
+ {"role": "assistant", "content": assistant_content}
254
+ )
255
+ if tool_name in ["complete_all_tasks", "ask_follow_up_question"]:
256
+ need_break = True
257
+ break
258
+ else:
259
+ conversation_history.append(
260
+ {
261
+ "role": "user",
262
+ "content": okay_str,
263
+ }
264
+ )
265
+ start_new_stream["value"] = True
266
+
267
+ if need_break:
268
+ break
269
+ if not no_exit_if_incomplete and not start_new_stream["value"]:
270
+ break
271
+ last_conversation = conversation_history[-1]
272
+ if last_conversation["role"] == 'user' and last_conversation["content"] == okay_str:
273
+ conversation_history.pop()
274
+
275
+ # 示例调用
276
+ # user_input_list = [
277
+ # "访问https://api-docs.deepseek.com/zh-cn/guides/chat_prefix_completion,并结合它编写一段代码,并保存"
278
+ # ]
279
+
280
+ # asyncio.run(handle_user_inputs(user_input_list))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pycoze
3
- Version: 0.1.409
3
+ Version: 0.1.410
4
4
  Summary: Package for pycoze only!
5
5
  Author: Yuan Jie Xiong
6
6
  Author-email: aiqqqqqqq@qq.com
@@ -18,6 +18,7 @@ pycoze/api/lib/web.py
18
18
  pycoze/api/lib/window.py
19
19
  pycoze/bot/__init__.py
20
20
  pycoze/bot/chat.py
21
+ pycoze/bot/chat_base copy.py
21
22
  pycoze/bot/chat_base.py
22
23
  pycoze/bot/lib.py
23
24
  pycoze/bot/message.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="pycoze",
5
- version="0.1.409",
5
+ version="0.1.410",
6
6
  packages=find_packages(),
7
7
  install_requires=[],
8
8
  author="Yuan Jie Xiong",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes