auto-coder 0.1.227__py3-none-any.whl → 0.1.229__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 auto-coder might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: auto-coder
3
- Version: 0.1.227
3
+ Version: 0.1.229
4
4
  Summary: AutoCoder: AutoCoder
5
5
  Author: allwefantasy
6
6
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
@@ -26,7 +26,7 @@ Requires-Dist: tabulate
26
26
  Requires-Dist: jupyter-client
27
27
  Requires-Dist: prompt-toolkit
28
28
  Requires-Dist: tokenizers
29
- Requires-Dist: byzerllm[saas] >=0.1.148
29
+ Requires-Dist: byzerllm[saas] >=0.1.150
30
30
  Requires-Dist: patch
31
31
  Requires-Dist: diff-match-patch
32
32
  Requires-Dist: GitPython
@@ -35,6 +35,7 @@ Requires-Dist: anthropic
35
35
  Requires-Dist: google-generativeai
36
36
  Requires-Dist: protobuf
37
37
  Requires-Dist: azure-cognitiveservices-speech
38
+ Requires-Dist: real-agent
38
39
  Requires-Dist: python-docx
39
40
  Requires-Dist: docx2txt
40
41
  Requires-Dist: pdf2image
@@ -1,17 +1,17 @@
1
1
  autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- autocoder/auto_coder.py,sha256=dggZdWFCXACD-5nObadXgA-JADDdwMwNkuyBhtqU_50,59164
2
+ autocoder/auto_coder.py,sha256=TGauh4UJQoPTL8rplB_DzziXnVw37A6-vs0TpT6VtVA,57054
3
3
  autocoder/auto_coder_lang.py,sha256=Rtupq6N3_HT7JRhDKdgCBcwRaiAnyCOR_Gsp4jUomrI,3229
4
4
  autocoder/auto_coder_rag.py,sha256=illKgzP2bv-Tq50ujsofJnOHdI4pzr0ALtfR8NHHWdQ,22351
5
5
  autocoder/auto_coder_rag_client_mcp.py,sha256=WV7j5JUiQge0x4-B7Hp5-pSAFXLbvLpzQMcCovbauIM,6276
6
6
  autocoder/auto_coder_rag_mcp.py,sha256=-RrjNwFaS2e5v8XDIrKR-zlUNUE8UBaeOtojffBrvJo,8521
7
7
  autocoder/auto_coder_server.py,sha256=XU9b4SBH7zjPPXaTWWHV4_zJm-XYa6njuLQaplYJH_c,20290
8
8
  autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
9
- autocoder/chat_auto_coder.py,sha256=ZKj_VdoEAFPsdInf_dQeBK6lQtz8Mzz7L4nLO6l8pEY,101456
9
+ autocoder/chat_auto_coder.py,sha256=eufxzEhopHzLPZUhE8epP5d3JVvcUWXrl_DdSh2-Sfs,101889
10
10
  autocoder/chat_auto_coder_lang.py,sha256=YJsFi8an0Kjbo9X7xKZfpdbHS3rbhrvChZNjWqEQ5Sw,11032
11
11
  autocoder/command_args.py,sha256=9aYJ-AmPxP1sQh6ciw04FWHjSn31f2W9afXFwo8wgx4,30441
12
12
  autocoder/lang.py,sha256=U6AjVV8Rs1uLyjFCZ8sT6WWuNUxMBqkXXIOs4S120uk,14511
13
- autocoder/models.py,sha256=shzX2EMArWZ7X8cS0yK4CwCJT5UPGzMaLgJwETrHdMA,5053
14
- autocoder/version.py,sha256=8GcCJXjjBKc6SzhEitvO8ub2W7HOhWSkKFq9aFDXd98,24
13
+ autocoder/models.py,sha256=YIvJZJ_Vrmff9mLyDuHvo8zd4YOnNP3v0uYG8oSu7ZM,5162
14
+ autocoder/version.py,sha256=sfyghLRAQ6aSLULneoCBX_LJssf68smbuYMGOKVEtDI,24
15
15
  autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  autocoder/agent/auto_demand_organizer.py,sha256=NWSAEsEk94vT3lGjfo25kKLMwYdPcpy9e-i21txPasQ,6942
17
17
  autocoder/agent/auto_filegroup.py,sha256=CW7bqp0FW1GIEMnl-blyAc2UGT7O9Mom0q66ITz1ckM,6635
