auto-coder 0.1.382__py3-none-any.whl → 0.1.384__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.382
3
+ Version: 0.1.384
4
4
  Summary: AutoCoder: AutoCoder
5
5
  Author: allwefantasy
6
6
  Classifier: Programming Language :: Python :: 3.10
@@ -1,7 +1,7 @@
1
1
  autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  autocoder/auto_coder.py,sha256=7602L3tG0JErNxh8vkLAmGUgv2c-DGPzPCkmWIQt9bs,69757
3
3
  autocoder/auto_coder_rag.py,sha256=tRAKfo3jIhcaQKN_3g7DZRKtDJSZXJxMRdT6Zz8W9nw,41173
4
- autocoder/auto_coder_runner.py,sha256=VktQIEWjVMmraVjD7W73eZmYtdfm9Ma2w_Ib-cWZYhM,112263
4
+ autocoder/auto_coder_runner.py,sha256=NhT1fVdV4NnV2SwpXl7G-tTKgduA0D-0lK_p2R6DWew,115569
5
5
  autocoder/auto_coder_server.py,sha256=bLORGEclcVdbBVfM140JCI8WtdrU0jbgqdJIVVupiEU,20578
6
6
  autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
7
7
  autocoder/chat_auto_coder.py,sha256=vNQwbYkdqeMl07Vx8z6x-kSPkHKn9AT3sSkYMTJiWtc,26655
@@ -11,7 +11,7 @@ autocoder/command_parser.py,sha256=fx1g9E6GaM273lGTcJqaFQ-hoksS_Ik2glBMnVltPCE,1
11
11
  autocoder/lang.py,sha256=PFtATuOhHRnfpqHQkXr6p4C893JvpsgwTMif3l-GEi0,14321
12
12
  autocoder/models.py,sha256=pD5u6gcMKRwWaLxeVin18g25k-ERyeHOFsRpOgO_Ae0,13788
13
13
  autocoder/run_context.py,sha256=IUfSO6_gp2Wt1blFWAmOpN0b0nDrTTk4LmtCYUBIoro,1643
14
- autocoder/version.py,sha256=WsLgumnTuWnjn9FpRrgmPyKJQyLwiu2BVqZ5GJpgbT0,25
14
+ autocoder/version.py,sha256=GKXrGNop64hmj7p85hlLkViSFSxh9tQvQZ4yEDTAuu4,25
15
15
  autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  autocoder/agent/agentic_filter.py,sha256=zlInIRhawKIYTJjCiJBWqPCOV5UtMbh5VnvszfTy2vo,39824
17
17
  autocoder/agent/auto_demand_organizer.py,sha256=URAq0gSEiHeV_W4zwhOI_83kHz0Ryfj1gcfh5jwCv_w,6501
@@ -97,6 +97,9 @@ autocoder/common/global_cancel.py,sha256=EYMIzdIJHQjoYP4grxhBxSIT3tCJOy3ESULNd-c
97
97
  autocoder/common/image_to_page.py,sha256=yWiTJQ49Lm3j0FngiJhQ9u7qayqE_bOGb8Rk0TmSWx0,14123
98
98
  autocoder/common/index_import_export.py,sha256=h758AYY1df6JMTKUXYmMkSgxItfymDt82XT7O-ygEuw,4565
99
99
  autocoder/common/interpreter.py,sha256=62-dIakOunYB4yjmX8SHC0Gdy2h8NtxdgbpdqRZJ5vk,2833
100
+ autocoder/common/llm_friendly_package.py,sha256=j44Wqco8-5sA2Yz05ZEidA1HwTbVGnbevbALCoasTtM,14760
101
+ autocoder/common/llm_friendly_package_example.py,sha256=NXUiz6j7gpfzExC-2jmppnZaZaTuu4oGMCDneV7FC_k,4647
102
+ autocoder/common/llm_friendly_package_test.py,sha256=FhbzdNPEceuEBIxNvek2OYDFVlJlYJpkskZ7_PB4YSg,1930
100
103
  autocoder/common/mcp_hub.py,sha256=grf51bZbZDXQIqlruIxXZjfat8MoVwK7NvHTHMaxKrg,23614
101
104
  autocoder/common/mcp_server.py,sha256=Aj6snmB4XXEcLpcm7SC-KBbNLOlEmiNW6hFtMLltpt8,17624
102
105
  autocoder/common/mcp_server_install.py,sha256=vQOWWZsl6MZ2qz3b7Y2zctKOEGO69Ph2Nrof4p_1SOg,11599
@@ -172,7 +175,7 @@ autocoder/common/v2/code_editblock_manager.py,sha256=DMwJw-FAM6VyaBQV3p4xespHpgZ
172
175
  autocoder/common/v2/code_manager.py,sha256=C403bS-f6urixwitlKHcml-J03hci-UyNwHJOqBiY6Q,9182
173
176
  autocoder/common/v2/code_strict_diff_manager.py,sha256=Bys7tFAq4G03R1zUZuxrszBTvP4QB96jIw2y5BDLyRM,9424
174
177
  autocoder/common/v2/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
