Files
cowork-local/presentation/co4e/co4e_agents.py
T
Nam Pham Dinh ThanhandClaude Opus 5 0e00bf3c2f refactor(co4e): co4e_tab.py 1885 -> 389, Co4ETab tách thành 7 mixin
File to nhất còn lại của Gamma. Lâm bàn giao ở 1.885 dòng với 100 method
trong một lớp; chia theo bảy mối quan tâm:

    co4e_runs.py           364   chạy flow, 3 chế độ, bảng lịch sử lượt chạy
    co4e_chat.py           343   khung chat + đếm token + định tuyến riêng
    co4e_layout.py         308   ba khung, bảng cấu hình, bố cục màn hẹp
    co4e_sidebar.py        251   thư viện workflow/agent/skill, 4 mục gập
    co4e_flow_tabs.py      180   dải tab các flow đang mở
    co4e_workflow_crud.py  154   tạo/sửa/xoá/nhân bản workflow
    co4e_agents.py          51   agent và skill dùng trong flow
    ui/co4e_tab.py         389   __init__, set_project, thư mục output

Mọi file dưới 400 dòng.

MỘT LỖI SUÝT LÀM HỎNG FILE: bản đầu tôi cắt method theo m.lineno, mà lineno
trỏ vào dòng `def`, không tính dòng `@...` phía trên. Decorator bị bỏ lại
thành mồ côi ngay trên một hằng số lớp -> file hỏng cú pháp. Bắt được vì
script tự parse lại sau mỗi lần cắt; nếu chỉ cắt rồi ghi thì đã đẩy lên một
file không import nổi.

Ba vòng sửa mức import tương đối: co4e_tab.py nằm ở ui/ (1 cấp), file mới ở
presentation/co4e/ (2 cấp). Còn co4e_canvas / co4e_config_panel /
co4e_agent_dialog thì VẪN ở ui/, nên `.co4e_canvas` phải thành
`...ui.co4e_canvas` chứ không phải `.co4e_canvas` cùng thư mục.

714 test xanh — trong đó có ~4.000 dòng test đặc tả Lâm viết cho đúng vùng
này, nên việc tách được soi khá kỹ. check_co4e, check_controls_alive,
check_layout_geometry, check_probes_bite đều qua.

Cập nhật đích đột biến thứ ba của check_probes_bite: dải tab flow nay ở
presentation/co4e/co4e_layout.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 10:43:33 +09:00

52 lines
1.8 KiB
Python

"""Agent và skill dùng trong flow — R08-T09.
"""
from __future__ import annotations
import re
from typing import Dict, List
from PySide6.QtCore import QSize, Qt
from ...core import co4e, skills as skills_mod
from ...i18n import tr
from ...presentation.co4e.co4e_chat_view import _skill_names
class Co4EAgentsMixin:
def _new_agent(self) -> None:
self._edit_agent_dialog(co4e.new_custom_agent(""))
def _edit_agent(self) -> None:
item = self.agent_list.currentItem()
cid = item.data(Qt.UserRole + 1) if item else None
if not cid:
self.status_message.emit(tr("co4e.select_custom_agent"))
return
agent = next((a for a in co4e.list_custom_agents() if a.id == cid), None)
if agent is not None:
self._edit_agent_dialog(agent)
def _edit_agent_dialog(self, agent: co4e.CustomAgent) -> None:
from ...ui.co4e_agent_dialog import Co4EAgentDialog
dlg = Co4EAgentDialog(self.ctx, agent, _skill_names(), self)
if dlg.exec():
co4e.save_custom_agent(dlg.result_agent())
self._reload_sidebar()
def _delete_agent(self) -> None:
item = self.agent_list.currentItem()
cid = item.data(Qt.UserRole + 1) if item else None
if not cid:
self.status_message.emit(tr("co4e.select_custom_agent"))
return
co4e.delete_custom_agent(cid)
self._reload_sidebar()
def _manage_skills(self) -> None:
from ...ui.skills_dialog import SkillsDialog
SkillsDialog(self, self.ctx).exec()
self._reload_sidebar()
def _skill_map(self) -> Dict[str, str]:
out = {}
for name in _skill_names():
block = skills_mod.skill_prefix_for(name)
if block:
out[name] = block.split("\n", 1)[1] if "\n" in block else block
return out