@@ -36,15 +36,16 @@ autocoder/common/code_auto_generate.py,sha256=5lEW9iudGYQIcd_QjrGyGaEmrWuyZ625PN
36
36
  autocoder/common/code_auto_generate_diff.py,sha256=o5yeqpc3WXSRWlcLzhlwJNosKo7dcj0CeIsFh6Aibus,16248
37
37
  autocoder/common/code_auto_generate_editblock.py,sha256=QdUHUkGaervvQNCY8T2vQ_tfnQX_2kxxu4qq_QW_Nn8,17828
38
38
  autocoder/common/code_auto_generate_strict_diff.py,sha256=uteWDEHfIbrnVgwKgqC7qwrIeW0enJCXcHzZGa48yY8,14774
39
- autocoder/common/code_auto_merge.py,sha256=1tiKrram8GCCuPYrNvHFbr-Tic-f84Y8H13fDTdcg6c,7142
40
- autocoder/common/code_auto_merge_diff.py,sha256=5SI6ggklJ0QDHvsS0cpNXFuIkFRQxp1i08k6iwWbPJc,15242
41
- autocoder/common/code_auto_merge_editblock.py,sha256=l6yEiZqXyIlUNIIPXvkHOnLCIInXR78TzSjF-jtJkkg,17035
39
+ autocoder/common/code_auto_merge.py,sha256=CH0-6AKVLGjhWvKCFqnfSbt62rxL7ZBobFAX5FUzY5A,7164
40
+ autocoder/common/code_auto_merge_diff.py,sha256=zyA5BxNiAROyzOEJnozelarAaFK8BKgezXAbm4aq7DA,15239
41
+ autocoder/common/code_auto_merge_editblock.py,sha256=dp8PFs1inKy3u70jnt8hWLdUhL5Biz1zsjay4SXpGko,16942
42
42
  autocoder/common/code_auto_merge_strict_diff.py,sha256=ABYOTDUQYA4Bn4BwT1Rw812y49cHW3UH_JSpM9uJ6ig,9399
43
43
  autocoder/common/code_modification_ranker.py,sha256=DFlbwgdg8GK47zVcvfZSzkyniEKmTVLTOWejjcVIgaw,5121
44
44
  autocoder/common/command_completer.py,sha256=SSeb8MDH0JPvfdyW-S2uaHnui4VBDfSQvQPLbv3ORPA,9314
45
45
  autocoder/common/command_generator.py,sha256=v4LmU7sO-P7jEZIXCWHUC6P-vT7AvBi_x_PTwCqBAE8,1323
46
46
  autocoder/common/command_templates.py,sha256=mnB3n8i0yjH1mqzyClEg8Wpr9VbZV44kxky66Zu6OJY,8557
47
47
  autocoder/common/const.py,sha256=eTjhjh4Aj4CUzviJ81jaf3Y5cwqsLATySn2wJxaS6RQ,2911
48
+ autocoder/common/files.py,sha256=uGpfKASYwIncK_Vt_e_FOjFlO5VyAQOnRJe2SFdSWrg,877
48
49
  autocoder/common/git_utils.py,sha256=btK45sxvfm4tX3fBRNUPRZoGQuZuOEQrWSAwLy1yoLw,23095
49
50
  autocoder/common/image_to_page.py,sha256=O0cNO_vHHUP-fP4GXiVojShmNqkPnZXeIyiY1MRLpKg,13936
50
51
  autocoder/common/interpreter.py,sha256=62-dIakOunYB4yjmX8SHC0Gdy2h8NtxdgbpdqRZJ5vk,2833
@@ -78,7 +79,7 @@ autocoder/index/for_command.py,sha256=LGnz-OWogT8rd24m4Zcan7doLaijxqorAuiMk7WuRq
78
79
  autocoder/index/index.py,sha256=1HLwK-ylpibYjHgPommdaL1bRwGP1QGWONaNYExzqRc,34828
79
80
  autocoder/index/symbols_utils.py,sha256=CjcjUVajmJZB75Ty3a7kMv1BZphrm-tIBAdOJv6uo-0,2037
80
81
  autocoder/index/types.py,sha256=tYoFicbS6k1Dx4EoMpuNq71-4pF6hhEbtej0VYCVlSo,524
81
- autocoder/pyproject/__init__.py,sha256=7ZuIxD2QBYIwhjmpva8eL2knorKo03yNqUhSyecpt7c,14448
82
+ autocoder/pyproject/__init__.py,sha256=dQ2_7YZ7guybT9BhfxSGn43eLQJGQN2zgeKa6--JlaQ,14403
82
83
  autocoder/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