175
- autocoder/common/v2/agent/agentic_edit.py,sha256=aPYUhDyLPALIHzULCHnVSoDc6x2vcrAFXBknxc8k_lg,112210
178
+ autocoder/common/v2/agent/agentic_edit.py,sha256=f9GxvaOvgirxyPCEiGxFi7u8X4ZB3do72PGldxCzpAI,115291
176
179
  autocoder/common/v2/agent/agentic_edit_types.py,sha256=nEcZc2MOZ_fQLaJX-YDha_x9Iim22ao4tykYM2iIy4k,4908
177
180
  autocoder/common/v2/agent/agentic_tool_display.py,sha256=-a-JTQLc4q03E_rdIILKMI0B6DHN-5gcGlrqq-mBYK4,7239
178
181
  autocoder/common/v2/agent/agentic_edit_tools/__init__.py,sha256=RbPZZcZg_VnGssL577GxSyFrYrxQ_LopJ4G_-mY3z_Q,1337
@@ -320,7 +323,7 @@ autocoder/utils/llms.py,sha256=CQRNsX8SJBpeHl_zJ1N-Nj-MYyqkFCi3zETYSurCMkU,4021
320
323
  autocoder/utils/log_capture.py,sha256=I-bsJFLWoGUiX-GKoZsH9kWJCKSV7ZlUnRt7jh-fOL0,1548
321
324
  autocoder/utils/model_provider_selector.py,sha256=JTYy6GLaqnGoqsumjRNXmQuwy9nDqiTSZlGQ9zkfdK0,8102
322
325
  autocoder/utils/multi_turn.py,sha256=unK9OpqVRbK6uIcTKXgggX2wNmyj7s5eyEAQ2xUwHoM,88
323
- autocoder/utils/operate_config_api.py,sha256=K1lQxXNHiAYTgRDS2EGpWmjdJTrQaeP16RUWS0DIorw,5841
326
+ autocoder/utils/operate_config_api.py,sha256=j9Ika5bbAGSQbFziREwISmp8BQ54m_eigEa5jwdG64Q,4530
324
327
  autocoder/utils/print_table.py,sha256=ZMRhCA9DD0FUfKyJBWd5bDdj1RrtPtgOMWSJwtvZcLs,403
325
328
  autocoder/utils/project_structure.py,sha256=KnRWtGsJSmZrEV5aOOjv120vvBkZ1UZtDTnWkzpMmKI,11426
326
329
  autocoder/utils/queue_communicate.py,sha256=buyEzdvab1QA4i2QKbq35rG5v_9x9PWVLWWMTznWcYM,6832
@@ -333,9 +336,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
333
336
  autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
334
337
  autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=t902pKxQ5xM7zgIHiAOsTPLwxhE6VuvXAqPy751S7fg,14096
335
338
  autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
336
- auto_coder-0.1.382.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
337
- auto_coder-0.1.382.dist-info/METADATA,sha256=PVXxhMLwdBO7U8UTU5jHi6gAsMUOoETYAsWTeWNvldI,2796
338
- auto_coder-0.1.382.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
339
- auto_coder-0.1.382.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
340
- auto_coder-0.1.382.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
341
- auto_coder-0.1.382.dist-info/RECORD,,
339
+ auto_coder-0.1.384.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
340
+ auto_coder-0.1.384.dist-info/METADATA,sha256=rPHocW41diQxO73kihXrTOfC8r9HBwK07EUF5X_F960,2796
341
+ auto_coder-0.1.384.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
342
+ auto_coder-0.1.384.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
343
+ auto_coder-0.1.384.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
344
+ auto_coder-0.1.384.dist-info/RECORD,,
@@ -657,6 +657,16 @@ def save_memory():
657
657
  load_memory()
658
658
 
659
659
 
660
+ def save_memory_with_new_memory(new_memory):
661
+ memory_path = os.path.join(base_persist_dir, "memory.json")
662
+ lock_path = memory_path + ".lock"
663
+
664
+ with FileLock(lock_path, timeout=30):
665
+ with open(memory_path, "w", encoding="utf-8") as f:
666
+ json.dump(new_memory, f, indent=2, ensure_ascii=False)
667
+ load_memory()
668
+
669
+
660
670
  def load_memory():
661
671
  global memory
662
672
  memory_path = os.path.join(base_persist_dir, "memory.json")
@@ -2653,7 +2663,7 @@ def lib_command(args: List[str]):
2653
2663
 
2654
2664
  if not args:
2655
2665
  console.print(
2656
- "Please specify a subcommand: /add, /remove, /list, /set-proxy, /refresh, or /get"
2666
+ "Please specify a subcommand: /add, /remove, /list, /list_all, /set-proxy, /refresh, or /get"
2657
2667
  )
2658
2668
  return
2659
2669
 
@@ -2710,6 +2720,66 @@ def lib_command(args: List[str]):
2710
2720
  console.print(table)
2711
2721
  else:
2712
2722
  console.print("No libraries added yet")
