auto-coder-web 0.1.109__py3-none-any.whl → 0.1.111__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.
@@ -61,12 +61,16 @@ class AutoCoderRunnerWrapper:
61
61
  memory = get_memory()
62
62
  return memory["conf"]
63
63
 
64
+ def get_memory_wrapper(self):
65
+ return get_memory()
64
66
 
65
67
  def coding_wapper(self,query):
66
68
  return coding(query)
67
69
 
68
70
  def chat_wrapper(self,query):
69
- return chat(query)
70
-
71
-
71
+ return chat(query)
72
+
73
+ def lib_wrapper(self,query):
74
+ return lib_command(query)
75
+
72
76
 
@@ -0,0 +1,325 @@
1
+ from fastapi import APIRouter, Depends, Request, HTTPException, Body
2
+ from pydantic import BaseModel
3
+ from typing import Dict, List, Optional
4
+ import os
5
+ import git
6
+ import json
7
+ from pathlib import Path
8
+ from autocoder.auto_coder_runner import get_memory, save_memory_with_new_memory
9
+
10
+ router = APIRouter()
11
+
12
+ # 定义依赖项函数
13
+ async def get_project_path(request: Request) -> str:
14
+ """获取项目路径作为依赖"""
15
+ return request.app.state.project_path
16
+
17
+
18
+ # 模型定义
19
+ class LibAddRequest(BaseModel):
20
+ lib_name: str
21
+
22
+ class LibRemoveRequest(BaseModel):
23
+ lib_name: str
24
+
25
+ class LibProxyRequest(BaseModel):
26
+ proxy_url: Optional[str] = None
27
+
28
+ class LibGetRequest(BaseModel):
29
+ package_name: str
30
+
31
+ class LibResponse(BaseModel):
32
+ success: bool
33
+ message: str
34
+ data: Optional[Dict] = None
35
+
36
+ class LibItem(BaseModel):
37
+ domain: str
38
+ username: str
39
+ lib_name: str
40
+ full_path: str
41
+ is_added: bool
42
+
43
+ @router.get("/api/lib/list", response_model=LibResponse)
44
+ async def list_libs(
45
+ request: Request,
46
+ memory: Dict = Depends(get_memory)
47
+ ):
48
+ """列出所有已添加的库"""
49
+ libs = memory.get("libs", {})
50
+
51
+ return LibResponse(
52
+ success=True,
53
+ message="Libraries retrieved successfully",
54
+ data={"libraries": list(libs.keys())}
55
+ )
56
+
57
+ @router.post("/api/lib/add", response_model=LibResponse)
58
+ async def add_lib(
59
+ request: Request,
60
+ lib_request: LibAddRequest,
61
+ memory: Dict = Depends(get_memory),
62
+ project_path: str = Depends(get_project_path)
63
+ ):
64
+ """添加一个库"""
65
+ lib_name = lib_request.lib_name.strip()
66
+
67
+ # 初始化目录
68
+ lib_dir = os.path.join(project_path, ".auto-coder", "libs")
69
+ llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
70
+
71
+ if not os.path.exists(lib_dir):
72
+ os.makedirs(lib_dir, exist_ok=True)
73
+
74
+ if "libs" not in memory:
75
+ memory["libs"] = {}
76
+
77
+ # 已存在的库直接返回
78
+ if lib_name in memory["libs"]:
79
+ return LibResponse(
80
+ success=True,
81
+ message=f"Library {lib_name} is already added"
82
+ )
83
+
84
+ # 克隆仓库(如果不存在)
85
+ if not os.path.exists(llm_friendly_packages_dir):
86
+ try:
87
+ proxy_url = memory.get(
88
+ "lib-proxy", "https://github.com/allwefantasy/llm_friendly_packages"
89
+ )
90
+ git.Repo.clone_from(
91
+ proxy_url,
92
+ llm_friendly_packages_dir,
93
+ )
94
+ except git.exc.GitCommandError as e:
95
+ return LibResponse(
96
+ success=False,
97
+ message=f"Error cloning repository: {str(e)}"
98
+ )
99
+
100
+ # 添加库到内存
101
+ memory["libs"][lib_name] = {}
102
+ await save_memory_with_new_memory(memory)
103
+
104
+ return LibResponse(
105
+ success=True,
106
+ message=f"Added library: {lib_name}"
107
+ )
108
+
109
+ @router.post("/api/lib/remove", response_model=LibResponse)
110
+ async def remove_lib(
111
+ request: Request,
112
+ lib_request: LibRemoveRequest,
113
+ memory: Dict = Depends(get_memory)
114
+ ):
115
+ """移除一个库"""
116
+ lib_name = lib_request.lib_name.strip()
117
+
118
+ if "libs" not in memory:
119
+ memory["libs"] = {}
120
+
121
+ if lib_name in memory["libs"]:
122
+ del memory["libs"][lib_name]
123
+ await save_memory_with_new_memory(memory)
124
+ return LibResponse(
125
+ success=True,
126
+ message=f"Removed library: {lib_name}"
127
+ )
128
+ else:
129
+ return LibResponse(
130
+ success=False,
131
+ message=f"Library {lib_name} is not in the list"
132
+ )
133
+
134
+ @router.post("/api/lib/set-proxy", response_model=LibResponse)
135
+ async def set_proxy(
136
+ request: Request,
137
+ proxy_request: LibProxyRequest = Body(None),
138
+ memory: Dict = Depends(get_memory)
139
+ ):
140
+ """设置代理URL"""
141
+ if proxy_request is None or proxy_request.proxy_url is None:
142
+ # 获取当前代理
143
+ current_proxy = memory.get("lib-proxy", "No proxy set")
144
+ return LibResponse(
145
+ success=True,
146
+ message=f"Current proxy: {current_proxy}",
147
+ data={"proxy": current_proxy}
148
+ )
149
+ else:
150
+ # 设置代理
151
+ memory["lib-proxy"] = proxy_request.proxy_url
152
+ await save_memory_with_new_memory(memory)
153
+ return LibResponse(
154
+ success=True,
155
+ message=f"Set proxy to: {proxy_request.proxy_url}"
156
+ )
157
+
158
+ @router.post("/api/lib/refresh", response_model=LibResponse)
159
+ async def refresh_lib(
160
+ request: Request,
161
+ memory: Dict = Depends(get_memory),
162
+ project_path: str = Depends(get_project_path)
163
+ ):
164
+ """刷新llm_friendly_packages仓库"""
165
+ llm_friendly_packages_dir = os.path.join(project_path, ".auto-coder", "libs", "llm_friendly_packages")
166
+
167
+ if not os.path.exists(llm_friendly_packages_dir):
168
+ return LibResponse(
169
+ success=False,
170
+ message="llm_friendly_packages repository does not exist. Please add a library first to clone it."
171
+ )
172
+
173
+ try:
174
+ repo = git.Repo(llm_friendly_packages_dir)
175
+ origin = repo.remotes.origin
176
+ proxy_url = memory.get("lib-proxy")
177
+
178
+ current_url = origin.url
179
+
180
+ if proxy_url and proxy_url != current_url:
181
+ new_url = proxy_url
182
+ origin.set_url(new_url)
183
+
184
+ origin.pull()
185
+ return LibResponse(
186
+ success=True,
187
+ message="Successfully updated llm_friendly_packages repository"
188
+ )
189
+ except git.exc.GitCommandError as e:
190
+ return LibResponse(
191
+ success=False,
192
+ message=f"Error updating repository: {str(e)}"
193
+ )
194
+
195
+ @router.post("/api/lib/get", response_model=LibResponse)
196
+ async def get_lib_docs(
197
+ request: Request,
198
+ get_request: LibGetRequest,
199
+ project_path: str = Depends(get_project_path),
200
+ memory: Dict = Depends(get_memory)
201
+ ):
202
+ """获取特定包的文档"""
203
+ package_name = get_request.package_name.strip()
204
+
205
+ # 使用与auto_coder_runner中相似的逻辑
206
+ lib_dir = os.path.join(project_path, ".auto-coder", "libs")
207
+ llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
208
+ docs = []
209
+
210
+ if not os.path.exists(llm_friendly_packages_dir):
211
+ return LibResponse(
212
+ success=False,
213
+ message="llm_friendly_packages repository does not exist"
214
+ )
215
+
216
+ libs = list(memory.get("libs", {}).keys())
217
+
218
+ for domain in os.listdir(llm_friendly_packages_dir):
219
+ domain_path = os.path.join(llm_friendly_packages_dir, domain)
220
+ if os.path.isdir(domain_path):
221
+ for username in os.listdir(domain_path):
222
+ username_path = os.path.join(domain_path, username)
223
+ if os.path.isdir(username_path):
224
+ for lib_name in os.listdir(username_path):
225
+ lib_path = os.path.join(username_path, lib_name)
226
+ if (
227
+ os.path.isdir(lib_path)
228
+ and (
229
+ package_name is None
230
+ or lib_name == package_name
231
+ or package_name == os.path.join(username, lib_name)
232
+ )
233
+ and lib_name in libs
234
+ ):
235
+ for root, _, files in os.walk(lib_path):
236
+ for file in files:
237
+ if file.endswith(".md"):
238
+ file_path = os.path.join(root, file)
239
+ docs.append(str(Path(file_path).relative_to(project_path)))
240
+
241
+ if docs:
242
+ return LibResponse(
243
+ success=True,
244
+ message=f"Found {len(docs)} markdown files for package: {package_name}",
245
+ data={"docs": docs}
246
+ )
247
+ else:
248
+ return LibResponse(
249
+ success=False,
250
+ message=f"No markdown files found for package: {package_name}"
251
+ )
252
+
253
+ @router.get("/api/lib/list-all", response_model=LibResponse)
254
+ async def list_all_libs(
255
+ request: Request,
256
+ memory: Dict = Depends(get_memory),
257
+ project_path: str = Depends(get_project_path)
258
+ ):
259
+ """列出所有可用的库,包括未添加的库"""
260
+ lib_dir = os.path.join(project_path, ".auto-coder", "libs")
261
+ llm_friendly_packages_dir = os.path.join(lib_dir, "llm_friendly_packages")
262
+ available_libs = []
263
+
264
+ # 如果仓库不存在,自动下载
265
+ if not os.path.exists(llm_friendly_packages_dir):
266
+ if not os.path.exists(lib_dir):
267
+ os.makedirs(lib_dir, exist_ok=True)
268
+
269
+ try:
270
+ # 获取代理URL(如果已设置)
271
+ proxy_url = memory.get(
272
+ "lib-proxy", "https://github.com/allwefantasy/llm_friendly_packages"
273
+ )
274
+ # 克隆仓库
275
+ git.Repo.clone_from(
276
+ proxy_url,
277
+ llm_friendly_packages_dir,
278
+ )
279
+ except git.exc.GitCommandError as e:
280
+ return LibResponse(
281
+ success=False,
282
+ message=f"Error cloning repository: {str(e)}",
283
+ data={"libraries": []}
284
+ )
285
+
286
+ # 获取已添加的库列表
287
+ added_libs = set(memory.get("libs", {}).keys())
288
+
289
+ # 遍历所有domain目录
290
+ for domain in os.listdir(llm_friendly_packages_dir):
291
+ domain_path = os.path.join(llm_friendly_packages_dir, domain)
292
+ if os.path.isdir(domain_path):
293
+ # 遍历所有username目录
294
+ for username in os.listdir(domain_path):
295
+ username_path = os.path.join(domain_path, username)
296
+ if os.path.isdir(username_path):
297
+ # 遍历所有lib_name目录
298
+ for lib_name in os.listdir(username_path):
299
+ lib_path = os.path.join(username_path, lib_name)
300
+ if os.path.isdir(lib_path):
301
+ # 检查是否有Markdown文件
302
+ has_md_files = False
303
+ for root, _, files in os.walk(lib_path):
304
+ if any(file.endswith('.md') for file in files):
305
+ has_md_files = True
306
+ break
307
+
308
+ if has_md_files:
309
+ lib_item = LibItem(
310
+ domain=domain,
311
+ username=username,
312
+ lib_name=lib_name,
313
+ full_path=f"{username}/{lib_name}",
314
+ is_added=lib_name in added_libs
315
+ )
316
+ available_libs.append(lib_item.dict())
317
+
318
+ # 按domain和username分组排序
319
+ available_libs.sort(key=lambda x: (x["domain"], x["username"], x["lib_name"]))
320
+
321
+ return LibResponse(
322
+ success=True,
323
+ message=f"Found {len(available_libs)} available libraries",
324
+ data={"libraries": available_libs}
325
+ )
@@ -264,6 +264,22 @@ def load_providers() -> List[Dict]:
264
264
  "output_price": 0.0,