84
  autocoder/rag/api_server.py,sha256=dRbhAZVRAOlZ64Cnxf4_rKb4iJwHnrWS9Zr67IVORw0,7288
84
85
  autocoder/rag/doc_filter.py,sha256=B99Qcy3tcNLuSz2kWbpgfBj2_Igme91zWKOJ2Niq2UY,6652
@@ -111,9 +112,9 @@ autocoder/rag/stream_event/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
111
112
  autocoder/rag/stream_event/event_writer.py,sha256=l7kq_LnDDE8E5dZ-73C7J2MgzSL7WrozdXk0eV-k55Q,409
112
113
  autocoder/rag/stream_event/types.py,sha256=rtLwOE8rShmi1dJdxyBpAV5ZjLBGG9vptMiSzMxGuIA,318
113
114
  autocoder/regex_project/__init__.py,sha256=EBZeCL5ORyD_9_5u_UuG4s7XtpXOu0y1sWDmxWFtufE,6781
114
- autocoder/regexproject/__init__.py,sha256=lHTpHfYkguCMtczXoH4bMr-IMNZQtXIjmtSvjtfX0Ro,9674
115
- autocoder/suffixproject/__init__.py,sha256=2dBat5ZuYIPVCuDwYC58yuzHP5R79JLzGXnZHisLLGo,11061
116
- autocoder/tsproject/__init__.py,sha256=77hu4rBcicnXHBwKtBo8RQnd61R--gQbo9s00w-ICvg,11719
115
+ autocoder/regexproject/__init__.py,sha256=cEr-ZOaQjLD5sx7T7F2DhD5ips03HcJ02rded9EpSXc,9693
116
+ autocoder/suffixproject/__init__.py,sha256=cmP54Y01ditZ83tiJqw5wle0I-uJBC0aZbZ7lYNSVO8,11080
117
+ autocoder/tsproject/__init__.py,sha256=yloVzkGLnbTd4Hcj9fMO-rcjNTTx4wI3Ga41LWOSYrY,11747
117
118
  autocoder/utils/__init__.py,sha256=KtcGElFNBgZPF7dEL8zF9JpXkCAjoyDrzaREJBhJrcs,994
118
119
  autocoder/utils/_markitdown.py,sha256=RU88qn4eZfYIy0GDrPxlI8oYXIypbi63VRJjdlnE0VU,47431
119
120
  autocoder/utils/coder.py,sha256=rK8e0svQBe0NOP26dIGToUXgha_hUDgxlWoC_p_r7oc,5698
@@ -126,11 +127,13 @@ autocoder/utils/print_table.py,sha256=ZMRhCA9DD0FUfKyJBWd5bDdj1RrtPtgOMWSJwtvZcL
126
127
  autocoder/utils/queue_communicate.py,sha256=buyEzdvab1QA4i2QKbq35rG5v_9x9PWVLWWMTznWcYM,6832
127
128
  autocoder/utils/request_event_queue.py,sha256=r3lo5qGsB1dIjzVQ05dnr0z_9Z3zOkBdP1vmRciKdi4,2095
128
129
  autocoder/utils/request_queue.py,sha256=nwp6PMtgTCiuwJI24p8OLNZjUiprC-TsefQrhMI-yPE,3889
129
- autocoder/utils/rest.py,sha256=HawagAap3wMIDROGhY1730zSZrJR_EycODAA5qOj83c,8807
130
+ autocoder/utils/rest.py,sha256=opE_kBEdNQdxh350M5lUTMk5TViRfpuKP_qWc0B1lks,8861
130
131
  autocoder/utils/tests.py,sha256=BqphrwyycGAvs-5mhH8pKtMZdObwhFtJ5MC_ZAOiLq8,1340
