auto-coder-web 0.1.91__py3-none-any.whl → 0.1.93__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.
- auto_coder_web/common_router/chat_list_manager.py +194 -0
- auto_coder_web/common_router/chat_list_router.py +55 -115
- auto_coder_web/common_router/chat_session_manager.py +111 -0
- auto_coder_web/common_router/file_group_router.py +55 -2
- auto_coder_web/proxy.py +3 -2
- auto_coder_web/routers/auto_router.py +33 -29
- auto_coder_web/routers/chat_panels_router.py +159 -0
- auto_coder_web/routers/chat_router.py +120 -1
- auto_coder_web/routers/code_editor_tabs_router.py +191 -0
- auto_coder_web/routers/coding_router.py +28 -26
- auto_coder_web/version.py +1 -1
- auto_coder_web/web/assets/{main-edBorJ-r.css → main-D8cC7hK1.css} +1 -1
- auto_coder_web/web/assets/main.js +382 -382
- auto_coder_web/web/index.html +1 -1
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/METADATA +2 -2
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/RECORD +19 -18
- auto_coder_web/file_cacher/__init__.py +0 -0
- auto_coder_web/file_cacher/filecacher.py +0 -195
- auto_coder_web/file_group.py +0 -69
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/WHEEL +0 -0
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/entry_points.txt +0 -0
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/top_level.txt +0 -0
@@ -16,6 +16,10 @@ from byzerllm.utils.langutil import asyncfy_with_semaphore
|
|
16
16
|
from autocoder.common.global_cancel import global_cancel, CancelRequestedException
|
17
17
|
from loguru import logger
|
18
18
|
import byzerllm
|
19
|
+
# 导入聊天会话和聊天列表管理器
|
20
|
+
from auto_coder_web.common_router.chat_session_manager import read_session_name_sync
|
21
|
+
from auto_coder_web.common_router.chat_list_manager import get_chat_list_sync
|
22
|
+
|
19
23
|
router = APIRouter()
|
20
24
|
|
21
25
|
# 创建线程池
|
@@ -25,6 +29,7 @@ class AutoCommandRequest(BaseModel):
|
|
25
29
|
command: str
|
26
30
|
include_conversation_history: bool = True
|
27
31
|
buildin_conversation_history: bool = False
|
32
|
+
panel_id: Optional[str] = None
|
28
33
|
|
29
34
|
class EventPollRequest(BaseModel):
|
30
35
|
event_file_id:str
|
@@ -102,40 +107,39 @@ async def auto_command(request: AutoCommandRequest, project_path: str = Depends(
|
|
102
107
|
|
103
108
|
if request.include_conversation_history:
|
104
109
|
# 获取当前会话名称
|
105
|
-
|
110
|
+
panel_id = request.panel_id or ""
|
106
111
|
current_session_name = ""
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
logger.exception(e)
|
112
|
+
try:
|
113
|
+
# 使用chat_session_manager模块获取当前会话名称
|
114
|
+
# 使用同步版本的函数,避免在线程中使用asyncio.run
|
115
|
+
current_session_name = read_session_name_sync(project_path, panel_id)
|
116
|
+
except Exception as e:
|
117
|
+
logger.error(f"Error reading current session: {str(e)}")
|
118
|
+
logger.exception(e)
|
115
119
|
|
116
120
|
# 获取历史消息
|
117
121
|
messages = []
|
118
122
|
if current_session_name:
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
123
|
+
try:
|
124
|
+
# 使用chat_list_manager模块获取聊天列表内容
|
125
|
+
logger.info(f"Loading chat history for session: {current_session_name}")
|
126
|
+
# 使用同步版本的函数,避免在线程中使用asyncio.run
|
127
|
+
chat_data = get_chat_list_sync(project_path, current_session_name)
|
128
|
+
|
129
|
+
# 从聊天历史中提取消息
|
130
|
+
for msg in chat_data.get("messages", []):
|
131
|
+
# if msg.get("metadata",{}).get("stream_out_type","") == "/agent/edit":
|
132
|
+
# messages.append(msg)
|
133
|
+
# continue
|
134
|
+
|
135
|
+
# if msg.get("type","") not in ["USER_RESPONSE","RESULT","COMPLETION"]:
|
136
|
+
# continue
|
137
|
+
if msg.get("contentType","") in ["token_stat"]:
|
138
|
+
continue
|
139
|
+
messages.append(msg)
|
140
|
+
except Exception as e:
|
141
|
+
logger.error(f"Error reading chat history: {str(e)}")
|
142
|
+
logger.exception(e)
|
139
143
|
|
140
144
|
if messages:
|
141
145
|
# 调用coding_prompt生成包含历史消息的提示
|
@@ -0,0 +1,159 @@
|
|
1
|
+
import os
|
2
|
+
import json
|
3
|
+
import aiofiles
|
4
|
+
from fastapi import APIRouter, HTTPException, Request, Depends
|
5
|
+
from pydantic import BaseModel
|
6
|
+
from pathlib import Path
|
7
|
+
from typing import List, Optional
|
8
|
+
|
9
|
+
router = APIRouter()
|
10
|
+
|
11
|
+
# 定义数据模型
|
12
|
+
class ChatTab(BaseModel):
|
13
|
+
id: str
|
14
|
+
name: str
|
15
|
+
|
16
|
+
class ChatPanelsConfig(BaseModel):
|
17
|
+
tabs: List[ChatTab] = [
|
18
|
+
ChatTab(id="main", name="主线面板"),
|
19
|
+
ChatTab(id="secondary", name="支线面板")
|
20
|
+
]
|
21
|
+
activeTabId: str = "main"
|
22
|
+
|
23
|
+
async def get_project_path(request: Request) -> str:
|
24
|
+
"""从FastAPI请求上下文中获取项目路径"""
|
25
|
+
return request.app.state.project_path
|
26
|
+
|
27
|
+
async def get_config_path(project_path: str) -> Path:
|
28
|
+
"""获取聊天面板配置文件路径"""
|
29
|
+
config_path = Path(project_path) / ".auto-coder" / "auto-coder.web" / "chat_panels.json"
|
30
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
31
|
+
return config_path
|
32
|
+
|
33
|
+
async def load_config(config_path: Path) -> ChatPanelsConfig:
|
34
|
+
"""加载聊天面板配置"""
|
35
|
+
if not config_path.exists():
|
36
|
+
return ChatPanelsConfig()
|
37
|
+
|
38
|
+
try:
|
39
|
+
async with aiofiles.open(config_path, mode='r', encoding='utf-8') as f:
|
40
|
+
content = await f.read()
|
41
|
+
config_data = json.loads(content)
|
42
|
+
return ChatPanelsConfig(**config_data)
|
43
|
+
except FileNotFoundError:
|
44
|
+
return ChatPanelsConfig()
|
45
|
+
except json.JSONDecodeError:
|
46
|
+
# 处理配置文件损坏或为空的情况
|
47
|
+
return ChatPanelsConfig()
|
48
|
+
|
49
|
+
async def save_config(config: ChatPanelsConfig, config_path: Path):
|
50
|
+
"""保存聊天面板配置"""
|
51
|
+
async with aiofiles.open(config_path, mode='w', encoding='utf-8') as f:
|
52
|
+
await f.write(json.dumps(config.dict(), indent=2, ensure_ascii=False))
|
53
|
+
|
54
|
+
# 获取所有聊天标签页
|
55
|
+
@router.get("/api/chat/panels")
|
56
|
+
async def get_chat_panels(request: Request):
|
57
|
+
"""获取所有聊天标签页配置"""
|
58
|
+
project_path = await get_project_path(request)
|
59
|
+
config_path = await get_config_path(project_path)
|
60
|
+
config = await load_config(config_path)
|
61
|
+
return config.dict()
|
62
|
+
|
63
|
+
# 更新聊天标签页列表
|
64
|
+
@router.put("/api/chat/panels/tabs")
|
65
|
+
async def update_chat_tabs(
|
66
|
+
tabs: List[ChatTab],
|
67
|
+
request: Request
|
68
|
+
):
|
69
|
+
"""更新聊天标签页列表"""
|
70
|
+
if not tabs:
|
71
|
+
raise HTTPException(status_code=400, detail="聊天标签页列表不能为空")
|
72
|
+
|
73
|
+
project_path = await get_project_path(request)
|
74
|
+
config_path = await get_config_path(project_path)
|
75
|
+
config = await load_config(config_path)
|
76
|
+
config.tabs = tabs
|
77
|
+
|
78
|
+
# 如果当前活跃标签不在新列表中,设置为第一个标签
|
79
|
+
tab_ids = [tab.id for tab in tabs]
|
80
|
+
if config.activeTabId not in tab_ids and tab_ids:
|
81
|
+
config.activeTabId = tab_ids[0]
|
82
|
+
|
83
|
+
await save_config(config, config_path)
|
84
|
+
return config.dict()
|
85
|
+
|
86
|
+
# 更新当前活跃标签
|
87
|
+
@router.put("/api/chat/panels/active-tab")
|
88
|
+
async def update_active_tab(
|
89
|
+
active_tab: dict,
|
90
|
+
request: Request
|
91
|
+
):
|
92
|
+
"""更新当前活跃的聊天标签页"""
|
93
|
+
tab_id = active_tab.get("id")
|
94
|
+
if not tab_id:
|
95
|
+
raise HTTPException(status_code=400, detail="必须提供标签页ID")
|
96
|
+
|
97
|
+
project_path = await get_project_path(request)
|
98
|
+
config_path = await get_config_path(project_path)
|
99
|
+
config = await load_config(config_path)
|
100
|
+
|
101
|
+
# 确保指定的标签页存在
|
102
|
+
tab_ids = [tab.id for tab in config.tabs]
|
103
|
+
if tab_id not in tab_ids:
|
104
|
+
raise HTTPException(status_code=404, detail=f"标签页ID '{tab_id}' 不存在")
|
105
|
+
|
106
|
+
config.activeTabId = tab_id
|
107
|
+
await save_config(config, config_path)
|
108
|
+
return {"activeTabId": tab_id}
|
109
|
+
|
110
|
+
# 添加新标签页
|
111
|
+
@router.post("/api/chat/panels/tabs")
|
112
|
+
async def add_chat_tab(
|
113
|
+
tab: ChatTab,
|
114
|
+
request: Request
|
115
|
+
):
|
116
|
+
"""添加新的聊天标签页"""
|
117
|
+
if not tab.id or not tab.name:
|
118
|
+
raise HTTPException(status_code=400, detail="标签页必须包含ID和名称")
|
119
|
+
|
120
|
+
project_path = await get_project_path(request)
|
121
|
+
config_path = await get_config_path(project_path)
|
122
|
+
config = await load_config(config_path)
|
123
|
+
|
124
|
+
# 检查ID是否已存在
|
125
|
+
if any(existing_tab.id == tab.id for existing_tab in config.tabs):
|
126
|
+
raise HTTPException(status_code=400, detail=f"标签页ID '{tab.id}' 已存在")
|
127
|
+
|
128
|
+
config.tabs.append(tab)
|
129
|
+
await save_config(config, config_path)
|
130
|
+
return tab.dict()
|
131
|
+
|
132
|
+
# 删除标签页
|
133
|
+
@router.delete("/api/chat/panels/tabs/{tab_id}")
|
134
|
+
async def delete_chat_tab(
|
135
|
+
tab_id: str,
|
136
|
+
request: Request
|
137
|
+
):
|
138
|
+
"""删除指定的聊天标签页"""
|
139
|
+
project_path = await get_project_path(request)
|
140
|
+
config_path = await get_config_path(project_path)
|
141
|
+
config = await load_config(config_path)
|
142
|
+
|
143
|
+
# 确保至少保留一个标签页
|
144
|
+
if len(config.tabs) <= 1:
|
145
|
+
raise HTTPException(status_code=400, detail="必须至少保留一个聊天标签页")
|
146
|
+
|
147
|
+
# 查找并删除标签页
|
148
|
+
initial_length = len(config.tabs)
|
149
|
+
config.tabs = [tab for tab in config.tabs if tab.id != tab_id]
|
150
|
+
|
151
|
+
if len(config.tabs) == initial_length:
|
152
|
+
raise HTTPException(status_code=404, detail=f"标签页ID '{tab_id}' 不存在")
|
153
|
+
|
154
|
+
# 如果删除的是当前活跃标签,切换到第一个标签
|
155
|
+
if config.activeTabId == tab_id:
|
156
|
+
config.activeTabId = config.tabs[0].id
|
157
|
+
|
158
|
+
await save_config(config, config_path)
|
159
|
+
return {"success": True, "activeTabId": config.activeTabId}
|
@@ -15,6 +15,10 @@ from autocoder.events.event_types import EventType
|
|
15
15
|
from byzerllm.utils.langutil import asyncfy_with_semaphore
|
16
16
|
from autocoder.common.global_cancel import global_cancel, CancelRequestedException
|
17
17
|
from loguru import logger
|
18
|
+
import byzerllm
|
19
|
+
# 导入聊天会话和聊天列表管理器
|
20
|
+
from auto_coder_web.common_router.chat_session_manager import read_session_name_sync
|
21
|
+
from auto_coder_web.common_router.chat_list_manager import get_chat_list_sync
|
18
22
|
|
19
23
|
router = APIRouter()
|
20
24
|
|
@@ -23,6 +27,7 @@ cancel_thread_pool = ThreadPoolExecutor(max_workers=5)
|
|
23
27
|
|
24
28
|
class ChatCommandRequest(BaseModel):
|
25
29
|
command: str
|
30
|
+
panel_id: Optional[str] = None
|
26
31
|
|
27
32
|
class EventPollRequest(BaseModel):
|
28
33
|
event_file_id: str
|
@@ -42,6 +47,10 @@ class TaskHistoryRequest(BaseModel):
|
|
42
47
|
class CancelTaskRequest(BaseModel):
|
43
48
|
event_file_id: str
|
44
49
|
|
50
|
+
class ChatResetRequest(BaseModel):
|
51
|
+
session_id: str
|
52
|
+
panel_id: Optional[str] = "main"
|
53
|
+
|
45
54
|
async def get_project_path(request: Request) -> str:
|
46
55
|
"""
|
47
56
|
从FastAPI请求上下文中获取项目路径
|
@@ -54,6 +63,25 @@ def ensure_task_dir(project_path: str) -> str:
|
|
54
63
|
os.makedirs(task_dir, exist_ok=True)
|
55
64
|
return task_dir
|
56
65
|
|
66
|
+
@byzerllm.prompt()
|
67
|
+
def chat_prompt(messages: List[Dict[str, Any]], request: ChatCommandRequest):
|
68
|
+
'''
|
69
|
+
下面是我们已经产生的一个消息列表,其中 USER_RESPONSE 表示用户的输入,其他都是你的输出:
|
70
|
+
<messages>
|
71
|
+
{% for message in messages %}
|
72
|
+
<message>
|
73
|
+
<type>{{ message.type }}</type>
|
74
|
+
<content>{{ message.content }}</content>
|
75
|
+
</message>
|
76
|
+
{% endfor %}
|
77
|
+
</messages>
|
78
|
+
|
79
|
+
下面是用户的最新需求:
|
80
|
+
<request>
|
81
|
+
{{ request.command }}
|
82
|
+
</request>
|
83
|
+
'''
|
84
|
+
|
57
85
|
@router.post("/api/chat-command")
|
58
86
|
async def chat_command(request: ChatCommandRequest, project_path: str = Depends(get_project_path)):
|
59
87
|
"""
|
@@ -71,8 +99,45 @@ async def chat_command(request: ChatCommandRequest, project_path: str = Depends(
|
|
71
99
|
wrapper.configure_wrapper(f"event_file:{event_file}")
|
72
100
|
global_cancel.register_token(event_file)
|
73
101
|
|
102
|
+
# 获取当前会话名称
|
103
|
+
panel_id = request.panel_id or ""
|
104
|
+
try:
|
105
|
+
# 使用同步版本的会话管理函数,传递panel_id参数
|
106
|
+
current_session_name = read_session_name_sync(project_path, panel_id)
|
107
|
+
except Exception as e:
|
108
|
+
logger.error(f"Error reading current session: {str(e)}")
|
109
|
+
current_session_name = ""
|
110
|
+
|
111
|
+
# 获取历史消息
|
112
|
+
messages = []
|
113
|
+
if current_session_name:
|
114
|
+
try:
|
115
|
+
# 使用同步版本的聊天列表管理函数
|
116
|
+
logger.info(f"Loading chat history for session: {current_session_name}")
|
117
|
+
chat_data = get_chat_list_sync(project_path, current_session_name)
|
118
|
+
|
119
|
+
# 从聊天历史中提取消息
|
120
|
+
for msg in chat_data.get("messages", []):
|
121
|
+
# 只保留用户和中间结果信息
|
122
|
+
if msg.get("type","") not in ["USER_RESPONSE","RESULT"]:
|
123
|
+
continue
|
124
|
+
|
125
|
+
if msg.get("contentType","") in ["token_stat"]:
|
126
|
+
continue
|
127
|
+
|
128
|
+
messages.append(msg)
|
129
|
+
except Exception as e:
|
130
|
+
logger.error(f"Error reading chat history: {str(e)}")
|
131
|
+
|
132
|
+
# 构建提示信息
|
133
|
+
prompt_text = request.command
|
134
|
+
if messages:
|
135
|
+
# 调用chat_prompt生成包含历史消息的提示
|
136
|
+
prompt_text = chat_prompt.prompt(messages, request)
|
137
|
+
|
74
138
|
# 调用chat方法
|
75
|
-
|
139
|
+
logger.info(f"Prompt text: {prompt_text}")
|
140
|
+
result = wrapper.chat_wrapper(prompt_text)
|
76
141
|
get_event_manager(event_file).write_completion(
|
77
142
|
EventContentCreator.create_completion(
|
78
143
|
"200", "completed", result).to_dict()
|
@@ -289,6 +354,60 @@ async def get_task_detail(task_id: str, project_path: str = Depends(get_project_
|
|
289
354
|
raise HTTPException(
|
290
355
|
status_code=500, detail=f"Failed to get task detail: {str(e)}")
|
291
356
|
|
357
|
+
@router.post("/api/chat/reset")
|
358
|
+
async def reset_chat(request: ChatResetRequest, project_path: str = Depends(get_project_path)):
|
359
|
+
"""
|
360
|
+
重置聊天会话
|
361
|
+
|
362
|
+
通过AutoCoderRunnerWrapper调用chat方法,执行/new命令重置会话
|
363
|
+
在单独的线程中运行,并返回一个唯一的UUID
|
364
|
+
|
365
|
+
Args:
|
366
|
+
request: 包含session_id和panel_id的请求对象
|
367
|
+
project_path: 项目路径
|
368
|
+
|
369
|
+
Returns:
|
370
|
+
重置操作的结果
|
371
|
+
"""
|
372
|
+
# 生成事件文件路径
|
373
|
+
event_file, file_id = gengerate_event_file_path()
|
374
|
+
|
375
|
+
# 定义在线程中运行的函数
|
376
|
+
def run_reset_in_thread():
|
377
|
+
try:
|
378
|
+
# 加载tokenizer
|
379
|
+
from autocoder.auto_coder_runner import load_tokenizer
|
380
|
+
load_tokenizer()
|
381
|
+
|
382
|
+
# 创建AutoCoderRunnerWrapper实例
|
383
|
+
wrapper = AutoCoderRunnerWrapper(project_path)
|
384
|
+
wrapper.configure_wrapper(f"event_file:{event_file}")
|
385
|
+
global_cancel.register_token(event_file)
|
386
|
+
|
387
|
+
# 调用chat方法,执行/new命令
|
388
|
+
result = wrapper.chat_wrapper("/new")
|
389
|
+
|
390
|
+
# 写入完成事件
|
391
|
+
get_event_manager(event_file).write_completion(
|
392
|
+
EventContentCreator.create_completion(
|
393
|
+
"200", "reset_completed", result).to_dict()
|
394
|
+
)
|
395
|
+
logger.info(f"Chat reset (event file id: {file_id}) completed successfully")
|
396
|
+
except Exception as e:
|
397
|
+
logger.error(f"Error resetting chat {file_id}: {str(e)}")
|
398
|
+
logger.exception(e)
|
399
|
+
get_event_manager(event_file).write_error(
|
400
|
+
EventContentCreator.create_error(error_code="500", error_message=str(e), details={}).to_dict()
|
401
|
+
)
|
402
|
+
|
403
|
+
# 创建并启动线程
|
404
|
+
thread = Thread(target=run_reset_in_thread)
|
405
|
+
thread.daemon = True # 设置为守护线程
|
406
|
+
thread.start()
|
407
|
+
|
408
|
+
logger.info(f"Started chat reset {file_id} in background thread")
|
409
|
+
return {"event_file_id": file_id, "session_id": request.session_id}
|
410
|
+
|
292
411
|
@router.post("/api/chat-command/cancel")
|
293
412
|
async def cancel_task(request: CancelTaskRequest, project_path: str = Depends(get_project_path)):
|
294
413
|
"""
|
@@ -0,0 +1,191 @@
|
|
1
|
+
import os
|
2
|
+
import json
|
3
|
+
import aiofiles
|
4
|
+
from fastapi import APIRouter, HTTPException, Request, Depends
|
5
|
+
from pydantic import BaseModel
|
6
|
+
from pathlib import Path
|
7
|
+
from typing import List, Optional
|
8
|
+
|
9
|
+
router = APIRouter()
|
10
|
+
|
11
|
+
# 定义数据模型
|
12
|
+
class EditorTab(BaseModel):
|
13
|
+
path: str
|
14
|
+
label: str
|
15
|
+
isActive: bool = False
|
16
|
+
|
17
|
+
class EditorTabsConfig(BaseModel):
|
18
|
+
tabs: List[EditorTab] = []
|
19
|
+
activeTabPath: Optional[str] = None
|
20
|
+
|
21
|
+
async def get_project_path(request: Request) -> str:
|
22
|
+
"""从FastAPI请求上下文中获取项目路径"""
|
23
|
+
return request.app.state.project_path
|
24
|
+
|
25
|
+
async def get_config_path(project_path: str) -> Path:
|
26
|
+
"""获取代码编辑器标签页配置文件路径"""
|
27
|
+
config_path = Path(project_path) / ".auto-coder" / "auto-coder.web" / "editor_tabs.json"
|
28
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
29
|
+
return config_path
|
30
|
+
|
31
|
+
async def load_config(config_path: Path) -> EditorTabsConfig:
|
32
|
+
"""加载代码编辑器标签页配置"""
|
33
|
+
if not config_path.exists():
|
34
|
+
return EditorTabsConfig()
|
35
|
+
|
36
|
+
try:
|
37
|
+
async with aiofiles.open(config_path, mode='r', encoding='utf-8') as f:
|
38
|
+
content = await f.read()
|
39
|
+
config_data = json.loads(content)
|
40
|
+
return EditorTabsConfig(**config_data)
|
41
|
+
except FileNotFoundError:
|
42
|
+
return EditorTabsConfig()
|
43
|
+
except json.JSONDecodeError:
|
44
|
+
# 处理配置文件损坏或为空的情况
|
45
|
+
return EditorTabsConfig()
|
46
|
+
|
47
|
+
async def save_config(config: EditorTabsConfig, config_path: Path):
|
48
|
+
"""保存代码编辑器标签页配置"""
|
49
|
+
async with aiofiles.open(config_path, mode='w', encoding='utf-8') as f:
|
50
|
+
await f.write(json.dumps(config.dict(), indent=2, ensure_ascii=False))
|
51
|
+
|
52
|
+
# 获取所有编辑器标签页
|
53
|
+
@router.get("/api/editor/tabs")
|
54
|
+
async def get_editor_tabs(request: Request):
|
55
|
+
"""获取所有代码编辑器标签页配置"""
|
56
|
+
project_path = await get_project_path(request)
|
57
|
+
config_path = await get_config_path(project_path)
|
58
|
+
config = await load_config(config_path)
|
59
|
+
return config.dict()
|
60
|
+
|
61
|
+
# 更新编辑器标签页列表
|
62
|
+
@router.put("/api/editor/tabs")
|
63
|
+
async def update_editor_tabs(
|
64
|
+
tabs: List[EditorTab],
|
65
|
+
request: Request
|
66
|
+
):
|
67
|
+
"""更新代码编辑器标签页列表"""
|
68
|
+
project_path = await get_project_path(request)
|
69
|
+
config_path = await get_config_path(project_path)
|
70
|
+
config = await load_config(config_path)
|
71
|
+
|
72
|
+
config.tabs = tabs
|
73
|
+
|
74
|
+
# 更新活跃标签
|
75
|
+
active_tabs = [tab for tab in tabs if tab.isActive]
|
76
|
+
if active_tabs:
|
77
|
+
config.activeTabPath = active_tabs[0].path
|
78
|
+
elif tabs:
|
79
|
+
config.activeTabPath = tabs[0].path
|
80
|
+
else:
|
81
|
+
config.activeTabPath = None
|
82
|
+
|
83
|
+
await save_config(config, config_path)
|
84
|
+
return config.dict()
|
85
|
+
|
86
|
+
# 更新当前活跃标签
|
87
|
+
@router.put("/api/editor/active-tab")
|
88
|
+
async def update_active_tab(
|
89
|
+
active_tab: dict,
|
90
|
+
request: Request
|
91
|
+
):
|
92
|
+
"""更新当前活跃的代码编辑器标签页"""
|
93
|
+
tab_path = active_tab.get("path")
|
94
|
+
if not tab_path:
|
95
|
+
raise HTTPException(status_code=400, detail="必须提供标签页路径")
|
96
|
+
|
97
|
+
project_path = await get_project_path(request)
|
98
|
+
config_path = await get_config_path(project_path)
|
99
|
+
config = await load_config(config_path)
|
100
|
+
|
101
|
+
# 确保指定的标签页存在
|
102
|
+
tab_paths = [tab.path for tab in config.tabs]
|
103
|
+
if tab_path not in tab_paths:
|
104
|
+
# 如果标签不存在,添加一个新标签
|
105
|
+
new_tab = EditorTab(
|
106
|
+
path=tab_path,
|
107
|
+
label=tab_path.split('/')[-1],
|
108
|
+
isActive=True
|
109
|
+
)
|
110
|
+
config.tabs.append(new_tab)
|
111
|
+
else:
|
112
|
+
# 更新标签的活跃状态
|
113
|
+
config.tabs = [
|
114
|
+
EditorTab(
|
115
|
+
path=tab.path,
|
116
|
+
label=tab.label,
|
117
|
+
isActive=(tab.path == tab_path)
|
118
|
+
)
|
119
|
+
for tab in config.tabs
|
120
|
+
]
|
121
|
+
|
122
|
+
config.activeTabPath = tab_path
|
123
|
+
await save_config(config, config_path)
|
124
|
+
return {"activeTabPath": tab_path}
|
125
|
+
|
126
|
+
# 添加新标签页
|
127
|
+
@router.post("/api/editor/tabs")
|
128
|
+
async def add_editor_tab(
|
129
|
+
tab: EditorTab,
|
130
|
+
request: Request
|
131
|
+
):
|
132
|
+
"""添加新的代码编辑器标签页"""
|
133
|
+
if not tab.path:
|
134
|
+
raise HTTPException(status_code=400, detail="标签页必须包含路径")
|
135
|
+
|
136
|
+
project_path = await get_project_path(request)
|
137
|
+
config_path = await get_config_path(project_path)
|
138
|
+
config = await load_config(config_path)
|
139
|
+
|
140
|
+
# 检查路径是否已存在
|
141
|
+
existing_paths = [existing_tab.path for existing_tab in config.tabs]
|
142
|
+
if tab.path in existing_paths:
|
143
|
+
# 如果标签已存在,只更新活跃状态
|
144
|
+
config.tabs = [
|
145
|
+
EditorTab(
|
146
|
+
path=t.path,
|
147
|
+
label=t.label,
|
148
|
+
isActive=(t.path == tab.path)
|
149
|
+
)
|
150
|
+
for t in config.tabs
|
151
|
+
]
|
152
|
+
else:
|
153
|
+
# 添加新标签并设置为活跃
|
154
|
+
for t in config.tabs:
|
155
|
+
t.isActive = False
|
156
|
+
config.tabs.append(tab)
|
157
|
+
|
158
|
+
if tab.isActive:
|
159
|
+
config.activeTabPath = tab.path
|
160
|
+
|
161
|
+
await save_config(config, config_path)
|
162
|
+
return tab.dict()
|
163
|
+
|
164
|
+
# 删除标签页
|
165
|
+
@router.delete("/api/editor/tabs/{tab_path}")
|
166
|
+
async def delete_editor_tab(
|
167
|
+
tab_path: str,
|
168
|
+
request: Request
|
169
|
+
):
|
170
|
+
"""删除指定的代码编辑器标签页"""
|
171
|
+
project_path = await get_project_path(request)
|
172
|
+
config_path = await get_config_path(project_path)
|
173
|
+
config = await load_config(config_path)
|
174
|
+
|
175
|
+
# 查找并删除标签页
|
176
|
+
initial_length = len(config.tabs)
|
177
|
+
config.tabs = [tab for tab in config.tabs if tab.path != tab_path]
|
178
|
+
|
179
|
+
if len(config.tabs) == initial_length:
|
180
|
+
raise HTTPException(status_code=404, detail=f"标签页路径 '{tab_path}' 不存在")
|
181
|
+
|
182
|
+
# 如果删除的是当前活跃标签,切换到第一个标签
|
183
|
+
if config.activeTabPath == tab_path:
|
184
|
+
if config.tabs:
|
185
|
+
config.activeTabPath = config.tabs[0].path
|
186
|
+
config.tabs[0].isActive = True
|
187
|
+
else:
|
188
|
+
config.activeTabPath = None
|
189
|
+
|
190
|
+
await save_config(config, config_path)
|
191
|
+
return {"success": True, "activeTabPath": config.activeTabPath}
|
@@ -16,6 +16,9 @@ from byzerllm.utils.langutil import asyncfy_with_semaphore
|
|
16
16
|
from autocoder.common.global_cancel import global_cancel, CancelRequestedException
|
17
17
|
from loguru import logger
|
18
18
|
import byzerllm
|
19
|
+
# 导入聊天会话和聊天列表管理器
|
20
|
+
from auto_coder_web.common_router.chat_session_manager import read_session_name_sync
|
21
|
+
from auto_coder_web.common_router.chat_list_manager import get_chat_list_sync
|
19
22
|
|
20
23
|
router = APIRouter()
|
21
24
|
|
@@ -24,6 +27,7 @@ cancel_thread_pool = ThreadPoolExecutor(max_workers=5)
|
|
24
27
|
|
25
28
|
class CodingCommandRequest(BaseModel):
|
26
29
|
command: str
|
30
|
+
panel_id: Optional[str] = None
|
27
31
|
|
28
32
|
class EventPollRequest(BaseModel):
|
29
33
|
event_file_id: str
|
@@ -92,36 +96,34 @@ async def coding_command(request: CodingCommandRequest, project_path: str = Depe
|
|
92
96
|
global_cancel.register_token(event_file)
|
93
97
|
|
94
98
|
# 获取当前会话名称
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
except Exception as e:
|
103
|
-
logger.error(f"Error reading current session: {str(e)}")
|
99
|
+
panel_id = request.panel_id or ""
|
100
|
+
try:
|
101
|
+
# 使用同步版本的会话管理函数,传递panel_id参数
|
102
|
+
current_session_name = read_session_name_sync(project_path, panel_id)
|
103
|
+
except Exception as e:
|
104
|
+
logger.error(f"Error reading current session: {str(e)}")
|
105
|
+
current_session_name = ""
|
104
106
|
|
105
107
|
# 获取历史消息
|
106
108
|
messages = []
|
107
109
|
if current_session_name:
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
110
|
+
try:
|
111
|
+
# 使用同步版本的聊天列表管理函数
|
112
|
+
logger.info(f"Loading chat history for session: {current_session_name}")
|
113
|
+
chat_data = get_chat_list_sync(project_path, current_session_name)
|
114
|
+
|
115
|
+
# 从聊天历史中提取消息
|
116
|
+
for msg in chat_data.get("messages", []):
|
117
|
+
# 只保留用户和中间结果信息
|
118
|
+
if msg.get("type","") not in ["USER_RESPONSE","RESULT"]:
|
119
|
+
continue
|
120
|
+
|
121
|
+
if msg.get("contentType","") in ["token_stat"]:
|
122
|
+
continue
|
123
|
+
|
124
|
+
messages.append(msg)
|
125
|
+
except Exception as e:
|
126
|
+
logger.error(f"Error reading chat history: {str(e)}")
|
125
127
|
|
126
128
|
# 构建提示信息
|
127
129
|
prompt_text = request.command
|