2723
+
2724
+ elif subcommand == "/list_all":
2725
+ if not os.path.exists(llm_friendly_packages_dir):
2726
+ console.print("llm_friendly_packages repository does not exist. Please run /lib /add <library_name> command first to clone it.")
2727
+ return
2728
+
2729
+ available_libs = []
2730
+
2731
+ # 遍历所有domain目录
2732
+ for domain in os.listdir(llm_friendly_packages_dir):
2733
+ domain_path = os.path.join(llm_friendly_packages_dir, domain)
2734
+ if os.path.isdir(domain_path):
2735
+ # 遍历所有username目录
2736
+ for username in os.listdir(domain_path):
2737
+ username_path = os.path.join(domain_path, username)
2738
+ if os.path.isdir(username_path):
2739
+ # 遍历所有lib_name目录
2740
+ for lib_name in os.listdir(username_path):
2741
+ lib_path = os.path.join(username_path, lib_name)
2742
+ if os.path.isdir(lib_path):
2743
+ # 检查是否有Markdown文件
2744
+ has_md_files = False
2745
+ for root, _, files in os.walk(lib_path):
2746
+ if any(file.endswith('.md') for file in files):
2747
+ has_md_files = True
2748
+ break
2749
+
2750
+ if has_md_files:
2751
+ available_libs.append({
2752
+ "domain": domain,
2753
+ "username": username,
2754
+ "lib_name": lib_name,
2755
+ "full_path": f"{username}/{lib_name}",
2756
+ "is_added": lib_name in memory["libs"]
2757
+ })
2758
+
2759
+ if available_libs:
2760
+ table = Table(title="Available Libraries")
2761
+ table.add_column("Domain", style="blue")
2762
+ table.add_column("Username", style="green")
2763
+ table.add_column("Library Name", style="cyan")
2764
+ table.add_column("Full Path", style="magenta")
2765
+ table.add_column("Status", style="yellow")
2766
+
2767
+ # 按domain和username分组排序
2768
+ available_libs.sort(key=lambda x: (x["domain"], x["username"], x["lib_name"]))
2769
+
2770
+ for lib in available_libs:
2771
+ status = "[green]Added[/green]" if lib["is_added"] else "[white]Not Added[/white]"
2772
+ table.add_row(
2773
+ lib["domain"],
2774
+ lib["username"],
2775
+ lib["lib_name"],
2776
+ lib["full_path"],
2777
+ status
2778
+ )
2779
+
2780
+ console.print(table)
2781
+ else:
2782
+ console.print("No available libraries found in the repository.")
2713
2783
 
2714
2784
  elif subcommand == "/set-proxy":
2715
2785
  if len(args) == 1:
@@ -0,0 +1,410 @@
1
+ """
2
+ LLM Friendly Package Manager
3
+
4
+ This module provides a class-based interface for managing LLM friendly packages,
5
+ including operations like get, list, list_all, add, remove, refresh, etc.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ from typing import List, Dict, Any, Optional, Tuple
11
+ from dataclasses import dataclass
12
+ from rich.console import Console
13
+ from rich.table import Table
14
+ import git
15
+ from filelock import FileLock
16
+
17
+
18
+ @dataclass
19
+ class LibraryInfo:
20
+ """Information about a library"""
21
+ domain: str
22
+ username: str
23
+ lib_name: str
24
+ full_path: str
25
+ is_added: bool
26
+ has_md_files: bool = True
27
+
28
+
29
+ @dataclass
30
+ class PackageDoc:
31
+ """Package documentation information"""
32
+ file_path: str
33
+ content: Optional[str] = None
34
+
35
+
36
+ class LLMFriendlyPackageManager:
37
+ """Manager for LLM friendly packages"""
38
+
39
+ def __init__(self, project_root: str = None, base_persist_dir: str = None):
40
+ """
41
+ Initialize the package manager
42
+
43
+ Args:
44
+ project_root: Project root directory, defaults to current working directory
45
+ base_persist_dir: Base directory for persistence, defaults to .auto-coder/plugins/chat-auto-coder
46
+ """
47
+ self.project_root = project_root or os.getcwd()
48
+ self.base_persist_dir = base_persist_dir or os.path.join(
49
+ self.project_root, ".auto-coder", "plugins", "chat-auto-coder"
50
+ )
51
+ self.lib_dir = os.path.join(self.project_root, ".auto-coder", "libs")
52
+ self.llm_friendly_packages_dir = os.path.join(self.lib_dir, "llm_friendly_packages")
53
+ self.console = Console()
54
+
55
+ # Ensure directories exist
56
+ os.makedirs(self.lib_dir, exist_ok=True)
57
+ os.makedirs(self.base_persist_dir, exist_ok=True)
58
+
59
+ def _get_memory_path(self) -> str:
60
+ """Get memory file path"""
61
+ return os.path.join(self.base_persist_dir, "memory.json")
62
+
63
+ def _load_memory(self) -> Dict[str, Any]:
64
+ """Load memory from file"""
65
+ memory_path = self._get_memory_path()
66
+ lock_path = memory_path + ".lock"
67
+
68
+ default_memory = {
69
+ "conversation": [],
70
+ "current_files": {"files": [], "groups": {}},
71
+ "conf": {},
72
+ "exclude_dirs": [],
73
+ "mode": "auto_detect",
74
+ "libs": {}
75
+ }
76
+
77
+ if not os.path.exists(memory_path):
78
+ return default_memory
79
+
80
+ try:
81
+ with FileLock(lock_path, timeout=30):
82
+ with open(memory_path, "r", encoding="utf-8") as f:
83
+ memory = json.load(f)
84
+ # Ensure libs key exists
85
+ if "libs" not in memory:
86
+ memory["libs"] = {}
87
+ return memory
88
+ except Exception:
89
+ return default_memory
90
+
91
+ def _save_memory(self, memory: Dict[str, Any]) -> None:
92
+ """Save memory to file"""
93
+ memory_path = self._get_memory_path()
94
+ lock_path = memory_path + ".lock"
95
+
96
+ with FileLock(lock_path, timeout=30):
97
+ with open(memory_path, "w", encoding="utf-8") as f:
98
+ json.dump(memory, f, indent=2, ensure_ascii=False)
99
+
100
+ def _get_current_proxy(self) -> str:
101
+ """Get current proxy URL"""
102
+ memory = self._load_memory()
103
+ return memory.get("lib-proxy", "https://github.com/allwefantasy/llm_friendly_packages")
104
+
105
+ def _clone_repository(self) -> bool:
106
+ """Clone the llm_friendly_packages repository"""
107
+ if os.path.exists(self.llm_friendly_packages_dir):
108
+ return True
109
+
110
+ self.console.print("Cloning llm_friendly_packages repository...")
111
+ try:
112
+ proxy_url = self._get_current_proxy()
113
+ git.Repo.clone_from(proxy_url, self.llm_friendly_packages_dir)
114
+ self.console.print("Successfully cloned llm_friendly_packages repository")
115
+ return True
116
+ except git.exc.GitCommandError as e:
117
+ self.console.print(f"Error cloning repository: {e}")
118
+ return False
119
+
120
+ def get_docs(self, package_name: Optional[str] = None, return_paths: bool = False) -> List[str]:
121
+ """
122
+ Get documentation for packages
123
+
124
+ Args:
125
+ package_name: Specific package name to get docs for, None for all packages
126
+ return_paths: If True, return file paths; if False, return file contents
127
+
128
+ Returns:
129
+ List of documentation content or file paths
130
+ """
131
+ docs = []
132
+
133
+ if not os.path.exists(self.llm_friendly_packages_dir):
134
+ return docs
135
+
136
+ memory = self._load_memory()
137
+ libs = list(memory.get("libs", {}).keys())
138
+
139
+ for domain in os.listdir(self.llm_friendly_packages_dir):
140
+ domain_path = os.path.join(self.llm_friendly_packages_dir, domain)
141
+ if not os.path.isdir(domain_path):
142
+ continue
143
+
144
+ for username in os.listdir(domain_path):
145
+ username_path = os.path.join(domain_path, username)
146
+ if not os.path.isdir(username_path):
147
+ continue
148
+
149
+ for lib_name in os.listdir(username_path):
150
+ lib_path = os.path.join(username_path, lib_name)
151
+
152
+ # Check if this is the requested package
153
+ if not os.path.isdir(lib_path):
154
+ continue
155
+
156
+ if package_name is not None:
157
+ if not (lib_name == package_name or
158
+ package_name == os.path.join(username, lib_name)):
159
+ continue
160
+
161
+ # Check if library is added
162
+ if lib_name not in libs:
163
+ continue
164
+
165
+ # Collect markdown files
166
+ for root, _, files in os.walk(lib_path):
167
+ for file in files:
168
+ if file.endswith(".md"):
169
+ file_path = os.path.join(root, file)
170
+ if return_paths:
171
+ docs.append(file_path)
172
+ else:
173
+ try:
174
+ with open(file_path, "r", encoding="utf-8") as f:
175
+ docs.append(f.read())
176
+ except Exception as e:
177
+ self.console.print(f"Error reading {file_path}: {e}")
178
+
179
+ return docs
180
+
181
+ def list_added_libraries(self) -> List[str]:
182
+ """List all added libraries"""
183
+ memory = self._load_memory()
184
+ return list(memory.get("libs", {}).keys())
185
+
186
+ def list_all_available_libraries(self) -> List[LibraryInfo]:
187
+ """List all available libraries in the repository"""
188
+ if not os.path.exists(self.llm_friendly_packages_dir):
189
+ return []
190
+
191
+ available_libs = []
192
+ memory = self._load_memory()
193
+ added_libs = set(memory.get("libs", {}).keys())
194
+
195
+ for domain in os.listdir(self.llm_friendly_packages_dir):
196
+ domain_path = os.path.join(self.llm_friendly_packages_dir, domain)
197
+ if not os.path.isdir(domain_path):
198
+ continue
199
+
200
+ for username in os.listdir(domain_path):
201
+ username_path = os.path.join(domain_path, username)
202
+ if not os.path.isdir(username_path):
203
+ continue
204
+
205
+ for lib_name in os.listdir(username_path):
206
+ lib_path = os.path.join(username_path, lib_name)
207
+ if not os.path.isdir(lib_path):
208
+ continue
209
+
210
+ # Check if has markdown files
211
+ has_md_files = False
212
+ for root, _, files in os.walk(lib_path):
213
+ if any(file.endswith('.md') for file in files):
214
+ has_md_files = True
215
+ break
216
+
217
+ if has_md_files:
218
+ available_libs.append(LibraryInfo(
219
+ domain=domain,
220
+ username=username,
221
+ lib_name=lib_name,
222
+ full_path=f"{username}/{lib_name}",
223
+ is_added=lib_name in added_libs,
224
+ has_md_files=has_md_files
225
+ ))
226
+
227
+ # Sort by domain, username, lib_name
228
+ available_libs.sort(key=lambda x: (x.domain, x.username, x.lib_name))
229
+ return available_libs
230
+
231
+ def add_library(self, lib_name: str) -> bool:
232
+ """
233
+ Add a library to the list
234
+
235
+ Args:
236
+ lib_name: Library name to add
237
+
238
+ Returns:
239
+ True if successful, False otherwise
240
+ """
241
+ # Clone repository if needed
242
+ if not self._clone_repository():
243
+ return False
244
+
245
+ memory = self._load_memory()
246
+
247
+ if lib_name in memory["libs"]:
248
+ self.console.print(f"Library {lib_name} is already added")
249
+ return False
250
+
251
+ memory["libs"][lib_name] = {}
252
+ self._save_memory(memory)
253
+ self.console.print(f"Added library: {lib_name}")
254
+ return True
255
+
256
+ def remove_library(self, lib_name: str) -> bool:
257
+ """
258
+ Remove a library from the list
259
+
260
+ Args:
261
+ lib_name: Library name to remove
262
+
263
+ Returns:
264
+ True if successful, False otherwise
265
+ """
266
+ memory = self._load_memory()
267
+
268
+ if lib_name not in memory["libs"]:
269
+ self.console.print(f"Library {lib_name} is not in the list")
270
+ return False
271
+
272
+ del memory["libs"][lib_name]
273
+ self._save_memory(memory)
274
+ self.console.print(f"Removed library: {lib_name}")
275
+ return True
276
+
277
+ def set_proxy(self, proxy_url: Optional[str] = None) -> str:
278
+ """
279
+ Set or get proxy URL
280
+
281
+ Args:
282
+ proxy_url: New proxy URL, None to get current proxy
283
+
284
+ Returns:
285
+ Current proxy URL
286
+ """
287
+ memory = self._load_memory()
288
+
289
+ if proxy_url is None:
290
+ current_proxy = memory.get("lib-proxy", "No proxy set")
291
+ self.console.print(f"Current proxy: {current_proxy}")
292
+ return current_proxy
293
+
294
+ memory["lib-proxy"] = proxy_url
295
+ self._save_memory(memory)
296
+ self.console.print(f"Set proxy to: {proxy_url}")
297
+ return proxy_url
298
+
299
+ def refresh_repository(self) -> bool:
300
+ """
301
+ Refresh the repository by pulling latest changes
302
+
303
+ Returns:
304
+ True if successful, False otherwise
305
+ """
306
+ if not os.path.exists(self.llm_friendly_packages_dir):
307
+ self.console.print(
308
+ "llm_friendly_packages repository does not exist. "
309
+ "Please run add_library() first to clone it."
310
+ )
311
+ return False
312
+
313
+ try:
314
+ repo = git.Repo(self.llm_friendly_packages_dir)
315
+ origin = repo.remotes.origin
316
+
317
+ # Update remote URL if proxy is set
318
+ memory = self._load_memory()
319
+ proxy_url = memory.get("lib-proxy")
320
+ current_url = origin.url
321
+
322
+ if proxy_url and proxy_url != current_url:
323
+ origin.set_url(proxy_url)
324
+ self.console.print(f"Updated remote URL to: {proxy_url}")
325
+
326
+ origin.pull()
327
+ self.console.print("Successfully updated llm_friendly_packages repository")
328
+ return True
329
+
330
+ except git.exc.GitCommandError as e:
331
+ self.console.print(f"Error updating repository: {e}")
332
+ return False
333
+
334
+ def get_library_docs_paths(self, package_name: str) -> List[str]:
335
+ """
336
+ Get documentation file paths for a specific package
337
+
338
+ Args:
339
+ package_name: Package name
340
+
341
+ Returns:
342
+ List of markdown file paths
343
+ """
344
+ return self.get_docs(package_name, return_paths=True)
345
+
346
+ def display_added_libraries(self) -> None:
347
+ """Display added libraries in a table"""
348
+ libs = self.list_added_libraries()
349
+
350
+ if not libs:
351
+ self.console.print("No libraries added yet")
352
+ return
353
+
354
+ table = Table(title="Added Libraries")
355
+ table.add_column("Library Name", style="cyan")
356
+
357
+ for lib_name in libs:
358
+ table.add_row(lib_name)
359
+
360
+ self.console.print(table)
361
+
362
+ def display_all_libraries(self) -> None:
363
+ """Display all available libraries in a table"""
364
+ if not os.path.exists(self.llm_friendly_packages_dir):
365
+ self.console.print(
366
+ "llm_friendly_packages repository does not exist. "
367
+ "Please call add_library() first to clone it."
368
+ )
369
+ return
370
+
371
+ available_libs = self.list_all_available_libraries()
372
+
373
+ if not available_libs:
374
+ self.console.print("No available libraries found in the repository.")
375
+ return
376
+
377
+ table = Table(title="Available Libraries")
378
+ table.add_column("Domain", style="blue")
379
+ table.add_column("Username", style="green")
380
+ table.add_column("Library Name", style="cyan")
381
+ table.add_column("Full Path", style="magenta")
382
+ table.add_column("Status", style="yellow")
383
+
384
+ for lib in available_libs:
385
+ status = "[green]Added[/green]" if lib.is_added else "[white]Not Added[/white]"
386
+ table.add_row(
387
+ lib.domain,
388
+ lib.username,
389
+ lib.lib_name,
390
+ lib.full_path,
391
+ status
392
+ )
393
+
394
+ self.console.print(table)
395
+
396
+ def display_library_docs(self, package_name: str) -> None:
397
+ """Display documentation paths for a package in a table"""
398
+ docs = self.get_library_docs_paths(package_name)
399
+
400
+ if not docs:
401
+ self.console.print(f"No markdown files found for package: {package_name}")
402
+ return
403
+
404
+ table = Table(title=f"Markdown Files for {package_name}")
405
+ table.add_column("File Path", style="cyan")
406
+
407
+ for doc in docs:
408
+ table.add_row(doc)
409
+
410
+ self.console.print(table)
@@ -0,0 +1,138 @@
1
+ """
2
+ LLMFriendlyPackageManager Usage Examples
3
+
4
+ This file demonstrates various ways to use the LLMFriendlyPackageManager class
5
+ for managing LLM friendly packages.
6
+ """
7
+
8
+ from autocoder.common.llm_friendly_package import LLMFriendlyPackageManager
9
+
10
+ def example_basic_usage():
11
+ """Basic usage example"""
12
+ print("=== Basic Usage Example ===")
13
+
14
+ # Initialize the manager
15
+ manager = LLMFriendlyPackageManager()
16
+
17
+ # List current added libraries
18
+ added_libs = manager.list_added_libraries()
19
+ print(f"Currently added libraries: {added_libs}")
20
+
21
+ # Display added libraries in a nice table
22
+ manager.display_added_libraries()
23
+
24
+ def example_library_management():
25
+ """Library management example"""
26
+ print("\n=== Library Management Example ===")
27
+
28
+ manager = LLMFriendlyPackageManager()
29
+
30
+ # Add a library (this will clone the repository if needed)
31
+ print("Adding a library...")
32
+ success = manager.add_library("example-lib")
33
+ if success:
34
+ print("Library added successfully!")
35
+
36
+ # List all available libraries
37
+ print("\nAll available libraries:")
38
+ manager.display_all_libraries()
39
+
40
+ # Remove a library
41
+ print("\nRemoving the library...")
42
+ removed = manager.remove_library("example-lib")
43
+ if removed:
44
+ print("Library removed successfully!")
45
+
46
+ def example_documentation_access():
47
+ """Documentation access example"""
48
+ print("\n=== Documentation Access Example ===")
49
+
50
+ manager = LLMFriendlyPackageManager()
51
+
52
+ # Get documentation content for all packages
53
+ docs_content = manager.get_docs()
54
+ print(f"Total documentation content items: {len(docs_content)}")
55
+
56
+ # Get documentation file paths for all packages
57
+ docs_paths = manager.get_docs(return_paths=True)
58
+ print(f"Total documentation files: {len(docs_paths)}")
59
+
60
+ # Get documentation for a specific package
61
+ specific_docs = manager.get_docs(package_name="some-package", return_paths=True)
62
+ print(f"Documentation files for 'some-package': {len(specific_docs)}")
63
+
64
+ # Display documentation paths for a specific package
65
+ manager.display_library_docs("some-package")
66
+
67
+ def example_repository_management():
68
+ """Repository management example"""
69
+ print("\n=== Repository Management Example ===")
70
+
71
+ manager = LLMFriendlyPackageManager()
72
+
73
+ # Get current proxy setting
74
+ current_proxy = manager.set_proxy()
75
+ print(f"Current proxy: {current_proxy}")
76
+
77
+ # Set a new proxy (optional)
78
+ # manager.set_proxy("https://gitee.com/your-mirror/llm_friendly_packages")
79
+
80
+ # Refresh the repository to get latest changes
81
+ print("Refreshing repository...")
82
+ success = manager.refresh_repository()
83
+ if success:
84
+ print("Repository refreshed successfully!")
85
+
86
+ def example_data_access():
87
+ """Data access example"""
88
+ print("\n=== Data Access Example ===")
89
+
90
+ manager = LLMFriendlyPackageManager()
91
+
92
+ # Get all available libraries as structured data
93
+ available_libs = manager.list_all_available_libraries()
94
+ print(f"Total available libraries: {len(available_libs)}")
95
+
96
+ # Process the library information
97
+ for lib in available_libs[:3]: # Show first 3
98
+ print(f"Domain: {lib.domain}, "
99
+ f"Username: {lib.username}, "
100
+ f"Library: {lib.lib_name}, "
101
+ f"Added: {lib.is_added}")
102
+
103
+ def example_custom_configuration():
104
+ """Custom configuration example"""
105
+ print("\n=== Custom Configuration Example ===")
106
+
107
+ # Initialize with custom directories (using existing project directory)
108
+ import tempfile
109
+ import os
110
+
111
+ # Create a temporary directory for demonstration
112
+ with tempfile.TemporaryDirectory() as temp_dir:
113
+ custom_project_root = temp_dir
114
+ custom_persist_dir = os.path.join(temp_dir, "custom_persist")
115
+
116
+ manager = LLMFriendlyPackageManager(
117
+ project_root=custom_project_root,
118
+ base_persist_dir=custom_persist_dir
119
+ )
120
+
121
+ print("Manager initialized with custom configuration")
122
+ print(f"Project root: {custom_project_root}")
123
+ print(f"Persistence directory: {custom_persist_dir}")
124
+
125
+ # Use the manager with custom configuration
126
+ added_libs = manager.list_added_libraries()
127
+ print(f"Added libraries with custom config: {added_libs}")
128
+
129
+ if __name__ == "__main__":
130
+ # Run all examples
131
+ example_basic_usage()
132
+ example_library_management()
133
+ example_documentation_access()
134
+ example_repository_management()
135
+ example_data_access()
136
+ example_custom_configuration()
137
+
138
+ print("\n=== All examples completed ===")
@@ -0,0 +1,63 @@
1
+ """
2
+ Test script for LLMFriendlyPackageManager
3
+
4
+ This script demonstrates the usage of the new LLMFriendlyPackageManager class.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ # Add the project root to the Python path
12
+ project_root = Path(__file__).parent.parent.parent
13
+ sys.path.insert(0, str(project_root))
14
+
15
+ from autocoder.common.llm_friendly_package import LLMFriendlyPackageManager
16
+
17
+ def test_llm_friendly_package_manager():
18
+ """Test the LLMFriendlyPackageManager functionality"""
19
+
20
+ # Initialize the manager
21
+ manager = LLMFriendlyPackageManager()
22
+
23
+ print("=== Testing LLMFriendlyPackageManager ===\n")
24
+
25
+ # Test 1: Display added libraries (should be empty initially)
26
+ print("1. Testing display_added_libraries():")
27
+ manager.display_added_libraries()
28
+ print()
29
+
30
+ # Test 2: List added libraries programmatically
31
+ print("2. Testing list_added_libraries():")
32
+ added_libs = manager.list_added_libraries()
33
+ print(f"Added libraries: {added_libs}")
34
+ print()
35
+
36
+ # Test 3: Show current proxy
37
+ print("3. Testing set_proxy() to get current proxy:")
38
+ current_proxy = manager.set_proxy()
39
+ print(f"Current proxy: {current_proxy}")
40
+ print()
41
+
42
+ # Test 4: Try to get docs (should be empty if no libraries added)
43
+ print("4. Testing get_docs():")
44
+ docs = manager.get_docs(return_paths=True)
45
+ print(f"Number of documentation files found: {len(docs)}")
46
+ if docs:
47
+ print("First few docs:")
48
+ for i, doc in enumerate(docs[:3]):
49
+ print(f" - {doc}")
50
+ print()
51
+
52
+ # Test 5: Display all available libraries (may require repository)
53
+ print("5. Testing display_all_libraries():")
54
+ try:
55
+ manager.display_all_libraries()
56
+ except Exception as e:
57
+ print(f"Could not display all libraries: {e}")
58
+ print()
59
+
60
+ print("=== Test completed ===")
61
+
62
+ if __name__ == "__main__":
63
+ test_llm_friendly_package_manager()
@@ -58,6 +58,7 @@ from autocoder.common.v2.agent.agentic_edit_tools import ( # Import specific re
58
58
  AttemptCompletionToolResolver, PlanModeRespondToolResolver, UseMcpToolResolver,
59
59
  ListPackageInfoToolResolver
60
60
  )