265
265
  "is_reasoning": False,
266
266
  "max_output_tokens": 8096*2
267
+ },
268
+ {
269
+ "id": "anthropic/claude-sonnet-4",
270
+ "name": "claude-sonnet-4",
271
+ "input_price": 22.0,
272
+ "output_price": 111.0,
273
+ "is_reasoning": False,
274
+ "max_output_tokens": 8096*4
275
+ },
276
+ {
277
+ "id": "anthropic/claude-opus-4",
278
+ "name": "claude-opus-4",
279
+ "input_price": 111.0,
280
+ "output_price": 555.0,
281
+ "is_reasoning": False,
282
+ "max_output_tokens": 8096*4
267
283
  }
268
284
  ]
269
285
  },
auto_coder_web/proxy.py CHANGED
@@ -21,7 +21,7 @@ from autocoder.common import AutoCoderArgs
21
21
  from auto_coder_web.auto_coder_runner_wrapper import AutoCoderRunnerWrapper
22
22
  from auto_coder_web.routers import todo_router, settings_router, auto_router, commit_router, chat_router, coding_router, index_router, config_router, upload_router, rag_router, editable_preview_router, mcp_router, direct_chat_router, rules_router, chat_panels_router, code_editor_tabs_router, file_command_router
23
23
  from auto_coder_web.expert_routers import history_router