131
- auto_coder-0.1.227.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
132
- auto_coder-0.1.227.dist-info/METADATA,sha256=wL1FIzxZxtMImRZSGTZyK4KemZ3cfHQZq0iI3Lbg9OI,2615
133
- auto_coder-0.1.227.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
134
- auto_coder-0.1.227.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
135
- auto_coder-0.1.227.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
136
- auto_coder-0.1.227.dist-info/RECORD,,
132
+ autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
+ autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=pBOyWa1qwCcsAag1XsLIeTMv_D4QN4ppGo5jFiKzIkE,4165
134
+ auto_coder-0.1.229.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
135
+ auto_coder-0.1.229.dist-info/METADATA,sha256=TAvwuRtI5_rO2QiAbGV_ug6L6bgkj8Jkj1p_p_zjz88,2641
136
+ auto_coder-0.1.229.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
137
+ auto_coder-0.1.229.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
138
+ auto_coder-0.1.229.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
139
+ auto_coder-0.1.229.dist-info/RECORD,,
autocoder/auto_coder.py CHANGED
@@ -42,6 +42,7 @@ from rich.live import Live
42
42
  from autocoder.auto_coder_lang import get_message
43
43
  from autocoder.common.memory_manager import save_to_memory_file
44
44
  from autocoder import models as models_module
45
+ from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
45
46
 
46
47
  console = Console()
47
48
 
@@ -1257,64 +1258,11 @@ def main(input_args: Optional[List[str]] = None):
1257
1258
  v = chat_llm.stream_chat_oai(
1258
1259
  conversations=loaded_conversations, delta_mode=True
1259
1260
  )