61
+ from autocoder.common.llm_friendly_package import LLMFriendlyPackageManager
61
62
  from autocoder.common.rulefiles.autocoderrules_utils import get_rules,auto_select_rules,get_required_and_index_rules
62
63
  from autocoder.common.v2.agent.agentic_edit_types import (AgenticEditRequest, ToolResult,
63
64
  MemoryConfig, CommandConfig, BaseTool,
@@ -127,7 +128,8 @@ class AgenticEdit:
127
128
  self.memory_config = memory_config
128
129
  self.command_config = command_config # Note: command_config might be unused now
129
130
  self.project_type_analyzer = ProjectTypeAnalyzer(
130
- args=args, llm=self.llm)
131
+ args=args, llm=self.llm)
132
+ self.base_persist_dir = os.path.join(args.source_dir, ".auto-coder", "plugins", "chat-auto-coder")
131
133
 
132
134
  # self.shadow_manager = ShadowManager(
133
135
  # args.source_dir, args.event_file, args.ignore_clean_shadows)
@@ -163,6 +165,33 @@ class AgenticEdit:
163
165
  # 格式: { file_path: FileChangeEntry(...) }
164
166
  self.file_changes: Dict[str, FileChangeEntry] = {}
165
167
 
168
+ @byzerllm.prompt()
169
+ def generate_library_docs_prompt(self, libraries: List[str], docs_content: str) -> Dict[str, Any]:
170
+ """
171
+ ====
172
+
173
+ THIRD-PARTY LIBRARY DOCUMENTATION
174
+
175
+ The following documentation is for third-party libraries that are available in this project. Use this information to understand the capabilities and APIs of these libraries when they are relevant to the user's task.
176
+
177
+ Libraries included: {{ libraries_list }}
178
+
179
+ <library_documentation>
180
+ {{ combined_docs }}
181
+ </library_documentation>
182
+
183
+ You should reference this documentation when:
184
+ 1. The user asks about functionality that might be provided by these libraries
185
+ 2. You need to implement features that could leverage these library capabilities
186
+ 3. You want to suggest using library functions instead of implementing from scratch
187
+ 4. You need to understand the API or usage patterns of these libraries
188
+ ====
189
+ """
190
+ return {
191
+ "libraries_list": ", ".join(libraries),
192
+ "combined_docs": docs_content
193
+ }
194
+
166
195
  def record_file_change(self, file_path: str, change_type: str, diff: Optional[str] = None, content: Optional[str] = None):
