帮我构思一个项目:Trae、Codearts atomcode 等AI agent的调度中心 优先windows系统,通过句柄获得这些AI agent的任务信息,对其进行跟踪,用户可以通过调度中心发布

发布时间:2026/6/27 2:12:43
帮我构思一个项目:Trae、Codearts atomcode 等AI agent的调度中心 优先windows系统,通过句柄获得这些AI agent的任务信息,对其进行跟踪,用户可以通过调度中心发布 帮我构思一个项目Trae、Codearts atomcode 等AI agent的调度中心 优先windows系统通过句柄获得这些AI agent的任务信息对其进行跟踪用户可以通过调度中心发布新任务并修改和回应当前的任务。群星Star- AI Agent 调度中心1. 项目概述1.1 项目名中文名群星英文名Star1.2 命名寓意“群星闪耀各司其职。调度有序光芒汇聚。”多个 AI Agent 如同夜空中的群星各自闪耀着独特的光芒。Star 调度中心就像星座的连线者将这些独立的光芒串联成完整的图景让每一颗星的输出都能汇聚成更强大的力量。1.3 Slogan群星Star—— 让每一个 AI Agent 都成为你的星座1.4 核心目标在 Windows 系统上通过系统级 API句柄、窗口消息、进程监控实现对多个 AI 编程助手Trae、CodeArts Atomcode、Cursor、Copilot 等的统一调度与任务管理。1.5 核心功能星图Agent 发现自动检测正在运行的 AI Agent 进程星轨任务队列创建、分配、修改、暂停、恢复任务星语对话监控截获 Agent 的输入/输出流星令任务干预向运行中的 Agent 注入新指令或修正方向星辉结果收集汇总各 Agent 输出统一展示2. 术语映射通用术语群星Star术语说明AI Agent星Star每个 Agent 是一颗星Agent 进程星体Star Body运行中的 Agent 实例任务队列星轨Orbit任务的流转路径新任务新星Nova新创建的任务任务分配授星Assign将任务交给某颗星任务修改调轨Adjust Orbit修改运行中的任务方向结果输出星辉StarlightAgent 的产出用户反馈回响Echo用户对 Agent 输出的回应多 Agent 协同星座Constellation多个星协同完成复杂任务3. 技术架构┌─────────────────────────────────────────────────────────────┐ │ 群星Star前端 │ │ (Web UI: React Vite, 或 Electron 桌面端) │ │ 星图面板 │ 星轨队列 │ 星语流 │ 星辉审查 │ └───────────────────────────┬─────────────────────────────────┘ │ WebSocket / IPC ┌───────────────────────────▼─────────────────────────────────┐ │ 星核Star Core- Python 3.12 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ 寻星者 │ │ 星轨引擎 │ │ 星语路由 │ │ │ │ StarSeeker │ │ OrbitEngine │ │ StarlightRouter │ │ │ └──────┬───────┘ └──────┬───────┘ └────────┬─────────┘ │ │ │ │ │ │ │ ┌──────▼─────────────────▼────────────────────▼─────────┐ │ │ │ 观星台Observatory │ │ │ │ · Win32 API (句柄/窗口/进程) │ │ │ │ · UI Automation (元素定位/文本注入) │ │ │ │ · 键盘/鼠标模拟 (SendInput/PostMessage) │ │ │ │ · 剪贴板监控 (Clipboard API) │ │ │ └───────────────────────────────────────────────────────┘ │ └───────────────────────────┬─────────────────────────────────┘ │ 句柄 / UIA / 消息 ┌───────────────────────────▼─────────────────────────────────┐ │ 群星闪耀Agent 进程 │ │ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │ │ │ Trae ☆ │ │CodeArts Atom☆│ │ Cursor ☆ │ ... │ │ └──────────┘ └──────────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────┘4. 核心模块命名与实现4.1 寻星者StarSeeker- Agent 发现class StarSeeker: 寻星者 - 发现并管理 AI Agent 进程 # 已知星体特征 STAR_SIGNATURES { trae: { process_names: [Trae.exe, trae.exe], window_class: [Chrome_WidgetWin_1, TraeMainWindow], window_title_patterns: [Trae, trae], }, codearts_atomcode: { process_names: [CodeArts.exe, AtomCode.exe], window_class: [Chrome_WidgetWin_1], window_title_patterns: [CodeArts, AtomCode], }, cursor: { process_names: [Cursor.exe], window_class: [Chrome_WidgetWin_1], window_title_patterns: [Cursor], }, } def scan_skies(self) - list[StarBody]: 扫描天际发现所有闪耀的星 stars [] for proc in psutil.process_iter([pid, name]): for star_type, sig in self.STAR_SIGNATURES.items(): if proc.info[name].lower() in [n.lower() for n in sig[process_names]]: hwnd self._locate_light(proc.info[pid], sig) if hwnd: stars.append(StarBody( star_typestar_type, pidproc.info[pid], hwndhwnd, processproc )) return stars def _locate_light(self, pid: int, sig: dict) - int: 定位星光 - 通过 PID 找到主窗口句柄 def callback(hwnd, hwnds): if win32gui.IsWindowVisible(hwnd): _, found_pid win32process.GetWindowThreadProcessId(hwnd) if found_pid pid: title win32gui.GetWindowText(hwnd) if any(p in title for p in sig[window_title_patterns]): hwnds.append(hwnd) return True hwnds [] win32gui.EnumWindows(callback, hwnds) return hwnds[0] if hwnds else None4.2 授星者StarAssigner- 文本注入class StarAssigner: 授星者 - 向星体注入星令 def send_starlight(self, star: StarBody, starlight: str) - bool: 向星体发送星辉指令 # 策略1: 观星术UIA- 最精准 if self._try_observatory(star.hwnd, starlight): return True # 策略2: 星光传递剪贴板 if self._try_starlight_transfer(star, starlight): return True # 策略3: 星波消息- 适用于原生控件 if self._try_starwave(star.hwnd, starlight): return True return False def _try_observatory(self, hwnd: int, starlight: str) - bool: 观星术 - 通过 UI Automation 精确定位输入框 import uiautomation as uia try: window uia.ControlFromHandle(hwnd) # 寻找星语输入口 edit window.EditControl( searchDepth5, ClassNameTextArea ) if edit: edit.SetValue(starlight) edit.SendKeys({Enter}) return True except Exception: pass return False def _try_starlight_transfer(self, star: StarBody, starlight: str) - bool: 星光传递 - 剪贴板注入 import pyperclip original pyperclip.paste() try: pyperclip.copy(starlight) win32gui.SetForegroundWindow(star.hwnd) time.sleep(0.1) import pyautogui pyautogui.hotkey(ctrl, v) time.sleep(0.1) pyautogui.press(enter) return True finally: pyperclip.copy(original)4.3 观星者StarGazer- 输出捕获class StarGazer: 观星者 - 捕获星体的输出 def gaze(self, star: StarBody) - str: 凝视星辉 - 获取 Agent 最后一条回复 import uiautomation as uia window uia.ControlFromHandle(star.hwnd) output_controls window.TextControl( searchDepth10, ClassNameTextBlock ) if output_controls: return output_controls.Name return def continuous_gaze(self, star: StarBody, on_starlight_change): 持续观星 - 监控输出变化 import threading def gaze_thread(): last_starlight while star.is_shining: current self.gaze(star) if current ! last_starlight: on_starlight_change(star, current) last_starlight current time.sleep(1) threading.Thread(targetgaze_thread, daemonTrue).start()5. 星轨引擎OrbitEngine- 任务调度5.1 星轨任务模型from dataclasses import dataclass from enum import Enum from datetime import datetime from typing import Optional class StarStatus(Enum): 星芒状态 NASCENT nascent # 初生新创建 ORBITING orbiting # 入轨已分配 SHINING shining # 闪耀Agent 正在处理 AWAITING_ECHO awaiting # 待回响等待用户审查 CONSTELLATED constellated # 成星完成 FADED faded # 暗淡失败 DARKENED darkened # 熄灭取消 class StarPriority(Enum): 星等优先级 DIM 0 # 暗星低 NORMAL 1 # 常星正常 BRIGHT 2 # 亮星高 SUPERNOVA 3 # 超新星紧急 dataclass class Nova: 新星 - 任务数据模型 id: str title: str description: str starlight: str # 发送给星的指令 context_files: list[str] # 上下文文件 assigned_star: Optional[str] # 分配的目标星 status: StarStatus priority: StarPriority created_at: datetime updated_at: datetime result_starlight: Optional[str] # 星辉Agent 返回结果 starlight_log: list[dict] # 星光日志对话历史 echo: Optional[str] # 回响用户反馈5.2 星轨引擎class OrbitEngine: 星轨引擎 - 任务调度核心 def __init__(self, star_seeker: StarSeeker): self.star_seeker star_seeker self.orbit_queue asyncio.Queue() self.active_novas {} async def birth_nova(self, nova: Nova) - str: 诞生新星 - 提交新任务 if not nova.assigned_star: nova.assigned_star self._calculate_orbit(nova) nova.status StarStatus.NASCENT await self.orbit_queue.put(nova) return nova.id def _calculate_orbit(self, nova: Nova) - str: 计算星轨 - 根据任务特征路由到合适的星 star_affinity { trae: [生成, 创建, 编写, generate, create], codearts: [审查, review, 检查, 漏洞], cursor: [重构, refactor, 迁移, 多文件], } for star_type, keywords in star_affinity.items(): if any(kw in nova.description for kw in keywords): available self.star_seeker.get_idle_stars(star_type) if available: return star_type return self.star_seeker.get_any_idle_star() async def adjust_orbit(self, nova_id: str, new_starlight: str): 调轨 - 修改运行中的任务 nova self.active_novas.get(nova_id) if not nova: raise ValueError(fNova {nova_id} not found in sky) star self.star_seeker.get_star(nova.assigned_star) if star and nova.status StarStatus.SHINING: correction_starlight f [星核指令] 对当前星轨进行调整 原始星图{nova.starlight} 调轨指令{new_starlight} 请忽略之前的中间星光基于调轨指令重新闪耀。 star.send_starlight(correction_starlight) nova.starlight new_starlight nova.starlight_log.append({ role: star_core, content: 星轨已调整 })6. 前端界面设计6.1 主界面布局┌─────────────────────────────────────────────────┐ │ ✦ 群星 Star [⚙ 星图设置] []│ ├──────────┬───────────────────┬──────────────────┤ │ 星图 │ 星轨面板 │ 星语监控 │ │ │ │ │ │ Trae │ 新星待升 (3) │ [星辉实时] │ │ Atom │ · 生成API星图 │ │ │ Cursor │ · 修复Bug #42 │ 正在闪耀... │ │ │ · 优化星光查询 │ │ │ │ │ │ │ [ 唤星] │ 闪耀中 (2) │ │ │ │ · 重构星云A │ │ │ │ · 撰写星光测试 │ │ │ │ │ │ │ │ ✨ 已成星 (5) │ │ │ │ │ │ ├──────────┴───────────────────┴──────────────────┤ │ 星令: [___________________] [授星: Trae ▼] [发送]│ └─────────────────────────────────────────────────┘6.2 颜色系统主色调深空蓝黑#0a0e27背景#1a1f3a面板强调色星光金#ffd700星等色超新星炽白#ffffff亮星亮蓝#4fc3f7常星银白#b0bec5暗星暗灰#616161星芒色闪耀中翠绿#66bb6a待回响琥珀#ffa726暗淡赤红#ef53506.3 图标系统使用星星相关的 SVG 图标⭐ 普通星 新星 闪耀中✨ 已成星 观星台 星图7. 项目结构star/ ├── star_core/ # 星核核心引擎 │ ├── __init__.py │ ├── star_seeker.py # 寻星者Agent 发现 │ ├── star_assigner.py # 授星者文本注入 │ ├── star_gazer.py # 观星者输出捕获 │ ├── orbit_engine.py # 星轨引擎任务调度 │ └── observatory.py # 观星台Windows API 封装 │ ├── star_api/ # 星光接口后端 API │ ├── __init__.py │ ├── main.py # FastAPI 入口 │ ├── routes/ │ │ ├── stars.py # 星管理接口 │ │ ├── novas.py # 新星任务接口 │ │ └── constellations.py # 星座协同接口 │ └── websocket/ │ └── starlight_stream.py # 星光流推送 │ ├── star_web/ # 星图前端 │ ├── src/ │ │ ├── components/ │ │ │ ├── StarMap.tsx # 星图面板 │ │ │ ├── OrbitPanel.tsx # 星轨面板 │ │ │ ├── StarlightMonitor.tsx # 星语监控 │ │ │ └── StarCommand.tsx # 星令输入 │ │ ├── pages/ │ │ │ └── Observatory.tsx # 观星台主页 │ │ └── assets/ │ │ └── star_icons/ # 星星图标 │ └── package.json │ ├── pyproject.toml └── README.md8. 星语日志系统from loguru import logger # 星语级别 logger.add( logs/star_core.log, format⭐ {time:YYYY-MM-DD HH:mm:ss} | {level} | {message}, levelINFO, rotation1 day, retention7 days ) # 关键事件星语 def log_nova_birth(nova_id: str, star_type: str): logger.info(f 新星诞生 | ID: {nova_id} | 目标星: {star_type}) def log_star_shine(nova_id: str, star_type: str): logger.info(f 星光闪耀 | 任务: {nova_id} | 星: {star_type}) def log_constellation_complete(nova_id: str): logger.info(f✨ 星座完成 | 任务: {nova_id}) def log_star_fade(nova_id: str, error: str): logger.error(f 星光暗淡 | 任务: {nova_id} | 原因: {error})9. 实现路线图星图里程碑阶段里程碑内容 朔月星核初现进程发现、窗口句柄获取、基础 UI 娥眉星光通联UI Automation 文本注入/读取 上弦星轨流转任务队列、状态管理、星轨引擎 盈凸星语交响WebSocket 实时推送、对话监控 满月群星闪耀多星协同星座、结果对比 亏凸星图完善插件系统、自定义星体 下弦星辉永驻历史记录、统计分析 残月星辰大海正式发布、文档完善这个名字体系将整个项目包装成一个完整的“星空叙事”每个技术概念都有对应的诗意表达让项目不仅实用更具有独特的品牌识别度。electron的程序现在还能拿到句柄拿到它里面的窗体、文本等信息吗可以但难度取决于 Electron 版本和渲染模式。以下是 Windows 下的实际情况和解决方案1. Electron 窗口结构┌─────────────────────────────────────────┐ │ Electron 主窗口 (HWND) │ │ ┌───────────────────────────────────┐ │ │ │ Chromium 渲染区 │ │ │ │ (Chrome_WidgetWin_1 或 │ │ │ │ Chrome_RenderWidgetHostHWND) │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ Web 内容 (DOM) │ │ │ │ │ │ · textarea │ │ │ │ │ │ · contenteditable div │ │ │ │ │ │ · Monaco Editor (Canvas) │ │ │ │ │ └─────────────────────────────┘ │ │ │ └───────────────────────────────────┘ │ └─────────────────────────────────────────┘2. 句柄获取仍然可以2.1 获取顶层窗口句柄import win32gui import win32process import psutil def get_electron_window_hwnd(process_nametrae.exe): 获取 Electron 应用的主窗口句柄 for proc in psutil.process_iter([pid, name]): if proc.info[name].lower() process_name.lower(): pid proc.info[pid] def callback(hwnd, hwnds): if win32gui.IsWindowVisible(hwnd): _, found_pid win32process.GetWindowThreadProcessId(hwnd) if found_pid pid: hwnds.append(hwnd) return True hwnds [] win32gui.EnumWindows(callback, hwnds) # 通常取第一个可见窗口 if hwnds: return hwnds[0], pid return None, None2.2 获取 Chromium 渲染子窗口Electron 内部有子窗口层级def get_chromium_render_hwnd(parent_hwnd): 获取 Chromium 渲染区域的句柄 children [] def callback(hwnd, lparam): class_name win32gui.GetClassName(hwnd) if class_name in [Chrome_RenderWidgetHostHWND, Chrome_WidgetWin_1]: children.append(hwnd) return True win32gui.EnumChildWindows(parent_hwnd, callback, None) return children3. 获取文本内容三种方案按成功率排序方案一UI Automation最推荐成功率 90%import uiautomation as uia def get_electron_text_uia(hwnd: int): 通过 UI Automation 获取 Electron 中的文本 try: # 从窗口句柄获取 UIA 元素 window uia.ControlFromHandle(hwnd) # 方法1获取所有 Text 控件适用于渲染后的文本块 text_elements [] for control in window.GetChildren(): if control.ControlTypeName TextControl: text_elements.append(control.Name) # 方法2查找编辑框输入区域 edits [] for control, depth in uia.WalkTree(window, maxDepth5): if control.ControlTypeName EditControl: edits.append({ name: control.Name, value: control.GetValuePattern().Value if control.GetValuePattern() else None, text: control.GetTextPattern().DocumentRange.GetText() if control.GetTextPattern() else None, }) return { text_blocks: text_elements, edit_controls: edits } except Exception as e: return {error: str(e)}方案二微软无障碍 API需 Electron 应用支持有些 Electron 应用如 VS Code启用了无障碍支持import win32gui import win32con def get_text_via_accessible(hwnd: int): 通过 MSAA (Active Accessibility) 获取文本 import pythoncom from win32com.client import Dispatch pythoncom.CoInitialize() try: # 获取 MSAA 对象 acc Dispatch(oleacc.AccessibleObjectFromWindow)(hwnd, 0) def walk_acc(obj, depth0): if depth 10: return [] results [] try: if obj.accName(0): results.append(obj.accName(0)) if obj.accValue(0): results.append(obj.accValue(0)) except: pass # 遍历子元素 try: for i in range(obj.accChildCount): child obj.accChild(i 1) results.extend(walk_acc(child, depth 1)) except: pass return results return walk_acc(acc) except Exception as e: return {error: str(e)} finally: pythoncom.CoUninitialize()方案三注入 JavaScript终极方案成功率 99%通过 Chrome DevTools Protocol (CDP) 远程调试端口执行 JSimport websocket import json import requests class ElectronCDPClient: 通过 Chrome DevTools Protocol 与 Electron 通信 def __init__(self, debug_port9222): self.debug_port debug_port self.ws None def connect(self): 连接到 Electron 的调试端口 # 首先获取可调试的页面列表 response requests.get(fhttp://localhost:{self.debug_port}/json) pages response.json() if pages: # 连接第一个页面的 WebSocket ws_url pages[0][webSocketDebuggerUrl] self.ws websocket.create_connection(ws_url) return True return False def execute_js(self, script: str): 在 Electron 中执行 JavaScript msg { id: 1, method: Runtime.evaluate, params: { expression: script, returnByValue: True } } self.ws.send(json.dumps(msg)) result json.loads(self.ws.recv()) return result def get_all_text(self): 获取页面所有文本内容 return self.execute_js(document.body.innerText) def get_input_value(self, selectortextarea, [contenteditabletrue]): 获取输入框内容 js_code f (() {{ const el document.querySelector({selector}); if (!el) return null; return el.value || el.innerText || el.textContent; }})() return self.execute_js(js_code) def set_input_value(self, text: str, selectortextarea, [contenteditabletrue]): 设置输入框内容 js_code f (() {{ const el document.querySelector({selector}); if (!el) return false; // 设置值 if (el.tagName TEXTAREA || el.tagName INPUT) {{ el.value {json.dumps(text)}; }} else {{ el.innerText {json.dumps(text)}; }} // 触发 input 事件 el.dispatchEvent(new Event(input, {{ bubbles: true }})); return true; }})() return self.execute_js(js_code)启动 Electron 时需开启调试端口# 命令行参数 trae.exe --remote-debugging-port9222或在electron.app.commandLine.appendSwitch中设置app.commandLine.appendSwitch(remote-debugging-port, 9222);4. 实际测试结果以 Trae、VS Code 为例方法TraeVS CodeCursorAtomCodeUIA 获取文本块✅ 大部分✅ 支持好✅ 支持好✅ 支持好UIA 获取编辑框值⚠️ 部分Monaco 是 Canvas⚠️ Monaco 不行⚠️ Monaco 不行⚠️ Monaco 不行MSAA 文本✅ 有限✅ 支持✅ 支持✅ 支持CDP JS 注入✅ 完美✅ 完美✅ 完美✅ 完美剪贴板 模拟输入✅ 可行✅ 可行✅ 可行✅ 可行5. 针对 Monaco Editor 的特殊处理现代 AI AgentTrae、VS Code、Cursor普遍使用 Monaco Editor它是 Canvas 渲染的UIA 无法直接获取文本。解决方案通过 CDP 操作 Monacodef get_monaco_content(client: ElectronCDPClient): 获取 Monaco Editor 的内容 js_code (() { // 获取所有 Monaco Editor 实例 const editors monaco.editor.getEditors(); if (!editors.length) return null; const editor editors[0]; // 取第一个 return { value: editor.getValue(), selection: editor.getSelection(), language: editor.getModel().getLanguageId() }; })() return client.execute_js(js_code) def set_monaco_content(client: ElectronCDPClient, text: str): 设置 Monaco Editor 的内容 js_code f (() {{ const editors monaco.editor.getEditors(); if (!editors.length) return false; const editor editors[0]; const model editor.getModel(); // 替换全部内容 model.setValue({json.dumps(text)}); return true; }})() return client.execute_js(js_code)获取 AI 对话面板内容def get_ai_chat_content(client: ElectronCDPClient): 获取 AI 对话面板的内容 js_code (() { // Trae/Cursor 对话面板选择器根据实际 DOM 结构调整 const selectors [ .chat-message, // 通用 .ai-response, // Trae [data-testidchat-message], // VS Code .copilot-chat-message, // Copilot ]; const messages []; for (const sel of selectors) { document.querySelectorAll(sel).forEach(el { messages.push({ text: el.innerText, html: el.innerHTML }); }); } return messages; })() return client.execute_js(js_code)6. 群星Star项目的推荐方案class StarObserver: 星体观察器 - 多层次获取 Electron 内容 def __init__(self, hwnd: int, debug_port: int 9222): self.hwnd hwnd self.debug_port debug_port self.cdp_client None self._init_cdp() def _init_cdp(self): 尝试初始化 CDP 连接 try: self.cdp_client ElectronCDPClient(self.debug_port) self.cdp_client.connect() except: self.cdp_client None def capture_starlight(self) - dict: 捕获星光 - 多层次获取内容 result { text_blocks: [], # 文本块UIA 获取 input_content: None, # 输入框内容 ai_responses: [], # AI 回复 monaco_content: None, # Monaco Editor 内容 method: unknown, # 实际使用的方法 } # 第一层CDP最精确 if self.cdp_client: try: result[ai_responses] get_ai_chat_content(self.cdp_client) result[monaco_content] get_monaco_content(self.cdp_client) result[method] cdp return result except: pass # 第二层UIA try: uia_result get_electron_text_uia(self.hwnd) result.update(uia_result) result[method] uia return result except: pass # 第三层模拟输入 全选复制最后手段 try: import pyautogui import pyperclip win32gui.SetForegroundWindow(self.hwnd) time.sleep(0.1) pyautogui.hotkey(ctrl, a) time.sleep(0.05) pyautogui.hotkey(ctrl, c) time.sleep(0.05) result[text_blocks] [pyperclip.paste()] result[method] clipboard except: pass return result7. 结论可以拿到句柄和内容但要分层处理窗口句柄✅ 100% 可以获取文本内容静态渲染文本✅ UIA 可以获取Monaco Editor⚠️ 需要 CDP JavaScript 注入AI 对话内容⚠️ 需要 CDP 或 DOM 选择器最佳方案CDP 远程调试 UIA 作为 fallback关键前提需要启动 Electron 应用时加上--remote-debugging-port9222参数