1260
-
1261
- assistant_response = ""
1262
- markdown_content = ""
1263
-
1264
- try:
1265
- with Live(
1266
- Panel("", title="Response", border_style="green", expand=False),
1267
- refresh_per_second=4,
1268
- auto_refresh=True,
1269
- vertical_overflow="visible",
1270
- console=Console(force_terminal=True, color_system="auto", height=None)
1271
- ) as live:
1272
- for res in v:
1273
- markdown_content += res[0]
1274
- assistant_response += res[0]
1275
- if args.request_id:
1276
- request_queue.add_request(
1277
- args.request_id,
1278
- RequestValue(
1279
- value=StreamValue(value=[res[0]]),
1280
- status=RequestOption.RUNNING,
1281
- ),
1282
- )
1283
- live.update(
1284
- Panel(
1285
- Markdown(markdown_content),
1286
- title="Response",
1287
- border_style="green",
1288
- expand=False,
1289
- )
1290
- )
1291
- live.update(
1292
- Panel(
1293
- Markdown(markdown_content),
1294
- title="Response",
1295
- border_style="green",
1296
- expand=False,
1297
- )
1298
- )
1299
- except Exception as e:
1300
- ##MARK
1301
- console.print(Panel(
1302
- f"Error: {str(e)}",
1303
- title="Error",
1304
- border_style="red"
1305
- ))
1306
- request_queue.add_request(
1307
- args.request_id,
1308
- RequestValue(
1309
- value=StreamValue(value=[str(e)]), status=RequestOption.FAILED
1310
- ),
1311
- )
1312
- finally:
1313
- request_queue.add_request(
1314
- args.request_id,
1315
- RequestValue(
1316
- value=StreamValue(value=[""]), status=RequestOption.COMPLETED
1317
- ),
1261
+
1262
+ assistant_response, last_meta = stream_out(
1263
+ v,
1264
+ request_id=args.request_id,
1265
+ console=console
1318
1266
  )
1319
1267
 
1320
1268
  chat_history["ask_conversation"].append(
@@ -2173,7 +2173,8 @@ def manage_models(params, query: str):
2173
2173
  "model_name": data_dict.get("model_name", data_dict["name"]),
2174
2174
  "base_url": data_dict.get("base_url", "https://api.openai.com/v1"),
2175
2175
  "api_key_path": data_dict.get("api_key_path", "api.openai.com"),
2176
- "description": data_dict.get("description", "")
2176
+ "description": data_dict.get("description", ""),
2177
+ "is_reasoning": data_dict.get("is_reasoning", "false") in ["true", "True", "TRUE", "1"]
2177
2178
  }
2178
2179
 
2179
2180
  models_data.append(final_model)
@@ -2476,6 +2477,9 @@ def lib_command(args: List[str]):
2476
2477
  else:
2477
2478
  console.print(f"Unknown subcommand: {subcommand}")
2478
2479
 
2480
+ def agent(query: str):
2481
+ console.print(f"Agent query: {query}")
2482
+
2479
2483
 
2480
2484
  def main():
2481
2485
  ARGS = parse_arguments()
@@ -2650,14 +2654,20 @@ def main():
2650
2654
  if not query:
2651
2655
  print("Please enter your query.")
2652
2656
  else:
2653
- manage_models(ARGS,query)
2657
+ manage_models(ARGS,query)
2658
+ elif user_input.startswith("/agent"):
2659
+ query = user_input[len("/agent"):].strip()
2660
+ if not query:
2661
+ print("Please enter your query.")
2662
+ else:
2663
+ agent(query)
2654
2664
 
2655
2665
  elif user_input.startswith("/mode"):
2656
2666
  conf = user_input[len("/mode"):].strip()
2657
2667
  if not conf:
2658
2668
  print(memory["mode"])
2659
2669
  else:
2660
- memory["mode"] = conf
2670
+ memory["mode"] = conf
2661
2671
 
2662
2672
  elif user_input.startswith("/conf"):
2663
2673
  conf = user_input[len("/conf"):].strip()
@@ -9,6 +9,7 @@ from loguru import logger
9
9
  from autocoder.common.types import CodeGenerateResult, MergeCodeWithoutEffect
10
10
  from autocoder.common.code_modification_ranker import CodeModificationRanker
11
11
  import hashlib
12
+ from autocoder.common import files as FileUtils
12
13
 
13
14
  class PathAndCode(pydantic.BaseModel):
14
15
  path: str
@@ -135,8 +136,7 @@ class CodeAutoMerge:
135
136
  file_content_mapping[file_path] = block.content
136
137
  else:
137
138
  if file_path not in file_content_mapping:
138
- with open(file_path, "r") as f:
139
- file_content_mapping[file_path] = f.read()
139
+ file_content_mapping[file_path] = FileUtils.read_file(file_path)
140
140
  if file_content_mapping[file_path] != block.content:
141
141
  file_content_mapping[file_path] = block.content
142
142
  else:
@@ -150,7 +150,7 @@ class CodeAutoMerge:
150
150
  def _merge_code(self, content: str,force_skip_git:bool=False):
151
151
  total = 0
152
152
 
153
- file_content = open(self.args.file).read()
153
+ file_content = FileUtils.read_file(self.args.file)
154
154
  md5 = hashlib.md5(file_content.encode('utf-8')).hexdigest()
155
155
  # get the file name
156
156
  file_name = os.path.basename(self.args.file)
@@ -17,6 +17,7 @@ from autocoder.common.search_replace import (
17
17
  )
18
18
  from autocoder.common.types import CodeGenerateResult, MergeCodeWithoutEffect
19
19
  from autocoder.common.code_modification_ranker import CodeModificationRanker
20
+ from autocoder.common import files as FileUtils
20
21
 
21
22
  class PathAndCode(pydantic.BaseModel):
22
23
  path: str
@@ -438,8 +439,7 @@ class CodeAutoMergeDiff:
438
439
  errors = []
439
440
  for path, hunk in uniq:
440
441
  full_path = self.abs_root_path(path)
441
- with open(full_path) as f:
442
- content = f.read()
442
+ content = FileUtils.read_file(full_path)
443
443
 
444
444
  original, _ = hunk_to_before_after(hunk)
445
445
 
@@ -488,8 +488,7 @@ class CodeAutoMergeDiff:
488
488
  continue
489
489
 
490
490
  if full_path not in file_content_mapping:
491
- with open(full_path, "r") as f:
492
- file_content_mapping[full_path] = f.read()
491
+ file_content_mapping[full_path] = FileUtils.read_file(full_path)
493
492
 
494
493
  content = file_content_mapping[full_path]
495
494
  new_content = do_replace(full_path, content, hunk)
@@ -20,7 +20,7 @@ import json
20
20
  from typing import Union, List, Tuple
21
21
  from autocoder.common.types import CodeGenerateResult, MergeCodeWithoutEffect
22
22
  from autocoder.common.code_modification_ranker import CodeModificationRanker
23
-
23
+ from autocoder.common import files as FileUtils
24
24
 
25
25
  class PathAndCode(pydantic.BaseModel):
26
26
  path: str
@@ -235,9 +235,7 @@ class CodeAutoMergeEditBlock:
235
235
  file_content_mapping[file_path] = update
236
236
  else:
237
237
  if file_path not in file_content_mapping:
238
- with open(file_path, "r") as f:
239
- temp = f.read()
240
- file_content_mapping[file_path] = temp
238
+ file_content_mapping[file_path] = FileUtils.read_file(file_path)
241
239
  existing_content = file_content_mapping[file_path]
242
240
 
243
241
  # First try exact match
@@ -290,9 +288,7 @@ class CodeAutoMergeEditBlock:
290
288
  changes_made = True
291
289
  else:
292
290
  if file_path not in file_content_mapping:
293
- with open(file_path, "r") as f:
294
- temp = f.read()
295
- file_content_mapping[file_path] = temp
291
+ file_content_mapping[file_path] = FileUtils.read_file(file_path)
296
292
  existing_content = file_content_mapping[file_path]
297
293
  new_content = (
298
294
  existing_content.replace(head, update, 1)
@@ -0,0 +1,26 @@
1
+ def read_file(file_path):
2
+ """Read a file with automatic encoding detection.
3
+
4
+ Tries common encodings in sequence (UTF-8 > GBK > UTF-16 > Latin-1) to handle
5
+ cross-platform encoding issues between Windows and Linux systems.
6
+
7
+ Args:
8
+ file_path (str): Path to the file to read
9
+
10
+ Returns:
11
+ str: The file contents as a string
12
+
13
+ Raises:
14
+ ValueError: If the file cannot be decoded with any of the tried encodings
15
+ """
16
+ encodings = ['utf-8', 'gbk', 'utf-16', 'latin-1']
17
+
18
+ for encoding in encodings:
19
+ try:
20
+ with open(file_path, 'r', encoding=encoding) as f:
21
+ content = f.read()
22
+ return content
23
+ except UnicodeDecodeError:
24
+ continue
25
+
26
+ raise ValueError(f"无法解码文件: {file_path}。尝试的编码: {', '.join(encodings)}")
autocoder/models.py CHANGED
@@ -13,15 +13,17 @@ default_models_list = [
13
13
  "model_name": "deepseek-reasoner",
14
14
  "model_type": "saas/openai",
15
15
  "base_url": "https://api.deepseek.com/v1",
16
- "api_key_path": "api.deepseek.com"
16
+ "api_key_path": "api.deepseek.com",
17
+ "is_reasoning": True
17
18
  },
18
19
  {
19
- "name": "deepsee_chat",
20
+ "name": "deepseek_chat",
20
21
  "description": "DeepSeek Chat is for coding",
21
22
  "model_name": "deepseek-chat",
22
23
  "model_type": "saas/openai",
23
24
  "base_url": "https://api.deepseek.com/v1",
24
- "api_key_path": "api.deepseek.com"
25
+ "api_key_path": "api.deepseek.com",
26
+ "is_reasoning": False
25
27
  },
26
28
  {
27
29
  "name":"o1",
@@ -29,7 +31,8 @@ default_models_list = [
29
31
  "model_name": "o1-2024-12-17",
30
32
  "model_type": "saas/openai",
31
33
  "base_url": "https://api.openai.com/v1",
32
- "api_key_path": ""
34
+ "api_key_path": "",
35
+ "is_reasoning": False
33
36
  }
34
37
  ]
35
38
 
@@ -123,7 +126,7 @@ def update_model_with_api_key(name: str, api_key: str) -> Dict:
123
126
  # 在现有模型中查找
124
127
  found_model = None
125
128
  for model in models:
126
- if model["name"] == name:
129
+ if model["name"] == name.strip():
127
130
  found_model = model
128
131
  break
129
132
 
@@ -140,7 +143,7 @@ def update_model_with_api_key(name: str, api_key: str) -> Dict:
140
143
  os.makedirs(api_key_dir, exist_ok=True)
141
144
  api_key_file = os.path.join(api_key_dir, api_key_path)
142
145
  with open(api_key_file, "w") as f:
143
- f.write(api_key)
146
+ f.write(api_key.strip())
144
147
 
145
148
  # 如果是新模型,添加到模型列表中
146
149
  if all(model["name"] != name for model in models):
@@ -17,7 +17,7 @@ from pydantic import BaseModel, Field
17
17
  from rich.console import Console
18
18
  import json
19
19
  from autocoder.utils.queue_communicate import queue_communicate, CommunicateEvent, CommunicateEventType
20
-
20
+ from autocoder.common import files as FileUtils
21
21
 
22
22
  class RegPattern(BaseModel):
23
23
  pattern: str = Field(
@@ -35,9 +35,8 @@ class Level1PyProject:
35
35
 
36
36
  def get_imports_from_script(self, file_path):
37
37
  script = ""
38
- with open(file_path, "r") as file:
39
- script = file.read()
40
- tree = ast.parse(script, filename=file_path)
38
+ script = FileUtils.read_file(file_path)
39
+ tree = ast.parse(script, filename=file_path)
41
40
 
42
41
  imports = [
43
42
  node
@@ -61,8 +60,7 @@ class Level1PyProject:
61
60
  def fetch_source_code(self, import_name):
62
61
  spec = importlib.util.find_spec(import_name)
63
62
  if spec and spec.origin:
64
- with open(spec.origin, "r") as file:
65
- return file.read()
63
+ return FileUtils.read_file(spec.origin)
66
64
  return None
67
65
 
68
66
  @byzerllm.prompt(render="jinja")
@@ -188,8 +186,7 @@ class PyProject:
188
186
  result.append(f"{line_number}:{line}")
189
187
  return "\n".join(result)
190
188
 
191
- with open(file_path, "r") as file:
192
- return file.read()
189
+ return FileUtils.read_file(file_path)
193
190
 
194
191
  def convert_to_source_code(self, file_path):
195
192
  module_name = file_path
@@ -12,7 +12,7 @@ from pydantic import BaseModel, Field
12
12
  from rich.console import Console
13
13
  import json
14
14
  from autocoder.utils.queue_communicate import queue_communicate, CommunicateEvent, CommunicateEventType
15
-
15
+ from autocoder.common import files as FileUtils
16
16
 
17
17
  class RegPattern(BaseModel):
18
18
  pattern: str = Field(
@@ -84,8 +84,7 @@ class RegexProject:
84
84
  return re.search(self.regex_pattern, file_path) is not None
85
85
 
86
86
  def read_file_content(self, file_path):
87
- with open(file_path, "r") as file:
88
- return file.read()
87
+ return FileUtils.read_file(file_path)
89
88
 
90
89
  def convert_to_source_code(self, file_path):
91
90
  module_name = file_path
@@ -12,7 +12,7 @@ from pydantic import BaseModel, Field
12
12
  from rich.console import Console
13
13
  import json
14
14
  from autocoder.utils.queue_communicate import queue_communicate, CommunicateEvent, CommunicateEventType
15
-
15
+ from autocoder.common import files as FileUtils
16
16
 
17
17
  class RegPattern(BaseModel):
18
18
  pattern: str = Field(
@@ -120,8 +120,7 @@ class SuffixProject:
120
120
  return any([file_path.endswith(suffix) for suffix in self.suffixs])
121
121
 
122
122
  def read_file_content(self, file_path):
123
- with open(file_path, "r") as file:
124
- return file.read()
123
+ return FileUtils.read_file(file_path)
125
124
 
126
125
  def convert_to_source_code(self, file_path):
127
126
  module_name = file_path
@@ -14,6 +14,7 @@ from pydantic import BaseModel, Field
14
14
  from rich.console import Console
15
15
  import json
16
16
  from autocoder.utils.queue_communicate import queue_communicate, CommunicateEvent, CommunicateEventType
17
+ from autocoder.common import files as FileUtils
17
18
 
18
19
 
19
20
  class RegPattern(BaseModel):
@@ -107,8 +108,7 @@ class TSProject:
107
108
  return open(self.target_file, "r").read()
108
109
 
109
110
  def read_file_content(self, file_path):
110
- with open(file_path, "r") as file:
111
- return file.read()
111
+ return FileUtils.read_file(file_path)
112
112
 
113
113
  def is_likely_useful_file(self, file_path):
114
114
  # Ignore common build output, dependency and configuration directories
File without changes
@@ -0,0 +1,120 @@
1
+ from rich.console import Console
2
+ from rich.live import Live
3
+ from rich.panel import Panel
4
+ from rich.markdown import Markdown
5
+ from typing import Generator, List, Dict, Any, Optional, Tuple
6
+ from autocoder.utils.request_queue import RequestValue, RequestOption, StreamValue
7
+ from autocoder.utils.request_queue import request_queue
8
+
9
+ MAX_HISTORY_LINES = 40 # 最大保留历史行数
10
+
11
+ def stream_out(
12
+ stream_generator: Generator[Tuple[str, Dict[str, Any]], None, None],
13
+ request_id: Optional[str] = None,
14
+ console: Optional[Console] = None
15
+ ) -> Tuple[str, Optional[Dict[str, Any]]]:
16
+ """
17
+ 处理流式输出事件并在终端中展示
18
+
19
+ Args:
20
+ stream_generator: 生成流式输出的生成器
21
+ request_id: 请求ID,用于更新请求队列
22
+ console: Rich Console对象
23
+
24
+ Returns:
25
+ Tuple[str, Dict[str, Any]]: 返回完整的响应内容和最后的元数据
26
+ """
27
+ if console is None:
28
+ console = Console(force_terminal=True, color_system="auto", height=None)
29
+
30
+ lines_buffer = [] # 存储历史行
31
+ current_line = "" # 当前行
32
+ assistant_response = ""
33
+ last_meta = None
34
+
35
+ try:
36
+ with Live(
37
+ Panel("", title="Response", border_style="green"),
38
+ refresh_per_second=4,
39
+ console=console
40
+ ) as live:
41
+ for res in stream_generator:
42
+ last_meta = res[1]
43
+ content = res[0]
44
+ assistant_response += content
45
+
46
+ # 处理所有行
47
+ parts = (current_line + content).split("\n")
48
+
49
+ # 最后一部分是未完成的新行
50
+ if len(parts) > 1:
51
+ # 将完整行加入缓冲区
52
+ lines_buffer.extend(parts[:-1])
53
+ # 保留最大行数限制
54
+ if len(lines_buffer) > MAX_HISTORY_LINES:
55
+ del lines_buffer[0:len(lines_buffer) - MAX_HISTORY_LINES]
56
+
57
+ # 更新当前行
58
+ current_line = parts[-1]
59
+
60
+ # 构建显示内容 = 历史行 + 当前行
61
+ display_content = "\n".join(lines_buffer[-MAX_HISTORY_LINES:] + [current_line])
62
+
63
+ if request_id and request_queue:
64
+ request_queue.add_request(
65
+ request_id,
66
+ RequestValue(
67
+ value=StreamValue(value=[content]),
68
+ status=RequestOption.RUNNING,
69
+ ),
70
+ )
71
+
72
+ live.update(
73
+ Panel(
74
+ Markdown(display_content),
75
+ title="Response",
76
+ border_style="green",
77
+ height=min(50, live.console.height - 4)
78
+ )
79
+ )
80
+
81
+ # 处理最后一行的内容
82
+ if current_line:
83
+ lines_buffer.append(current_line)
84
+
85
+ # 最终显示结果
86
+ live.update(
87
+ Panel(
88
+ Markdown(assistant_response),
89
+ title="Final Response",
90
+ border_style="blue"
91
+ )
92
+ )
93
+
94
+ except Exception as e:
95
+ console.print(Panel(
96
+ f"Error: {str(e)}",
97
+ title="Error",
98
+ border_style="red"
99
+ ))
100
+
101
+ if request_id and request_queue:
102
+ request_queue.add_request(
103
+ request_id,
104
+ RequestValue(
105
+ value=StreamValue(value=[str(e)]),
106
+ status=RequestOption.FAILED
107
+ ),
108
+ )
109
+
110
+ finally:
111
+ if request_id and request_queue:
112
+ request_queue.add_request(
113
+ request_id,
114
+ RequestValue(
115
+ value=StreamValue(value=[""]),
116
+ status=RequestOption.COMPLETED
117
+ ),
118
+ )
119
+
120
+ return assistant_response, last_meta
autocoder/utils/rest.py CHANGED
@@ -7,6 +7,7 @@ from bs4 import BeautifulSoup
7
7
  from loguru import logger
8
8
  import os
9
9
  from pathlib import Path
10
+ from autocoder.common import files as FileUtils
10
11
 
11
12
  class HttpDoc:
12
13
  def __init__(self, args, llm: byzerllm.ByzerLLM,urls:Optional[List[str]]=None):
@@ -112,7 +113,7 @@ class HttpDoc:
112
113
  return temp_documents
113
114
 
114
115
  if ext not in exts.keys():
115
- main_content = open(file_path, "r").read()
116
+ main_content = FileUtils.read_file(file_path)
116
117
  source_code = SourceCode(module_name=file_path, source_code=main_content)
117
118
  source_codes.append(source_code)
118
119
  else:
@@ -135,7 +136,7 @@ class HttpDoc:
135
136
 
136
137
  except ImportError as e:
137
138
  logger.warning(f"Failed to import llama_index. Please install it using 'pip install llama_index' {e}")
138
- main_content = open(url, "r").read()
139
+ main_content = FileUtils.read_file(url)
139
140
  source_code = SourceCode(module_name=url, source_code=main_content)
140
141
  source_codes.append(source_code)
141
142
  else:
autocoder/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.227"
1
+ __version__ = "0.1.229"