167
196
  """
168
197
  记录单个文件的变更信息。
@@ -801,6 +830,43 @@ class AgenticEdit:
801
830
  conversations = [
802
831
  {"role": "system", "content": system_prompt},
803
832
  ]
833
+
834
+ # Add third-party library documentation information
835
+ try:
836
+ package_manager = LLMFriendlyPackageManager(
837
+ project_root=self.args.source_dir,
838
+ base_persist_dir=self.base_persist_dir
839
+ )
840
+
841
+ # Get list of added libraries
842
+ added_libraries = package_manager.list_added_libraries()
843
+
844
+ if added_libraries:
845
+ # Get documentation content for all added libraries
846
+ docs_content = package_manager.get_docs(return_paths=False)
847
+
848
+ if docs_content:
849
+ # Combine all documentation content
850
+ combined_docs = "\n\n".join(docs_content)
851
+
852
+ # Generate library documentation prompt using decorator
853
+ library_docs_prompt = self.generate_library_docs_prompt.prompt(
854
+ libraries=added_libraries,
855
+ docs_content=combined_docs
856
+ )
857
+
858
+ conversations.append({
859
+ "role": "user",
860
+ "content": library_docs_prompt
861
+ })
862
+
863
+ conversations.append({
864
+ "role": "assistant",
865
+ "content": "我已经阅读并理解了项目中可用的第三方库文档信息。在处理您的请求时,我会适当地参考这些库的功能和API,帮助您更好地利用这些库的能力。"
866
+ })
867
+
868
+ except Exception as e:
869
+ logger.warning(f"Failed to load library documentation: {str(e)}")
804
870
 
805
871
  conversations.append({
806
872
  "role": "user", "content": request.user_input
@@ -824,7 +890,8 @@ class AgenticEdit:
824
890
 
825
891
  while True:
826
892
  iteration_count += 1
827
- logger.info(f"Starting LLM interaction cycle #{iteration_count}")
893
+ logger.info(f"Starting LLM interaction cycle #{iteration_count}, reset tool_executed to False")
894
+ tool_executed = False
828
895
  global_cancel.check_and_raise(token=self.args.event_file)
829
896
  last_message = conversations[-1]
830
897
  if last_message["role"] == "assistant":
@@ -41,44 +41,20 @@ def convert_yaml_config_to_str(yaml_config):
41
41
  def get_llm_friendly_package_docs(memory,
42
42
  package_name: Optional[str] = None, return_paths: bool = False
43
43
  ) -> List[str]:
44
- lib_dir = os.path.join(".auto-coder", "libs")
45
- llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
46
- docs = []
47
-
48
- if not os.path.exists(llm_friendly_packages_dir):
49
- print("llm_friendly_packages directory not found.")
50
- return docs
51
-
52
- libs = list(memory.get("libs", {}).keys())
53
-
54
- for domain in os.listdir(llm_friendly_packages_dir):
55
- domain_path = os.path.join(llm_friendly_packages_dir, domain)
56
- if os.path.isdir(domain_path):
57
- for username in os.listdir(domain_path):
58
- username_path = os.path.join(domain_path, username)
59
- if os.path.isdir(username_path):
60
- for lib_name in os.listdir(username_path):
61
- lib_path = os.path.join(username_path, lib_name)
62
- if (
63
- os.path.isdir(lib_path)
64
- and (
65
- package_name is None
66
- or lib_name == package_name
67
- or package_name == os.path.join(username, lib_name)
68
- )
69
- and lib_name in libs
70
- ):
71
- for root, _, files in os.walk(lib_path):
72
- for file in files:
73
- if file.endswith(".md"):
74
- file_path = os.path.join(root, file)
75
- if return_paths:
76
- docs.append(file_path)
77
- else:
78
- with open(file_path, "r",encoding="utf-8") as f:
79
- docs.append(f.read())
80
-
81
- return docs
44
+ """
45
+ Legacy function for backward compatibility.
46
+ Use LLMFriendlyPackageManager class for new code.
47
+ """
48
+ from autocoder.common.llm_friendly_package import LLMFriendlyPackageManager
49
+
50
+ project_root = os.getcwd()
51
+ base_persist_dir = os.path.join(project_root, ".auto-coder", "plugins", "chat-auto-coder")
52
+
53
+ manager = LLMFriendlyPackageManager(
54
+ project_root=project_root,
55
+ base_persist_dir=base_persist_dir
56
+ )
57
+ return manager.get_docs(package_name, return_paths)
82
58
 
83
59
 
84
60
  def convert_config_value(key, value):
autocoder/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
 
2
- __version__ = "0.1.382"
2
+ __version__ = "0.1.384"