24
- from auto_coder_web.common_router import completions_router, file_router, auto_coder_conf_router, chat_list_router, file_group_router, model_router, compiler_router
24
+ from auto_coder_web.common_router import completions_router, file_router, auto_coder_conf_router, chat_list_router, file_group_router, model_router, compiler_router, lib_router
25
25
  from auto_coder_web.common_router import active_context_router
26
26
  from rich.console import Console
27
27
  from loguru import logger
@@ -86,6 +86,9 @@ class ProxyServer:
86
86
  # self.app.state.file_cacher = FileCacher(self.project_path)
87
87
  # Store initialization status
88
88
  self.app.state.is_initialized = self.is_initialized
89
+ # Store memory for lib_router
90
+ if self.auto_coder_runner:
91
+ self.app.state.memory = self.auto_coder_runner.get_memory_wrapper()
89
92
 
90
93
  self.app.include_router(todo_router.router)
91
94
  self.app.include_router(settings_router.router)
@@ -113,6 +116,7 @@ class ProxyServer:
113
116
  self.app.include_router(chat_panels_router.router)
114
117
  self.app.include_router(code_editor_tabs_router.router)
115
118
  self.app.include_router(file_command_router.router)
119
+ self.app.include_router(lib_router.router)
116
120
 
117
121
  @self.app.on_event("shutdown")
118
122
  async def shutdown_event():
auto_coder_web/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.109"
1
+ __version__ = "0.1.111"