From ddef8bec1c52780734e781ae65278347a6f822d4 Mon Sep 17 00:00:00 2001 From: tzt <14718231+flying-travel@user.noreply.gitee.com> Date: Tue, 1 Sep 2026 23:41:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(v3):=20T29=20token=20=E7=BA=A7=E6=B5=81?= =?UTF-8?q?=E5=BC=8F=E8=BE=93=E5=87=BA=EF=BC=88SSE=20=E6=B5=81=E5=BC=8F?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=20+=20delta=20=E4=BA=8B=E4=BB=B6=20+=20?= =?UTF-8?q?=E6=89=93=E5=AD=97=E6=9C=BA=E6=B8=B2=E6=9F=93=EF=BC=8CD10?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OpenAICompatChat 默认 stream=True:httpx 流式解析 OpenAI chunk, tool_calls 碎片按 index 组装(不在正文展示),include_usage 计量; 失败自动回退非流式一次(已有部分增量输出则如实抛出); 补 raise_for_status(修复流式 4xx 误入回退的缺陷) - ToolLoop 增 on_delta(签名探测兼容 2/3 参 chat_fn);_loads_json_object 宽松解析 - DeltaThrottle >=48 字符节流落 delta 事件;单模型与两级模式(含规划者)接线 - 前端:streamText 打字机渲染 + 光标动画;工具/阶段事件到达时清空归档 - 配套修复:AgentView 闭包持有 push 前原始对象导致响应式丢失、过程事件不渲染 - 测试 +7(SSE 解析/碎片组装/回退/部分失败抛出/on_delta/节流/service delta 事件), 全量 296 passed --- gateway/agent.py | 201 +++++++++++- gateway/api.py | 85 ++++- gateway/settings.py | 1 + ...zJVru.js => CollaborationView-BzBpxfYH.js} | 2 +- ...ew-BMWM9u4c.js => MetricsView-Dm03Grst.js} | 2 +- ...iew-Cm34POvM.js => ReviewView-wY3DEmtF.js} | 2 +- ...w-DMG9EXA2.js => SettingsView-B4tzUqnq.js} | 2 +- .../{index-C8Za1808.js => index-C4nTxB0s.js} | 4 +- ...{index-wqjFJqzj.css => index-rGGK-sk_.css} | 2 +- gateway/static/index.html | 4 +- router_system/tools.py | 310 ++++++++++++++++-- tests/test_streaming.py | 196 +++++++++++ ..._e50d4f25-3ac6-43f2-b2f3-8833b3150465.json | 2 +- webapp/src/views/AgentView.vue | 5 +- webapp/任务拆解与执行计划.md | 2 + webapp/实现方案_v4_模型池与工具智能体.md | 13 + 任务拆解与执行计划.md | 2 + 实现方案_v4_模型池与工具智能体.md | 13 + 18 files changed, 786 insertions(+), 62 deletions(-) rename gateway/static/assets/{CollaborationView-DHMzJVru.js => CollaborationView-BzBpxfYH.js} (98%) rename gateway/static/assets/{MetricsView-BMWM9u4c.js => MetricsView-Dm03Grst.js} (98%) rename gateway/static/assets/{ReviewView-Cm34POvM.js => ReviewView-wY3DEmtF.js} (97%) rename gateway/static/assets/{SettingsView-DMG9EXA2.js => SettingsView-B4tzUqnq.js} (99%) rename gateway/static/assets/{index-C8Za1808.js => index-C4nTxB0s.js} (94%) rename gateway/static/assets/{index-wqjFJqzj.css => index-rGGK-sk_.css} (66%) create mode 100644 tests/test_streaming.py create mode 100644 webapp/任务拆解与执行计划.md create mode 100644 webapp/实现方案_v4_模型池与工具智能体.md diff --git a/gateway/agent.py b/gateway/agent.py index 1c25169..b860a9c 100644 --- a/gateway/agent.py +++ b/gateway/agent.py @@ -35,10 +35,12 @@ AGENT_SYSTEM_PROMPT = ( "你是端云协同 LLM 系统中的智能体(Agent),正在操作用户选择的**真实项目工作目录**。" "你拥有的工具:list_dir(列目录)、read_file(读文件)、write_file(写文件/新建)、" "edit_file(精确替换编辑:old_string 须唯一匹配)、search_files(跨文件搜索内容)、" - "run_command(执行 shell 命令,仅当系统开启 allow_shell 时可用,否则不要尝试)。" + "run_command(执行 shell 命令,仅当系统开启 allow_shell 时可用,否则不要尝试)、" + "web_fetch(抓取公网 http/https 文档页面,私网地址会被拒绝)。" "像编程助手一样工作:先列目录/搜索了解项目结构,读文件核对原文后再用 edit_file 小步修改" - "(或 write_file 新建),需要时运行命令验证。任务完成或给出结论后," - "直接输出给用户的最终答复(中文,不要再调用工具)。" + "(或 write_file 新建),需要查外部资料时用 web_fetch,需要时运行命令验证。" + "任务完成或给出结论后,直接输出给用户的最终答复(中文,不要再调用工具)。" + "注意:不要反复以完全相同的参数调用同一工具——那不会带来新信息。" ) # ── 两级智能体(D7):规划者(大模型)+ 执行者(本地小模型),交接走 handoff 文档 ── @@ -92,6 +94,9 @@ class OpenAICompatChat: temperature: float = 0.3, max_tokens: int = 4096, timeout_s: float = 120.0, + stream: bool = True, + max_retries: int = 2, + retry_delay_s: float = 1.0, transport: Any = None, _client: Any = None, ): @@ -101,6 +106,9 @@ class OpenAICompatChat: self.temperature = temperature self.max_tokens = max_tokens self.timeout_s = timeout_s + self.stream = stream # D10:默认流式;解析失败自动回退非流式 + self.max_retries = max(0, int(max_retries)) # 可重试错误的重试次数(dsh llm-retry 同款) + self.retry_delay_s = max(0.0, float(retry_delay_s)) # 指数退避基数 self._transport = transport self._client = _client self._owns = _client is None @@ -120,7 +128,114 @@ class OpenAICompatChat: self._client = None async def __call__(self, messages: List[Dict[str, Any]], - tools_spec: List[Dict[str, Any]]) -> Dict[str, Any]: + tools_spec: List[Dict[str, Any]], + on_delta: Optional[Callable[[str], None]] = None) -> Dict[str, Any]: + """ToolLoop.chat_fn:默认流式(D10);流式不可用时回退非流式(带重试退避)。""" + if self.stream: + try: + return await self._stream_call(messages, tools_spec, on_delta) + except Exception: + # 已有部分增量输出则如实抛出;否则回退非流式 + if getattr(self, "_stream_partial", False): + raise + return await self._post_with_retry(messages, tools_spec) + + @staticmethod + def _is_retryable(exc: Exception) -> bool: + """可重试错误:网络传输类 / 408 / 429 / 5xx(dsh retryableCodes 同思路)。""" + import httpx + if isinstance(exc, httpx.TransportError): + return True + if isinstance(exc, httpx.HTTPStatusError): + code = exc.response.status_code + return code in (408, 429) or code >= 500 + return False + + async def _post_with_retry(self, messages: List[Dict[str, Any]], + tools_spec: List[Dict[str, Any]]) -> Dict[str, Any]: + """非流式调用 + 指数退避重试(仅针对可重试错误)。""" + for attempt in range(self.max_retries + 1): + try: + return await self._post_once(messages, tools_spec) + except Exception as exc: + if attempt >= self.max_retries or not self._is_retryable(exc): + raise + await asyncio.sleep(self.retry_delay_s * (2 ** attempt)) + + async def _stream_call(self, messages: List[Dict[str, Any]], + tools_spec: List[Dict[str, Any]], + on_delta: Optional[Callable[[str], None]]) -> Dict[str, Any]: + """流式调用:逐段转发 content 增量;tool_calls 碎片按 index 组装(不在正文展示)。""" + import json as _json + self._stream_partial = False # 每次调用前复位(防上次的标志影响本次回退判定) + body: Dict[str, Any] = { + "model": self.model, + "messages": messages, + "temperature": self.temperature, + "max_tokens": self.max_tokens, + "stream": True, + "stream_options": {"include_usage": True}, + } + if tools_spec: + body["tools"] = tools_spec + body["tool_choice"] = "auto" + headers = {"Authorization": f"Bearer {self.api_key}"} if self.api_key else {} + client = self._get_client() + content_parts: List[str] = [] + tc_slots: Dict[int, Dict[str, str]] = {} + usage: Dict[str, Any] = {} + async with client.stream("POST", f"{self.base_url}/chat/completions", + headers=headers, json=body) as resp: + resp.raise_for_status() + async for line in resp.aiter_lines(): + line = line.strip() + if not line.startswith("data:"): + continue + payload = line[5:].strip() + if payload == "[DONE]": + break + try: + obj = _json.loads(payload) + except _json.JSONDecodeError: + continue + choices = obj.get("choices") or [{}] + delta = (choices[0].get("delta") or {}) if choices else {} + piece = delta.get("content") + if piece: + self._stream_partial = True + content_parts.append(piece) + if on_delta is not None: + try: + on_delta(piece) + except Exception: + pass + for tc in delta.get("tool_calls") or []: + idx = int(tc.get("index", 0)) + slot = tc_slots.setdefault(idx, {"id": "", "name": "", "args": ""}) + if tc.get("id"): + slot["id"] = tc["id"] + fn = tc.get("function") or {} + if fn.get("name"): + slot["name"] = fn["name"] + if fn.get("arguments"): + slot["args"] += fn["arguments"] + if obj.get("usage"): + usage = obj["usage"] + content = "".join(content_parts) or None + from router_system.tools import _loads_json_object + tool_calls = [] + for idx in sorted(tc_slots): + slot = tc_slots[idx] + tool_calls.append({ + "id": slot["id"] or f"call_{idx}", + "name": slot["name"], + "arguments": _loads_json_object(slot["args"]), + }) + return {"content": content, "tool_calls": tool_calls, "usage": usage} + + async def _post_once(self, messages: List[Dict[str, Any]], + tools_spec: List[Dict[str, Any]]) -> Dict[str, Any]: + """非流式调用(回退路径)。""" body: Dict[str, Any] = { "model": self.model, "messages": messages, @@ -137,7 +252,6 @@ class OpenAICompatChat: resp.raise_for_status() data = resp.json() msg = (data.get("choices") or [{}])[0].get("message") or {} - # tool_calls 解析放这里(网关层),内核 tools.parse_tool_calls 供其他调用方复用 from router_system.tools import parse_tool_calls return { "content": msg.get("content"), @@ -232,6 +346,7 @@ class AgentService: async def run(self, info: AgentRunInfo, chat: Any, workspace_dir: str | Path, max_rounds: int = 8, token_cap: int = 0, allow_shell: bool = False, shell_timeout_s: int = 20, + allow_net: bool = True, executor_chat: Any = None, max_handoffs: int = DEFAULT_MAX_HANDOFFS, session: Optional["AgentSession"] = None, @@ -246,6 +361,7 @@ class AgentService: history = self._history_from_session(session) approval_mgr = ApprovalManager() info._approval_manager = approval_mgr # 供 /approve 端点裁决(瞬态属性) + throttle = DeltaThrottle(lambda ev: self._append_event(info, ev)) async def approval_hook(name: str, args: Dict[str, Any]) -> bool: """按策略判定;需审批则挂起等用户裁决,超时 fail-closed。""" @@ -281,16 +397,20 @@ class AgentService: info, chat, executor_chat, workspace_dir, max_rounds=max_rounds, token_cap=token_cap, allow_shell=allow_shell, shell_timeout_s=shell_timeout_s, + allow_net=allow_net, max_handoffs=max_handoffs, approval_hook=approval_hook) else: tools = WorkspaceTools(workspace_dir, allow_shell=allow_shell, - shell_timeout_s=shell_timeout_s) + shell_timeout_s=shell_timeout_s, + allow_net=allow_net) loop = ToolLoop(tools, chat, max_rounds=max_rounds, token_cap=token_cap, on_event=self._make_event_writer(info), - approval_hook=approval_hook) + approval_hook=approval_hook, + on_delta=throttle.make_cb("executor")) result = await loop.run(info.task, system=AGENT_SYSTEM_PROMPT, history=history) + throttle.flush("executor") self._apply_result(info, result) except Exception as exc: # pragma: no cover info.state = STATE_FAILED @@ -348,14 +468,15 @@ class AgentService: async def run_dual(self, info: AgentRunInfo, planner_chat: Any, executor_chat: Any, workspace_dir: str | Path, max_rounds: int = 8, token_cap: int = 0, allow_shell: bool = False, - shell_timeout_s: int = 20, + shell_timeout_s: int = 20, allow_net: bool = True, max_handoffs: int = DEFAULT_MAX_HANDOFFS, approval_hook: Optional[Callable[[str, Dict[str, Any]], Awaitable[bool]]] = None ) -> Dict[str, Any]: """大模型拆解/审查 + 小模型执行工具轮,交接状态写 handoff.json(智能体版交流文本)。""" info.mode = "dual" tools = WorkspaceTools(workspace_dir, allow_shell=allow_shell, - shell_timeout_s=shell_timeout_s) + shell_timeout_s=shell_timeout_s, allow_net=allow_net) + throttle = DeltaThrottle(lambda ev: self._append_event(info, ev)) handoff: Dict[str, Any] = { "task": info.task, "planner_model": info.model, "executor_model": info.executor_model, "workspace": info.workspace, @@ -380,13 +501,23 @@ class AgentService: async def _planner_json(user_msg: str) -> Dict[str, Any]: """调规划者并解析 JSON;解析失败回喂重试一次,再失败降级为 {}(禁止带病继续的软版本)。""" + import inspect messages = [{"role": "system", "content": PLANNER_SYSTEM_PROMPT}, {"role": "user", "content": user_msg}] content = "" for attempt in (1, 2): - resp = await planner_chat(messages, []) + # 规划者同样流式(前端弱化展示其 JSON 草稿) + try: + accepts = len(inspect.signature(planner_chat).parameters) >= 3 + except (TypeError, ValueError): + accepts = False + if accepts: + resp = await planner_chat(messages, [], throttle.make_cb("planner")) + else: + resp = await planner_chat(messages, []) _account(resp.get("usage")) content = resp.get("content") or "" + throttle.flush("planner") obj = _parse_json_loose(content) if obj: break @@ -424,7 +555,8 @@ class AgentService: token_cap=max(1, _remaining_cap()), on_event=self._make_event_writer(info), emit_final=False, - approval_hook=approval_hook) + approval_hook=approval_hook, + on_delta=throttle.make_cb("executor")) exec_result = await loop.run(instructions, system=EXECUTOR_SYSTEM_PROMPT) _account({"prompt_tokens": exec_result.get("prompt_tokens", 0), "completion_tokens": exec_result.get("completion_tokens", 0)}) @@ -587,7 +719,7 @@ def new_request_id() -> str: # ───────────────────────────────────────────────────────────────────────────── # 审批流(D9):dsh 式 allow-once / deny,fail-closed # ───────────────────────────────────────────────────────────────────────────── -READ_ONLY_TOOLS = {"list_dir", "read_file", "search_files"} +READ_ONLY_TOOLS = {"list_dir", "read_file", "search_files", "web_fetch"} def needs_approval(policy: str, tool_name: str) -> bool: @@ -599,6 +731,39 @@ def needs_approval(policy: str, tool_name: str) -> bool: return False +class DeltaThrottle: + """流式增量节流(D10):积攒超过阈值才落一条 delta 事件,防事件爆炸。""" + + THRESHOLD = 48 + + def __init__(self, append_event): + self._append = append_event # (ev: dict) -> None + self._buf: Dict[str, str] = {} + + def make_cb(self, role: str): + def cb(text: str) -> None: + self.add(role, text) + return cb + + def add(self, role: str, text: str) -> None: + buf = self._buf.get(role, "") + (text or "") + if len(buf) >= self.THRESHOLD: + self._flush(role, buf) + buf = "" + self._buf[role] = buf + + def flush(self, role: Optional[str] = None) -> None: + roles = [role] if role else list(self._buf.keys()) + for r in roles: + buf = self._buf.get(r, "") + if buf: + self._flush(r, buf) + self._buf[r] = "" + + def _flush(self, role: str, text: str) -> None: + self._append({"type": "delta", "role": role, "text": text}) + + class ApprovalManager: """单次智能体运行内的审批挂起/裁决(asyncio Event 实现,dsh 式 allow-once)。""" @@ -705,6 +870,18 @@ class SessionStore: return True return False + def rename(self, sid: str, title: str) -> Optional[AgentSession]: + """重命名会话标题(dsh session.rename 对齐)。""" + sess = self.get(sid) + if sess is None: + return None + title = (title or "").strip() + if not title: + return sess + sess.data["title"] = title[:24] + self.save(sess) + return sess + def save(self, sess: AgentSession) -> None: self._cache[sess.data["id"]] = sess self._save(sess) diff --git a/gateway/api.py b/gateway/api.py index 52edc2c..efdd760 100644 --- a/gateway/api.py +++ b/gateway/api.py @@ -8,7 +8,8 @@ v2 端点(《实现方案_v2》5.3): GET /review/queue、POST /review/{id} 人工检验 GET /metrics 含 v2 token/快路径统计 -启动:uvicorn gateway.api:app --host 0.0.0.0 --port 8000 +启动:uvicorn gateway.api:app --host 127.0.0.1 --port 8000 +(默认仅回环;如需局域网访问改 --host 0.0.0.0 并设置 GATEWAY_TRUSTED_HOSTS) """ from __future__ import annotations @@ -22,6 +23,7 @@ if _dotenv_path.exists(): load_dotenv(_dotenv_path) import asyncio +import re from pathlib import Path from typing import List, Optional @@ -38,6 +40,10 @@ from gateway.model_pool import ( get_pool, ) +# 路径参数 ID 白名单(runs/agent/sessions 的 ID 都由此系统生成; +# 拒绝任意其他字符可一并杀灭 Windows 反斜杠穿越 ../..%5C 等变体) +_ID_RE = re.compile(r"^[a-zA-Z0-9_-]{1,64}$") + # ---- v2 依赖(惰性导入,缺依赖时降级提示) ---- try: from router_system.architect import build_architect @@ -179,6 +185,19 @@ try: version="2.0.0", ) + # Web 信任围栏(dsh browser-auth 同款思路):只信任本机/显式放行的 Host, + # 防 DNS rebinding 把浏览器请求打到本网关。GATEWAY_TRUSTED_HOSTS 可覆盖("*" = 放行全部)。 + _trusted = _os.environ.get( + "GATEWAY_TRUSTED_HOSTS", + "localhost,127.0.0.1,0.0.0.0,[::1],testserver,testclient", + ) + try: + from starlette.middleware.trustedhost import TrustedHostMiddleware + app.add_middleware(TrustedHostMiddleware, + allowed_hosts=[h.strip() for h in _trusted.split(",")]) + except ImportError: # pragma: no cover + pass + # Vue SPA 静态资源(html=True:对不存在的路径 fallback 到 index.html,支持 SPA 路由) app.mount("/static", StaticFiles(directory=str(_STATIC_DIR), html=True), name="static") @@ -189,6 +208,12 @@ try: return HTMLResponse(_INDEX_PATH.read_text(encoding="utf-8")) return HTMLResponse("

端云协同 LLM 系统

请先构建前端:cd webapp && npm run build

") + def _check_id(value: str, what: str = "ID") -> str: + """校验路径参数 ID(防目录穿越/注入:仅允许系统生成的字符集)。""" + if not _ID_RE.fullmatch(value or ""): + raise HTTPException(status_code=400, detail=f"非法 {what}: {value!r}") + return value + @app.get("/health", response_model=HealthResponse, tags=["system"]) async def health(): return get_router().health() @@ -265,6 +290,7 @@ try: @app.get("/runs/{request_id}/status", tags=["v2"]) async def get_run_status(request_id: str): """查询任务当前状态(pending / running / done / failed)。""" + _check_id(request_id, "request_id") info = get_job_store().get(request_id) if info is None: raise HTTPException(status_code=404, detail=f"任务 {request_id} 不存在") @@ -302,6 +328,7 @@ try: @app.get("/runs/{request_id}/stream", tags=["v2"]) async def stream_run(request_id: str): """SSE 端点:实时推送 workspace.json 状态变化(供前端协作可视化)。""" + _check_id(request_id, "request_id") from fastapi.responses import StreamingResponse async def event_generator(): @@ -354,6 +381,7 @@ try: @app.get("/traces/{request_id}", tags=["system"]) async def get_trace(request_id: str): + _check_id(request_id, "request_id") trace = get_router().trace_store.get(request_id) if trace is None: raise HTTPException(status_code=404, detail=f"未找到请求 {request_id} 的推理链") @@ -362,6 +390,7 @@ try: # ---------------- v2:workspace / artifacts ---------------- @app.get("/runs/{request_id}/workspace", tags=["v2"]) async def get_workspace(request_id: str): + _check_id(request_id, "request_id") p = Path("runs") / request_id / "workspace.json" if not p.exists(): raise HTTPException(status_code=404, detail=f"未找到运行 {request_id}") @@ -370,7 +399,12 @@ try: @app.get("/runs/{request_id}/artifacts/{name}", tags=["v2"]) async def get_artifact(request_id: str, name: str): - p = Path("runs") / request_id / "artifacts" / name + _check_id(request_id, "request_id") + d = (Path("runs") / request_id / "artifacts").resolve() + # 工件名关押:解析后必须仍在 artifacts 目录内(防 ..\ 与绝对路径逃逸) + p = (d / name).resolve() + if p != d and d not in p.parents: + raise HTTPException(status_code=400, detail=f"非法工件名: {name!r}") if not p.exists(): raise HTTPException(status_code=404, detail=f"未找到工件 {name}") return {"name": name, "content": p.read_text(encoding="utf-8")} @@ -599,6 +633,7 @@ try: token_cap=int(agent_cfg.get("token_cap", 20000)), allow_shell=bool(agent_cfg.get("allow_shell", False)), shell_timeout_s=int(agent_cfg.get("shell_timeout_s", 20)), + allow_net=bool(agent_cfg.get("allow_net", True)), executor_chat=executor_chat, max_handoffs=int(agent_cfg.get("max_handoffs", 2)), session=session, @@ -625,6 +660,7 @@ try: @app.post("/agent/{request_id}/cancel", tags=["agent"]) async def agent_cancel(request_id: str): """停止运行中的智能体任务。""" + _check_id(request_id, "request_id") from gateway.agent import get_agent_service service = get_agent_service() info = service.get(request_id) @@ -643,6 +679,7 @@ try: @app.post("/agent/{request_id}/approve", tags=["agent"]) async def agent_approve(request_id: str, req: dict): """裁决待审批操作:{"approval_id", "allowed"}(dsh 式 allow-once / deny)。""" + _check_id(request_id, "request_id") from gateway.agent import get_agent_service info = get_agent_service().get(request_id) if info is None: @@ -678,14 +715,30 @@ try: @app.get("/agent/sessions/{sid}", tags=["agent"]) async def agent_session_detail(sid: str): + """会话详情(含轮次)。""" + _check_id(sid, "会话 ID") from gateway.agent import get_session_store sess = get_session_store().get(sid) if sess is None: raise HTTPException(status_code=404, detail=f"会话不存在: {sid}") return sess.view() + @app.patch("/agent/sessions/{sid}", tags=["agent"]) + async def agent_session_rename(sid: str, req: dict = None): + """重命名会话:{"title"}(dsh session.rename 对齐)。""" + _check_id(sid, "会话 ID") + from gateway.agent import get_session_store + title = str((req or {}).get("title") or "").strip() + if not title: + raise HTTPException(status_code=400, detail="title 不能为空") + sess = get_session_store().rename(sid, title) + if sess is None: + raise HTTPException(status_code=404, detail=f"会话不存在: {sid}") + return sess.view() + @app.delete("/agent/sessions/{sid}", tags=["agent"]) async def agent_session_delete(sid: str): + _check_id(sid, "会话 ID") from gateway.agent import get_session_store return {"ok": get_session_store().delete(sid)} @@ -733,6 +786,7 @@ try: @app.get("/agent/{request_id}/status", tags=["agent"]) async def agent_status(request_id: str): + _check_id(request_id, "request_id") from gateway.agent import get_agent_service info = get_agent_service().get(request_id) if info is None: @@ -747,12 +801,14 @@ try: @app.get("/agent/{request_id}/events", tags=["agent"]) async def agent_events(request_id: str): """完整事件列表(JSON,刷新后恢复用)。""" + _check_id(request_id, "request_id") from gateway.agent import get_agent_service return get_agent_service().read_events(request_id) @app.get("/agent/{request_id}/stream", tags=["agent"]) async def agent_stream(request_id: str): """SSE:实时推送智能体过程事件(round/tool_call/tool_result/usage/final)。""" + _check_id(request_id, "request_id") from fastapi.responses import StreamingResponse from gateway.agent import get_agent_service @@ -811,19 +867,36 @@ try: # ---------------- 模型设置(用户可调整) ---------------- @app.get("/config", tags=["settings"]) async def get_config(): - """读取当前可调整设置(小模型 / 大模型 / 管线)。""" - return settings_store().to_dict() + """读取当前可调整设置(小模型 / 大模型 / 管线)。 + + architect.api_key 打码返回(api_key_set + 前 6 位,对齐 D2 池条目语义); + 修改时留空/不传 = 保留服务端已存值。 + """ + out = settings_store().to_dict() + arch = out.get("architect") or {} + key = arch.get("api_key") or "" + arch["api_key_set"] = bool(key) + arch["api_key"] = (key[:6] + "…") if key else "" + return out @app.put("/config", tags=["settings"]) async def put_config(patch: dict): """部分更新设置并重建管线。示例: {"worker": {"backend": "openai", "base_url": "http://127.0.0.1:11434/v1", "temperature": 0.4}} + + architect.api_key 传空串 = 保留原值(与打码返回配套)。 """ + arch_patch = (patch or {}).get("architect") + if isinstance(arch_patch, dict) and not str(arch_patch.get("api_key") or "").strip(): + arch_patch.pop("api_key", None) try: merged = settings_store().update(patch) except Exception as e: raise HTTPException(status_code=400, detail=f"设置非法: {e}") rebuild_pipeline() + key = merged.get("architect", {}).get("api_key") or "" + merged["architect"]["api_key_set"] = bool(key) + merged["architect"]["api_key"] = (key[:6] + "…") if key else "" return merged @app.post("/config/reset", tags=["settings"]) @@ -1110,4 +1183,6 @@ def _maybe_enqueue(result) -> None: if __name__ == "__main__": import uvicorn - uvicorn.run("gateway.api:app", host="0.0.0.0", port=8000, reload=False) + # 默认只绑定回环地址:网关能读写工作区文件/执行命令,不宜默认暴露到局域网 + # (需要局域网访问时显式 --host 0.0.0.0,并设置 GATEWAY_TRUSTED_HOSTS 放行对应主机名) + uvicorn.run("gateway.api:app", host="127.0.0.1", port=8000, reload=False) diff --git a/gateway/settings.py b/gateway/settings.py index 1a92127..889e8d6 100644 --- a/gateway/settings.py +++ b/gateway/settings.py @@ -43,6 +43,7 @@ DEFAULTS: Dict[str, Any] = { "token_cap": 20000, # 单次智能体任务 token 熔断 "allow_shell": False, # 允许 run_command 执行 shell(默认关) "shell_timeout_s": 20, # shell 命令超时 + "allow_net": True, # 允许 web_fetch 抓取公网页面(SSRF 防护内置) "max_handoffs": 2, # 两级模式:规划者<->执行者交接轮数上限 "approval_policy": "dangerous", # 审批策略:off | dangerous(写/编辑/命令询问)| all "approval_timeout_s": 120, # 审批等待超时(超时自动拒绝) diff --git a/gateway/static/assets/CollaborationView-DHMzJVru.js b/gateway/static/assets/CollaborationView-BzBpxfYH.js similarity index 98% rename from gateway/static/assets/CollaborationView-DHMzJVru.js rename to gateway/static/assets/CollaborationView-BzBpxfYH.js index 355c723..7753f51 100644 --- a/gateway/static/assets/CollaborationView-DHMzJVru.js +++ b/gateway/static/assets/CollaborationView-BzBpxfYH.js @@ -1 +1 @@ -import{A as e,C as t,D as n,G as r,H as ee,I as i,L as a,M as o,N as s,O as c,R as l,U as u,V as d,W as te,j as f,k as p,n as ne,t as m}from"./index-C8Za1808.js";var re={class:`collab-view`},ie={class:`collab-sidebar`},ae={class:`session-list`},oe=[`onClick`],se={class:`meta`},ce={key:0,class:`stats`},h={class:`stat-grid`},g={class:`route-flow`},_={class:`collab-main`},v={key:0,class:`empty`},y={class:`section brief-section`},b={class:`brief-card`},x={class:`goal`},S={class:`tags`},C={key:0,class:`domain`},w={key:0,class:`constraints`},T={class:`section plan-section`},E={class:`plan-timeline`},D={class:`step-content`},O={class:`step-header`},k={class:`step-id`},A={class:`step-status`},j={class:`step-task`},M={key:0,class:`step-deps`},N={key:1,class:`step-artifact`},P={class:`section progress-section`},le={class:`progress-bar-wrap`},F={class:`progress-label`},I={class:`progress-bar`},L={class:`progress-steps`},R={class:`pg-icon`},z={key:0,class:`pg-note`},B={key:0,class:`section issues-section`},V={class:`issue-header`},H={class:`issue-id`},U={class:`issue-step`},W={key:0,class:`decision`},ue={key:1,class:`section archive-section`},de={class:`archive-list`},fe={key:2,class:`section deliver-section`},pe={class:`response-block`},G=m(s({__name:`CollaborationView`,setup(s){let m=ne(),G=d(m.currentId),K=d(null),q=c(()=>m.sessions.find(e=>e.requestId===G.value)??null),J=c(()=>K.value??q.value?.workspace??null);function Y(e){G.value=e,K.value=null}let X=null;function me(e){X?.close(),X=t(e),X.subscribe({onWorkspace(t){t.request_id===G.value&&(K.value=t,m.updateWorkspace(e,t))},onStatus(){m.pollStatus(e)},onDone(){m.pollStatus(e)},onError(){}})}l(()=>m.sessions,e=>{G.value&&(e.find(e=>e.requestId===G.value)||(G.value=e[0]?.requestId??null))},{deep:!0}),l(G,e=>{if(!e)return;let t=m.sessions.find(t=>t.requestId===e);t?.workspace&&(K.value=t.workspace),me(e)},{immediate:!0});function Z(e){return J.value?.progress?.find(t=>t.step===e)?.status??`pending`}function Q(e){return J.value?.progress?.find(t=>t.step===e)?.artifact??null}function $(e){return J.value?.decisions?.find(t=>t.ref===e)??null}return(t,s)=>(i(),f(`div`,re,[p(`aside`,ie,[s[6]||=p(`h3`,null,`协作会话`,-1),p(`ul`,ae,[(i(!0),f(n,null,a(ee(m).sessions,e=>(i(),f(`li`,{key:e.requestId,class:u([`session-item`,{active:e.requestId===G.value}]),onClick:t=>Y(e.requestId)},[p(`span`,null,r(e.query.slice(0,24))+r(e.query.length>24?`…`:``),1),p(`span`,se,r(e.status?.rounds_used??`?`)+` 轮 · `+r(e.status?.model_used??`—`),1)],10,oe))),128))]),q.value?(i(),f(`div`,ce,[s[4]||=p(`h4`,null,`运行统计`,-1),p(`div`,h,[s[0]||=p(`span`,null,`输入 Token`,-1),p(`b`,null,r(q.value.status?.api_input_tokens??0),1),s[1]||=p(`span`,null,`输出 Token`,-1),p(`b`,null,r(q.value.status?.api_output_tokens??0),1),s[2]||=p(`span`,null,`延迟`,-1),p(`b`,null,r(q.value.status?.latency_ms?.toFixed(0)??`—`)+` ms`,1),s[3]||=p(`span`,null,`快路径`,-1),p(`b`,null,r(q.value.status?.fast_path?`是`:`否`),1)]),s[5]||=p(`h4`,null,`路由路径`,-1),p(`div`,g,[(i(!0),f(n,null,a(q.value.status?.route??[],(e,t)=>(i(),f(`span`,{key:t,class:`route-node`},r(e),1))),128))])])):e(``,!0)]),p(`main`,_,[J.value?(i(),f(n,{key:1},[p(`section`,y,[s[8]||=p(`h2`,{class:`section-title`},`📋 Brief(任务简报)`,-1),p(`div`,b,[p(`div`,x,r(J.value.brief?.goal??`(未生成)`),1),p(`div`,S,[(i(!0),f(n,null,a(J.value.brief?.tags??[],e=>(i(),f(`span`,{key:e,class:`tag`},r(e),1))),128)),J.value.brief?.domain?(i(),f(`span`,C,r(J.value.brief.domain),1)):e(``,!0)]),J.value.brief?.constraints?.length?(i(),f(`ul`,w,[(i(!0),f(n,null,a(J.value.brief.constraints,(e,t)=>(i(),f(`li`,{key:t},r(e),1))),128))])):e(``,!0)])]),p(`section`,T,[s[12]||=p(`h2`,{class:`section-title`},`📌 Plan(执行计划)`,-1),p(`div`,E,[(i(!0),f(n,null,a(J.value.plan??[],t=>(i(),f(`div`,{key:t.id,class:u([`plan-step`,Z(t.id)])},[s[11]||=p(`div`,{class:`step-dot`},null,-1),p(`div`,D,[p(`div`,O,[p(`span`,k,r(t.id),1),p(`span`,A,r(Z(t.id)),1)]),p(`p`,j,r(t.task),1),t.deps.length?(i(),f(`div`,M,[s[9]||=o(` 依赖:`,-1),(i(!0),f(n,null,a(t.deps,e=>(i(),f(`span`,{key:e,class:`dep`},r(e),1))),128))])):e(``,!0),Q(t.id)?(i(),f(`div`,N,[p(`details`,null,[s[10]||=p(`summary`,null,`📄 工件内容`,-1),p(`pre`,null,r(Q(t.id)),1)])])):e(``,!0)])],2))),128))])]),p(`section`,P,[s[13]||=p(`h2`,{class:`section-title`},`🔄 进度(实时)`,-1),p(`div`,le,[p(`div`,F,` 第 `+r(J.value.meta.round)+` / `+r(J.value.meta.rounds_cap)+` 轮 `,1),p(`div`,I,[p(`div`,{class:`progress-fill`,style:te({width:`${J.value.meta.round/J.value.meta.rounds_cap*100}%`})},null,4)])]),p(`div`,L,[(i(!0),f(n,null,a(J.value.progress??[],t=>(i(),f(`div`,{key:t.step,class:u([`pg-step`,t.status])},[p(`span`,R,r(t.status===`done`?`✅`:t.status===`running`?`⏳`:`⭕`),1),p(`span`,null,r(t.step),1),t.note?(i(),f(`span`,z,r(t.note),1)):e(``,!0)],2))),128))])]),J.value.issues?.length?(i(),f(`section`,B,[s[15]||=p(`h2`,{class:`section-title`},`⚠️ Issues & 裁决`,-1),(i(!0),f(n,null,a(J.value.issues,t=>(i(),f(`div`,{key:t.id,class:`issue-card`},[p(`div`,V,[p(`span`,H,r(t.id),1),p(`span`,U,`Step: `+r(t.step),1)]),p(`p`,null,r(t.description),1),$(t.id)?(i(),f(`div`,W,[s[14]||=p(`strong`,null,`Architect 裁决:`,-1),o(r($(t.id)?.reply),1)])):e(``,!0)]))),128))])):e(``,!0),J.value.archive?.length?(i(),f(`section`,ue,[s[16]||=p(`h2`,{class:`section-title`},`📦 Archive(摘要归档)`,-1),p(`ul`,de,[(i(!0),f(n,null,a(J.value.archive,(e,t)=>(i(),f(`li`,{key:t},r(e),1))),128))])])):e(``,!0),J.value.meta.state===`done`?(i(),f(`section`,fe,[s[17]||=p(`h2`,{class:`section-title`},`🎉 交付`,-1),p(`div`,pe,[p(`pre`,null,r(q.value?.status?.response??`(无内容)`),1)])])):e(``,!0)],64)):(i(),f(`div`,v,[...s[7]||=[p(`p`,null,`从左侧选择一个会话,或在「对话」页发起新提问。`,-1),p(`p`,null,`协作过程通过 SSE 实时推送,无需刷新。`,-1)]]))])]))}}),[[`__scopeId`,`data-v-556e88a4`]]);export{G as default}; \ No newline at end of file +import{A as e,C as t,D as n,G as r,H as ee,I as i,L as a,M as o,N as s,O as c,R as l,U as u,V as d,W as te,j as f,k as p,n as ne,t as m}from"./index-C4nTxB0s.js";var re={class:`collab-view`},ie={class:`collab-sidebar`},ae={class:`session-list`},oe=[`onClick`],se={class:`meta`},ce={key:0,class:`stats`},h={class:`stat-grid`},g={class:`route-flow`},_={class:`collab-main`},v={key:0,class:`empty`},y={class:`section brief-section`},b={class:`brief-card`},x={class:`goal`},S={class:`tags`},C={key:0,class:`domain`},w={key:0,class:`constraints`},T={class:`section plan-section`},E={class:`plan-timeline`},D={class:`step-content`},O={class:`step-header`},k={class:`step-id`},A={class:`step-status`},j={class:`step-task`},M={key:0,class:`step-deps`},N={key:1,class:`step-artifact`},P={class:`section progress-section`},le={class:`progress-bar-wrap`},F={class:`progress-label`},I={class:`progress-bar`},L={class:`progress-steps`},R={class:`pg-icon`},z={key:0,class:`pg-note`},B={key:0,class:`section issues-section`},V={class:`issue-header`},H={class:`issue-id`},U={class:`issue-step`},W={key:0,class:`decision`},ue={key:1,class:`section archive-section`},de={class:`archive-list`},fe={key:2,class:`section deliver-section`},pe={class:`response-block`},G=m(s({__name:`CollaborationView`,setup(s){let m=ne(),G=d(m.currentId),K=d(null),q=c(()=>m.sessions.find(e=>e.requestId===G.value)??null),J=c(()=>K.value??q.value?.workspace??null);function Y(e){G.value=e,K.value=null}let X=null;function me(e){X?.close(),X=t(e),X.subscribe({onWorkspace(t){t.request_id===G.value&&(K.value=t,m.updateWorkspace(e,t))},onStatus(){m.pollStatus(e)},onDone(){m.pollStatus(e)},onError(){}})}l(()=>m.sessions,e=>{G.value&&(e.find(e=>e.requestId===G.value)||(G.value=e[0]?.requestId??null))},{deep:!0}),l(G,e=>{if(!e)return;let t=m.sessions.find(t=>t.requestId===e);t?.workspace&&(K.value=t.workspace),me(e)},{immediate:!0});function Z(e){return J.value?.progress?.find(t=>t.step===e)?.status??`pending`}function Q(e){return J.value?.progress?.find(t=>t.step===e)?.artifact??null}function $(e){return J.value?.decisions?.find(t=>t.ref===e)??null}return(t,s)=>(i(),f(`div`,re,[p(`aside`,ie,[s[6]||=p(`h3`,null,`协作会话`,-1),p(`ul`,ae,[(i(!0),f(n,null,a(ee(m).sessions,e=>(i(),f(`li`,{key:e.requestId,class:u([`session-item`,{active:e.requestId===G.value}]),onClick:t=>Y(e.requestId)},[p(`span`,null,r(e.query.slice(0,24))+r(e.query.length>24?`…`:``),1),p(`span`,se,r(e.status?.rounds_used??`?`)+` 轮 · `+r(e.status?.model_used??`—`),1)],10,oe))),128))]),q.value?(i(),f(`div`,ce,[s[4]||=p(`h4`,null,`运行统计`,-1),p(`div`,h,[s[0]||=p(`span`,null,`输入 Token`,-1),p(`b`,null,r(q.value.status?.api_input_tokens??0),1),s[1]||=p(`span`,null,`输出 Token`,-1),p(`b`,null,r(q.value.status?.api_output_tokens??0),1),s[2]||=p(`span`,null,`延迟`,-1),p(`b`,null,r(q.value.status?.latency_ms?.toFixed(0)??`—`)+` ms`,1),s[3]||=p(`span`,null,`快路径`,-1),p(`b`,null,r(q.value.status?.fast_path?`是`:`否`),1)]),s[5]||=p(`h4`,null,`路由路径`,-1),p(`div`,g,[(i(!0),f(n,null,a(q.value.status?.route??[],(e,t)=>(i(),f(`span`,{key:t,class:`route-node`},r(e),1))),128))])])):e(``,!0)]),p(`main`,_,[J.value?(i(),f(n,{key:1},[p(`section`,y,[s[8]||=p(`h2`,{class:`section-title`},`📋 Brief(任务简报)`,-1),p(`div`,b,[p(`div`,x,r(J.value.brief?.goal??`(未生成)`),1),p(`div`,S,[(i(!0),f(n,null,a(J.value.brief?.tags??[],e=>(i(),f(`span`,{key:e,class:`tag`},r(e),1))),128)),J.value.brief?.domain?(i(),f(`span`,C,r(J.value.brief.domain),1)):e(``,!0)]),J.value.brief?.constraints?.length?(i(),f(`ul`,w,[(i(!0),f(n,null,a(J.value.brief.constraints,(e,t)=>(i(),f(`li`,{key:t},r(e),1))),128))])):e(``,!0)])]),p(`section`,T,[s[12]||=p(`h2`,{class:`section-title`},`📌 Plan(执行计划)`,-1),p(`div`,E,[(i(!0),f(n,null,a(J.value.plan??[],t=>(i(),f(`div`,{key:t.id,class:u([`plan-step`,Z(t.id)])},[s[11]||=p(`div`,{class:`step-dot`},null,-1),p(`div`,D,[p(`div`,O,[p(`span`,k,r(t.id),1),p(`span`,A,r(Z(t.id)),1)]),p(`p`,j,r(t.task),1),t.deps.length?(i(),f(`div`,M,[s[9]||=o(` 依赖:`,-1),(i(!0),f(n,null,a(t.deps,e=>(i(),f(`span`,{key:e,class:`dep`},r(e),1))),128))])):e(``,!0),Q(t.id)?(i(),f(`div`,N,[p(`details`,null,[s[10]||=p(`summary`,null,`📄 工件内容`,-1),p(`pre`,null,r(Q(t.id)),1)])])):e(``,!0)])],2))),128))])]),p(`section`,P,[s[13]||=p(`h2`,{class:`section-title`},`🔄 进度(实时)`,-1),p(`div`,le,[p(`div`,F,` 第 `+r(J.value.meta.round)+` / `+r(J.value.meta.rounds_cap)+` 轮 `,1),p(`div`,I,[p(`div`,{class:`progress-fill`,style:te({width:`${J.value.meta.round/J.value.meta.rounds_cap*100}%`})},null,4)])]),p(`div`,L,[(i(!0),f(n,null,a(J.value.progress??[],t=>(i(),f(`div`,{key:t.step,class:u([`pg-step`,t.status])},[p(`span`,R,r(t.status===`done`?`✅`:t.status===`running`?`⏳`:`⭕`),1),p(`span`,null,r(t.step),1),t.note?(i(),f(`span`,z,r(t.note),1)):e(``,!0)],2))),128))])]),J.value.issues?.length?(i(),f(`section`,B,[s[15]||=p(`h2`,{class:`section-title`},`⚠️ Issues & 裁决`,-1),(i(!0),f(n,null,a(J.value.issues,t=>(i(),f(`div`,{key:t.id,class:`issue-card`},[p(`div`,V,[p(`span`,H,r(t.id),1),p(`span`,U,`Step: `+r(t.step),1)]),p(`p`,null,r(t.description),1),$(t.id)?(i(),f(`div`,W,[s[14]||=p(`strong`,null,`Architect 裁决:`,-1),o(r($(t.id)?.reply),1)])):e(``,!0)]))),128))])):e(``,!0),J.value.archive?.length?(i(),f(`section`,ue,[s[16]||=p(`h2`,{class:`section-title`},`📦 Archive(摘要归档)`,-1),p(`ul`,de,[(i(!0),f(n,null,a(J.value.archive,(e,t)=>(i(),f(`li`,{key:t},r(e),1))),128))])])):e(``,!0),J.value.meta.state===`done`?(i(),f(`section`,fe,[s[17]||=p(`h2`,{class:`section-title`},`🎉 交付`,-1),p(`div`,pe,[p(`pre`,null,r(q.value?.status?.response??`(无内容)`),1)])])):e(``,!0)],64)):(i(),f(`div`,v,[...s[7]||=[p(`p`,null,`从左侧选择一个会话,或在「对话」页发起新提问。`,-1),p(`p`,null,`协作过程通过 SSE 实时推送,无需刷新。`,-1)]]))])]))}}),[[`__scopeId`,`data-v-556e88a4`]]);export{G as default}; \ No newline at end of file diff --git a/gateway/static/assets/MetricsView-BMWM9u4c.js b/gateway/static/assets/MetricsView-Dm03Grst.js similarity index 98% rename from gateway/static/assets/MetricsView-BMWM9u4c.js rename to gateway/static/assets/MetricsView-Dm03Grst.js index d5f37bb..5c10cd5 100644 --- a/gateway/static/assets/MetricsView-BMWM9u4c.js +++ b/gateway/static/assets/MetricsView-Dm03Grst.js @@ -1 +1 @@ -import{A as e,D as t,G as n,I as r,L as i,N as a,O as o,P as s,V as c,W as l,j as u,k as d,s as f,t as p}from"./index-C8Za1808.js";var m={class:`metrics-view`},h={key:0,class:`loading`},g={key:1,class:`error`},_={class:`card-grid`},v={class:`metric-card`},y={class:`kv-list`},b={class:`metric-card`},x={class:`kv-list`},S={key:0,class:`metric-card highlight`},C={class:`kv-list`},w={key:0},T={key:1},E={key:1,class:`metric-card`},D={class:`by-model`},O={class:`mono`},k={key:2,class:`metric-card review-card`},A={class:`review-stats`},j={class:`stat-item`},M={class:`stat-num`},N={class:`stat-item`},P={class:`stat-num`},F={key:0,class:`progress-wrap`},I={class:`review-rate`},L={class:`raw-json`},R=p(a({__name:`MetricsView`,setup(a){let p=c(null),R=c(!1),z=c(``),B=o(()=>p.value?.v2?.by_model||null);async function V(){R.value=!0,z.value=``;try{p.value=await f()}catch(e){z.value=e instanceof Error?e.message:`指标加载失败,请检查后端服务`}finally{R.value=!1}}return s(V),(a,o)=>(r(),u(`div`,m,[d(`header`,{class:`metrics-header`},[o[0]||=d(`h2`,null,`系统指标`,-1),d(`button`,{class:`refresh`,onClick:V},`🔄 刷新`)]),R.value?(r(),u(`div`,h,`加载中…`)):z.value?(r(),u(`div`,g,n(z.value),1)):p.value?(r(),u(t,{key:2},[d(`div`,_,[d(`div`,v,[o[1]||=d(`h3`,null,`路由器(v1)`,-1),d(`div`,y,[(r(!0),u(t,null,i(p.value.router,(e,i)=>(r(),u(t,{key:i},[d(`span`,null,n(i),1),d(`b`,null,n(e),1)],64))),128))])]),d(`div`,b,[o[2]||=d(`h3`,null,`缓存`,-1),d(`div`,x,[(r(!0),u(t,null,i(p.value.cache,(e,i)=>(r(),u(t,{key:i},[d(`span`,null,n(i),1),d(`b`,null,n(e),1)],64))),128))])]),p.value.v2?(r(),u(`div`,S,[o[3]||=d(`h3`,null,`协作管线(v2)`,-1),d(`div`,C,[(r(!0),u(t,null,i(p.value.v2,(i,a)=>(r(),u(t,{key:a},[a===`by_model`?e(``,!0):(r(),u(`span`,w,n(a),1)),a===`by_model`?e(``,!0):(r(),u(`b`,T,n(i),1))],64))),128))])])):e(``,!0),B.value&&Object.keys(B.value).length?(r(),u(`div`,E,[o[5]||=d(`h3`,null,`按模型分账(token / 成本)`,-1),d(`table`,D,[o[4]||=d(`thead`,null,[d(`tr`,null,[d(`th`,null,`模型`),d(`th`,null,`次数`),d(`th`,null,`入`),d(`th`,null,`出`),d(`th`,null,`成本 $`)])],-1),d(`tbody`,null,[(r(!0),u(t,null,i(B.value,(e,t)=>(r(),u(`tr`,{key:t},[d(`td`,O,n(t),1),d(`td`,null,n(e.requests),1),d(`td`,null,n(e.input_tokens),1),d(`td`,null,n(e.output_tokens),1),d(`td`,null,n(e.cost_est_usd),1)]))),128))])]),o[6]||=d(`p`,{class:`hint`},`单价来自模型池条目($/1M tokens);经典设置下的模型成本不计入。`,-1)])):e(``,!0),p.value.review?(r(),u(`div`,k,[o[9]||=d(`h3`,null,`人工检验`,-1),d(`div`,A,[d(`div`,j,[d(`span`,M,n(p.value.review.pending),1),o[7]||=d(`span`,{class:`stat-label`},`待审核`,-1)]),d(`div`,N,[d(`span`,P,n(p.value.review.total),1),o[8]||=d(`span`,{class:`stat-label`},`总提交`,-1)])]),p.value.review.total>0?(r(),u(`div`,F,[d(`div`,{class:`reviewed-bar`,style:l({width:`${(p.value.review.total-p.value.review.pending)/p.value.review.total*100}%`})},null,4)])):e(``,!0),d(`p`,I,` 通过率: `+n(((p.value.review.total-p.value.review.pending)/p.value.review.total*100).toFixed(1))+`% `,1)])):e(``,!0)]),d(`details`,L,[o[10]||=d(`summary`,null,`原始 JSON`,-1),d(`pre`,null,n(JSON.stringify(p.value,null,2)),1)])],64)):e(``,!0)]))}}),[[`__scopeId`,`data-v-8b237097`]]);export{R as default}; \ No newline at end of file +import{A as e,D as t,G as n,I as r,L as i,N as a,O as o,P as s,V as c,W as l,j as u,k as d,s as f,t as p}from"./index-C4nTxB0s.js";var m={class:`metrics-view`},h={key:0,class:`loading`},g={key:1,class:`error`},_={class:`card-grid`},v={class:`metric-card`},y={class:`kv-list`},b={class:`metric-card`},x={class:`kv-list`},S={key:0,class:`metric-card highlight`},C={class:`kv-list`},w={key:0},T={key:1},E={key:1,class:`metric-card`},D={class:`by-model`},O={class:`mono`},k={key:2,class:`metric-card review-card`},A={class:`review-stats`},j={class:`stat-item`},M={class:`stat-num`},N={class:`stat-item`},P={class:`stat-num`},F={key:0,class:`progress-wrap`},I={class:`review-rate`},L={class:`raw-json`},R=p(a({__name:`MetricsView`,setup(a){let p=c(null),R=c(!1),z=c(``),B=o(()=>p.value?.v2?.by_model||null);async function V(){R.value=!0,z.value=``;try{p.value=await f()}catch(e){z.value=e instanceof Error?e.message:`指标加载失败,请检查后端服务`}finally{R.value=!1}}return s(V),(a,o)=>(r(),u(`div`,m,[d(`header`,{class:`metrics-header`},[o[0]||=d(`h2`,null,`系统指标`,-1),d(`button`,{class:`refresh`,onClick:V},`🔄 刷新`)]),R.value?(r(),u(`div`,h,`加载中…`)):z.value?(r(),u(`div`,g,n(z.value),1)):p.value?(r(),u(t,{key:2},[d(`div`,_,[d(`div`,v,[o[1]||=d(`h3`,null,`路由器(v1)`,-1),d(`div`,y,[(r(!0),u(t,null,i(p.value.router,(e,i)=>(r(),u(t,{key:i},[d(`span`,null,n(i),1),d(`b`,null,n(e),1)],64))),128))])]),d(`div`,b,[o[2]||=d(`h3`,null,`缓存`,-1),d(`div`,x,[(r(!0),u(t,null,i(p.value.cache,(e,i)=>(r(),u(t,{key:i},[d(`span`,null,n(i),1),d(`b`,null,n(e),1)],64))),128))])]),p.value.v2?(r(),u(`div`,S,[o[3]||=d(`h3`,null,`协作管线(v2)`,-1),d(`div`,C,[(r(!0),u(t,null,i(p.value.v2,(i,a)=>(r(),u(t,{key:a},[a===`by_model`?e(``,!0):(r(),u(`span`,w,n(a),1)),a===`by_model`?e(``,!0):(r(),u(`b`,T,n(i),1))],64))),128))])])):e(``,!0),B.value&&Object.keys(B.value).length?(r(),u(`div`,E,[o[5]||=d(`h3`,null,`按模型分账(token / 成本)`,-1),d(`table`,D,[o[4]||=d(`thead`,null,[d(`tr`,null,[d(`th`,null,`模型`),d(`th`,null,`次数`),d(`th`,null,`入`),d(`th`,null,`出`),d(`th`,null,`成本 $`)])],-1),d(`tbody`,null,[(r(!0),u(t,null,i(B.value,(e,t)=>(r(),u(`tr`,{key:t},[d(`td`,O,n(t),1),d(`td`,null,n(e.requests),1),d(`td`,null,n(e.input_tokens),1),d(`td`,null,n(e.output_tokens),1),d(`td`,null,n(e.cost_est_usd),1)]))),128))])]),o[6]||=d(`p`,{class:`hint`},`单价来自模型池条目($/1M tokens);经典设置下的模型成本不计入。`,-1)])):e(``,!0),p.value.review?(r(),u(`div`,k,[o[9]||=d(`h3`,null,`人工检验`,-1),d(`div`,A,[d(`div`,j,[d(`span`,M,n(p.value.review.pending),1),o[7]||=d(`span`,{class:`stat-label`},`待审核`,-1)]),d(`div`,N,[d(`span`,P,n(p.value.review.total),1),o[8]||=d(`span`,{class:`stat-label`},`总提交`,-1)])]),p.value.review.total>0?(r(),u(`div`,F,[d(`div`,{class:`reviewed-bar`,style:l({width:`${(p.value.review.total-p.value.review.pending)/p.value.review.total*100}%`})},null,4)])):e(``,!0),d(`p`,I,` 通过率: `+n(((p.value.review.total-p.value.review.pending)/p.value.review.total*100).toFixed(1))+`% `,1)])):e(``,!0)]),d(`details`,L,[o[10]||=d(`summary`,null,`原始 JSON`,-1),d(`pre`,null,n(JSON.stringify(p.value,null,2)),1)])],64)):e(``,!0)]))}}),[[`__scopeId`,`data-v-8b237097`]]);export{R as default}; \ No newline at end of file diff --git a/gateway/static/assets/ReviewView-Cm34POvM.js b/gateway/static/assets/ReviewView-wY3DEmtF.js similarity index 97% rename from gateway/static/assets/ReviewView-Cm34POvM.js rename to gateway/static/assets/ReviewView-wY3DEmtF.js index f11f4e9..ca34b8a 100644 --- a/gateway/static/assets/ReviewView-Cm34POvM.js +++ b/gateway/static/assets/ReviewView-wY3DEmtF.js @@ -1 +1 @@ -import{A as e,D as t,E as n,G as r,I as i,L as a,M as o,N as s,O as c,P as l,U as u,V as d,f,j as p,k as m,t as h,v as g,z as _}from"./index-C8Za1808.js";var v={class:`review-view`},y={class:`review-header`},b={class:`controls`},x={key:0,class:`loading`},S={key:1,class:`error`},C={key:2,class:`queue-list`},w={key:0,class:`empty`},T={class:`card-header`},E={class:`card-id`},D={class:`tags`},O={class:`date`},k={class:`query-block`},A={class:`response-block`},j={key:0,class:`actions`},M=[`onUpdate:modelValue`],N={class:`btn-row`},P=[`onClick`],F=[`onClick`],I={key:1,class:`correction`},L=h(s({__name:`ReviewView`,setup(s){let h=d([]),L=d(!1),R=d(``),z=d(`pending`),B=d({}),V=c(()=>z.value===`all`?h.value:h.value.filter(e=>e.verdict===z.value));async function H(){L.value=!0,R.value=``;try{h.value=await f()}catch(e){R.value=e instanceof Error?e.message:String(e)}finally{L.value=!1}}async function U(e,t){try{await g(e,t,B.value[e]||void 0),await H()}catch(e){R.value=e instanceof Error?e.message:String(e)}}return l(H),(s,c)=>(i(),p(`div`,v,[m(`header`,y,[c[4]||=m(`h2`,null,`人工检验队列`,-1),m(`div`,b,[m(`button`,{class:u({active:z.value===`all`}),onClick:c[0]||=e=>z.value=`all`},`全部`,2),m(`button`,{class:u({active:z.value===`pending`}),onClick:c[1]||=e=>z.value=`pending`},`待审核`,2),m(`button`,{class:u({active:z.value===`approved`}),onClick:c[2]||=e=>z.value=`approved`},`已通过`,2),m(`button`,{class:u({active:z.value===`rejected`}),onClick:c[3]||=e=>z.value=`rejected`},`已拒绝`,2),m(`button`,{class:`refresh-btn`,onClick:H},`🔄 刷新`)])]),L.value?(i(),p(`div`,x,`加载中…`)):R.value?(i(),p(`div`,S,r(R.value),1)):(i(),p(`div`,C,[V.value.length?e(``,!0):(i(),p(`div`,w,`队列为空。`)),(i(!0),p(t,null,a(V.value,s=>(i(),p(`div`,{key:s.id,class:`review-card`},[m(`div`,T,[m(`span`,E,`#`+r(s.id),1),m(`span`,{class:u([`verdict-badge`,s.verdict])},r(s.verdict),3),m(`span`,D,[(i(!0),p(t,null,a(s.tags,e=>(i(),p(`span`,{key:e,class:`tag`},r(e),1))),128))]),m(`span`,O,r(s.created_at),1)]),m(`div`,k,[c[5]||=m(`strong`,null,`Query:`,-1),o(r(s.query),1)]),m(`div`,A,[c[6]||=m(`strong`,null,`Response:`,-1),m(`pre`,null,r(s.response),1)]),s.verdict===`pending`?(i(),p(`div`,j,[_(m(`textarea`,{"onUpdate:modelValue":e=>B.value[s.id]=e,placeholder:`修正意见(可选)`,rows:`2`},null,8,M),[[n,B.value[s.id]]]),m(`div`,N,[m(`button`,{class:`approve`,onClick:e=>U(s.id,`approved`)},`✅ 通过`,8,P),m(`button`,{class:`reject`,onClick:e=>U(s.id,`rejected`)},`❌ 拒绝`,8,F)])])):s.correction?(i(),p(`div`,I,[c[7]||=m(`strong`,null,`修正:`,-1),o(r(s.correction),1)])):e(``,!0)]))),128))]))]))}}),[[`__scopeId`,`data-v-d5b38f1c`]]);export{L as default}; \ No newline at end of file +import{A as e,D as t,E as n,G as r,I as i,L as a,M as o,N as s,O as c,P as l,U as u,V as d,f,j as p,k as m,t as h,v as g,z as _}from"./index-C4nTxB0s.js";var v={class:`review-view`},y={class:`review-header`},b={class:`controls`},x={key:0,class:`loading`},S={key:1,class:`error`},C={key:2,class:`queue-list`},w={key:0,class:`empty`},T={class:`card-header`},E={class:`card-id`},D={class:`tags`},O={class:`date`},k={class:`query-block`},A={class:`response-block`},j={key:0,class:`actions`},M=[`onUpdate:modelValue`],N={class:`btn-row`},P=[`onClick`],F=[`onClick`],I={key:1,class:`correction`},L=h(s({__name:`ReviewView`,setup(s){let h=d([]),L=d(!1),R=d(``),z=d(`pending`),B=d({}),V=c(()=>z.value===`all`?h.value:h.value.filter(e=>e.verdict===z.value));async function H(){L.value=!0,R.value=``;try{h.value=await f()}catch(e){R.value=e instanceof Error?e.message:String(e)}finally{L.value=!1}}async function U(e,t){try{await g(e,t,B.value[e]||void 0),await H()}catch(e){R.value=e instanceof Error?e.message:String(e)}}return l(H),(s,c)=>(i(),p(`div`,v,[m(`header`,y,[c[4]||=m(`h2`,null,`人工检验队列`,-1),m(`div`,b,[m(`button`,{class:u({active:z.value===`all`}),onClick:c[0]||=e=>z.value=`all`},`全部`,2),m(`button`,{class:u({active:z.value===`pending`}),onClick:c[1]||=e=>z.value=`pending`},`待审核`,2),m(`button`,{class:u({active:z.value===`approved`}),onClick:c[2]||=e=>z.value=`approved`},`已通过`,2),m(`button`,{class:u({active:z.value===`rejected`}),onClick:c[3]||=e=>z.value=`rejected`},`已拒绝`,2),m(`button`,{class:`refresh-btn`,onClick:H},`🔄 刷新`)])]),L.value?(i(),p(`div`,x,`加载中…`)):R.value?(i(),p(`div`,S,r(R.value),1)):(i(),p(`div`,C,[V.value.length?e(``,!0):(i(),p(`div`,w,`队列为空。`)),(i(!0),p(t,null,a(V.value,s=>(i(),p(`div`,{key:s.id,class:`review-card`},[m(`div`,T,[m(`span`,E,`#`+r(s.id),1),m(`span`,{class:u([`verdict-badge`,s.verdict])},r(s.verdict),3),m(`span`,D,[(i(!0),p(t,null,a(s.tags,e=>(i(),p(`span`,{key:e,class:`tag`},r(e),1))),128))]),m(`span`,O,r(s.created_at),1)]),m(`div`,k,[c[5]||=m(`strong`,null,`Query:`,-1),o(r(s.query),1)]),m(`div`,A,[c[6]||=m(`strong`,null,`Response:`,-1),m(`pre`,null,r(s.response),1)]),s.verdict===`pending`?(i(),p(`div`,j,[_(m(`textarea`,{"onUpdate:modelValue":e=>B.value[s.id]=e,placeholder:`修正意见(可选)`,rows:`2`},null,8,M),[[n,B.value[s.id]]]),m(`div`,N,[m(`button`,{class:`approve`,onClick:e=>U(s.id,`approved`)},`✅ 通过`,8,P),m(`button`,{class:`reject`,onClick:e=>U(s.id,`rejected`)},`❌ 拒绝`,8,F)])])):s.correction?(i(),p(`div`,I,[c[7]||=m(`strong`,null,`修正:`,-1),o(r(s.correction),1)])):e(``,!0)]))),128))]))]))}}),[[`__scopeId`,`data-v-d5b38f1c`]]);export{L as default}; \ No newline at end of file diff --git a/gateway/static/assets/SettingsView-DMG9EXA2.js b/gateway/static/assets/SettingsView-B4tzUqnq.js similarity index 99% rename from gateway/static/assets/SettingsView-DMG9EXA2.js rename to gateway/static/assets/SettingsView-B4tzUqnq.js index ac9f3b4..b59e102 100644 --- a/gateway/static/assets/SettingsView-DMG9EXA2.js +++ b/gateway/static/assets/SettingsView-B4tzUqnq.js @@ -1 +1 @@ -import{A as e,B as t,D as n,E as r,F as i,G as a,I as o,L as s,M as c,N as ee,O as l,P as te,S as ne,T as u,U as d,V as f,W as re,_ as ie,a as ae,b as oe,c as se,d as ce,g as le,h as ue,i as de,j as p,k as m,l as fe,m as pe,o as me,p as he,r as ge,t as h,u as _e,w as ve,x as ye,y as be,z as g}from"./index-C8Za1808.js";var xe={class:`settings-view`},Se={class:`settings-section`},Ce={class:`section-body`},we={class:`role-bar`},Te=[`onUpdate:modelValue`],Ee=[`value`],De={key:0,class:`pool-table`},Oe={class:`mono`},ke=[`onUpdate:modelValue`,`onChange`],Ae={class:`row-actions`},je=[`disabled`,`onClick`],Me=[`onClick`],Ne=[`onClick`],Pe={key:1,class:`no-models`},Fe={key:3,class:`pool-edit`},Ie={class:`pool-edit-title`},Le={class:`form-grid`},Re={class:`field`},ze={class:`field`},Be={class:`field`},Ve={class:`field`},He=[`disabled`],Ue={id:`pool-model-options`},We=[`value`],Ge={key:0,class:`field full-width`},Ke={key:1,class:`field`},qe={class:`field`},Je={class:`field`},Ye={class:`field`},Xe={class:`field`},Ze={class:`pool-edit-actions`},Qe={class:`checkbox-label`},$e=[`disabled`],et={class:`settings-section`},tt={class:`section-title`},nt={class:`title-right`},rt={class:`section-body`},it={class:`server-control-bar`},at={class:`server-info`},ot={class:`model-chip`},st={class:`model-chip port-chip`},ct={class:`model-chip pid-chip`},lt={key:1,class:`server-idle`},ut={class:`server-actions`},dt=[`disabled`],ft=[`disabled`],pt={key:0,class:`error-msg llama-error`},mt={class:`local-models`},ht={class:`local-models-header`},gt=[`disabled`],_t={key:0,class:`no-models`},vt={key:1,class:`model-list`},yt=[`onClick`],bt={class:`model-item-name`},xt={class:`model-item-size`},St={class:`download-section`},Ct={class:`download-form`},wt=[`disabled`],Tt=[`disabled`],Et={key:0,class:`progress-wrap`},Dt={class:`progress-bar`},Ot={class:`progress-info`},kt={key:1,class:`error-msg download-error`},At={key:2,class:`done-msg`},jt={class:`form-grid`,style:{"margin-top":`16px`}},Mt={class:`field full-width`},Nt={key:0,class:`field full-width`},Pt=[`disabled`],Ft={class:`input-row`},It=[`placeholder`],Lt={key:1,class:`field full-width`},Rt=[`disabled`],zt=[`value`],Bt=[`value`],Vt={key:3,class:`field-hint warn`},Ht={key:2,class:`field`},Ut={class:`field`},Wt={class:`field`},Gt={class:`field`},Kt={class:`settings-section`},qt={class:`section-title`},Jt={class:`title-right`},Yt={class:`section-body`},Xt={class:`form-grid`},Zt={class:`field full-width`},Qt=[`disabled`],$t={class:`field full-width`},en={class:`field full-width`},tn=[`disabled`],nn=[`value`],rn={key:0,class:`field-hint warn`},an={class:`settings-section`},on={class:`section-body`},sn={class:`form-grid`},cn={class:`field full-width`},ln={class:`checkbox-label`},un={class:`field`},dn={class:`field`},fn={class:`field full-width`},pn={class:`actions`},mn=[`disabled`],hn=[`disabled`],_=h(ee({__name:`SettingsView`,setup(ee){let h=f(!1),_=f(``),v=f(null),gn=[{key:`architect`,label:`🧠 Architect(决策/终审)`},{key:`worker`,label:`🔧 Worker(实现/自验证)`},{key:`agent`,label:`🤖 Agent(智能体工具)`}],_n={local:`本地/零成本`,budget:`低价 API`,premium:`旗舰 API`},y=f({roles:{architect:``,worker:``,agent:``},entries:[]}),b=t({architect:``,worker:``,agent:``}),x=f(null),S=f(!1),C=f(``),w=f(``),T=f(!1),E=f(!1),D=f(!1),vn=f([]),yn=l(()=>y.value.entries.filter(e=>e.enabled));function bn(e){return _n[e]??e}async function xn(){try{y.value=await se(),b.architect=y.value.roles.architect||``,b.worker=y.value.roles.worker||``,b.agent=y.value.roles.agent||``}catch{}}async function Sn(){try{y.value=await ue({...b}),v.value={ok:!0,msg:`✅ 角色已更新,管线已重建`}}catch(e){v.value={ok:!1,msg:`❌ 角色指派失败:`+(e?.response?.data?.detail||e?.message||e)},await xn()}setTimeout(()=>v.value=null,3e3)}function Cn(){S.value=!0,x.value={name:``,tier:`budget`,backend:`openai`,base_url:``,model:``,api_key:``,price_in:.1,price_out:.1,temperature:.3,max_tokens:4096,enabled:!0}}function wn(e){S.value=!1,x.value={...e,api_key:``}}async function Tn(){if(x.value){E.value=!0;try{y.value=await ye(x.value),x.value=null,v.value={ok:!0,msg:`✅ 模型条目已保存`}}catch(e){v.value={ok:!1,msg:`❌ 保存失败:`+(e?.response?.data?.detail||e?.message||e)}}finally{E.value=!1,setTimeout(()=>v.value=null,3e3)}}}async function En(e){confirm(`删除模型条目「${e.name}」?相关角色指派会一并清空。`)&&(y.value=await ge(e.id))}async function Dn(e){y.value=await ye({...e,api_key:``})}async function On(e){C.value=e.id,w.value=``;try{let t=await be(e.id);T.value=t.ok,w.value=t.ok?`✅ ${e.name} 连接正常`:`❌ ${e.name}: ${t.detail||`连接失败`}`}catch(e){T.value=!1,w.value=`❌ `+(e?.message||String(e))}finally{C.value=``}}async function kn(){if(x.value){D.value=!0;try{let e;e=!S.value&&x.value.id?await ce(x.value.id):x.value.backend===`mock`?{models:[{id:`mock`,name:`mock(内置模拟)`}]}:await _e(x.value.backend||`openai`,x.value.base_url||``,x.value.api_key||``),e.error?(T.value=!1,w.value=e.error,vn.value=[]):vn.value=e.models||[]}finally{D.value=!1}}}let O=f({running:!1}),k=f(!1),A=f(!1),j=f([]),M=f(!1),N=f(``),P=f(!1),F=f(``),I=f(0),L=f(``),An=f(``),jn=f(``),R=f(null),Mn=f(``),z=f(``),Nn=f(!1),B=null,V=f([]),H=f([]),U=t({worker:!1,architect:!1}),W=t({worker:``,architect:``}),G=t({worker:!1,architect:!1}),K=t({worker:null,architect:null}),q=t({worker:``,architect:``}),J=[{id:`deepseek-v4-flash`,name:`deepseek-v4-flash(推荐)`},{id:`deepseek-v4-pro`,name:`deepseek-v4-pro(推理模式)`},{id:`deepseek-coder`,name:`deepseek-coder`},{id:`gpt-4o-mini`,name:`gpt-4o-mini`},{id:`gpt-4o`,name:`gpt-4o`},{id:`claude-3-5-sonnet-20241022`,name:`claude-3.5-sonnet`},{id:`qwen-plus`,name:`qwen-plus`},{id:`qwen-max`,name:`qwen-max`}],Y=f(null),X=t({worker:{backend:`mock`,model:``,base_url:``,port:8901,temperature:.3,max_fix_attempts:2,code_timeout_s:10},architect:{model:`deepseek-v4-flash`,base_url:`https://api.deepseek.com`,api_key:``},pipeline:{fast_path:!0,rounds_cap:6,api_token_cap:8e3,breach_policy:`architect_do`}}),Pn=l(()=>X.worker.backend===`llama_server`?`http://127.0.0.1:${X.worker.port}/v1`:`http://127.0.0.1:11434/v1`),Fn=l(()=>Y.value?JSON.stringify(X)!==JSON.stringify(Y.value):!1);function In(e){return e>=1e9?(e/1e9).toFixed(1)+` GB`:e>=1e6?(e/1e6).toFixed(1)+` MB`:e>=1e3?(e/1e3).toFixed(0)+` KB`:e+` B`}async function Ln(){try{let e=await me();return O.value=e,e}catch{return O.value={running:!1},{running:!1}}}async function Z(){M.value=!0;try{j.value=await fe()}catch{j.value=[]}finally{M.value=!1}}async function Rn(){if(!X.worker.model){alert(`请先从上方「本地模型」列表中选择一个模型,再启动服务`);return}k.value=!0;try{let e=await le(X.worker.model,X.worker.port,99,4096);O.value=e,e.running&&(X.worker.backend=`llama_server`,X.worker.base_url=`http://127.0.0.1:${e.port}/v1`,await Z(),await Q())}catch(e){O.value={running:!1,error:String(e?.message||e)}}finally{k.value=!1}}async function zn(){A.value=!0;try{await ie(),O.value={running:!1}}catch{O.value={running:!1}}finally{A.value=!1}}function Bn(e){N.value=e.id,X.worker.model=e.id}function Vn(){F.value.trim()&&(z.value=``,Nn.value=!1,I.value=0,L.value=``,An.value=``,jn.value=`0 B`,R.value=null,P.value=!0,de(F.value.trim()).then(e=>{if(e.error){z.value=e.error,P.value=!1;return}if(e.done){Hn(e);return}B=ne(F.value.trim()),B.subscribe({onProgress:Hn,onDone:e=>{Hn(e),B?.close(),B=null}})}))}function Hn(e){I.value=Math.round(e.progress_pct),L.value=e.speed,An.value=e.eta,jn.value=In(e.downloaded_bytes),R.value=e.total_bytes?In(e.total_bytes):null,Mn.value=e.dest,e.done&&(P.value=!1,e.error?z.value=e.error:(Nn.value=!0,Z()))}async function Un(){W.worker=``,V.value=[],X.worker.backend!==`mock`&&await Q()}async function Wn(){W.architect=``,H.value=[],await Gn()}async function Q(){if(X.worker.backend!==`mock`){U.worker=!0,W.worker=``;try{let e=await _e(X.worker.backend,X.worker.base_url,``);e.error?X.worker.backend===`llama_server`?W.worker=`💡 llama-server 未启动,请先点击上方「启动服务」`:W.worker=e.error||`连接失败`:V.value=e.models||[]}catch{W.worker=`获取模型列表失败`}finally{U.worker=!1}}}async function Gn(){if(U.architect=!0,W.architect=``,!X.architect.base_url){H.value=[...J],U.architect=!1;return}try{let e=await _e(`openai`,X.architect.base_url,X.architect.api_key||``);e.error?(W.architect=e.error,H.value=[...J]):(e.models||[]).length>0?H.value=e.models||[]:H.value=[...J]}catch{W.architect=`获取模型列表失败`,H.value=[...J]}finally{U.architect=!1}}async function Kn(){if(X.worker.backend!==`mock`){G.worker=!0,K.worker=null,q.worker=``;try{let e=await he(X.worker.backend,X.worker.base_url,``);K.worker=e.ok,e.ok||(q.worker=e.detail||`连接失败`)}catch(e){K.worker=!1,q.worker=e?.message||String(e)}finally{G.worker=!1}}}async function qn(){if(!X.architect.base_url){K.architect=!1,q.architect=`请先填写 API 端点`;return}G.architect=!0,K.architect=null,q.architect=``;try{let e=await he(`openai`,X.architect.base_url,X.architect.api_key||``);K.architect=e.ok,e.ok||(q.architect=e.detail||`连接失败`)}catch(e){K.architect=!1,q.architect=e?.message||String(e)}finally{G.architect=!1}}function $(e,t){if(t)for(let n of Object.keys(e))t[n]!==void 0&&(typeof e[n]==`object`&&typeof t[n]==`object`&&e[n]!==null?$(e[n],t[n]):e[n]=t[n])}async function Jn(){_.value=``;try{let[e,t]=await Promise.all([ae(),Ln()]);O.value=t,xn(),e.worker&&$(X.worker,e.worker),e.architect&&$(X.architect,e.architect),e.pipeline&&$(X.pipeline,e.pipeline),Y.value=JSON.parse(JSON.stringify(X)),await Z(),H.value=[...J],X.worker.backend!==`mock`&&Q(),X.worker.model&&(N.value=X.worker.model)}catch(e){_.value=`加载配置失败:`+(e?.message||String(e))}}async function Yn(){h.value=!0,v.value=null;try{let e=JSON.parse(JSON.stringify(X));e.architect.api_key||delete e.architect.api_key;let t=await oe(e);$(X.worker,t.worker||{}),$(X.architect,t.architect||{}),$(X.pipeline,t.pipeline||{}),Y.value=JSON.parse(JSON.stringify(X)),v.value={ok:!0,msg:`✅ 设置已保存,管线已重建`},setTimeout(()=>v.value=null,3e3)}catch(e){v.value={ok:!1,msg:`❌ 保存失败:`+(e?.message||String(e))}}finally{h.value=!1}}async function Xn(){if(confirm(`确定恢复默认设置?`)){h.value=!0,v.value=null;try{let e=await pe();$(X.worker,e.worker||{}),$(X.architect,e.architect||{}),$(X.pipeline,e.pipeline||{}),Y.value=JSON.parse(JSON.stringify(X)),V.value=[],H.value=[...J],K.worker=null,K.architect=null,v.value={ok:!0,msg:`✅ 已恢复默认设置`},setTimeout(()=>v.value=null,3e3)}catch(e){v.value={ok:!1,msg:`❌ 重置失败:`+(e?.message||String(e))}}finally{h.value=!1}}}return te(Jn),i(()=>{B?.close()}),(t,i)=>(o(),p(`div`,xe,[i[68]||=m(`header`,{class:`settings-header`},[m(`h2`,null,`⚙️ 模型设置`),m(`p`,{class:`subtitle`},`配置小模型(Worker)与大模型(Architect)参数,保存后实时生效`)],-1),m(`section`,Se,[m(`div`,{class:`section-title`},[i[29]||=m(`span`,null,`🗄️ 模型池(多价位异构模型)`,-1),m(`div`,{class:`title-right`},[m(`button`,{class:`btn-refresh`,onClick:Cn},`+ 添加模型`)])]),m(`div`,Ce,[m(`div`,we,[(o(),p(n,null,s(gn,e=>m(`div`,{class:`role-item`,key:e.key},[m(`label`,null,a(e.label),1),g(m(`select`,{"onUpdate:modelValue":t=>b[e.key]=t,onChange:Sn},[i[30]||=m(`option`,{value:``},`经典设置(下方表单)`,-1),(o(!0),p(n,null,s(yn.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name),9,Ee))),128))],40,Te),[[u,b[e.key]]])])),64))]),i[44]||=m(`p`,{class:`role-hint`},` 按价位组织模型:本地 llama.cpp 为零成本档,低价 API 干批量活,旗舰 API 做决策—— 随时切换,保存后管线自动重建。 `,-1),y.value.entries.length?(o(),p(`table`,De,[i[31]||=m(`thead`,null,[m(`tr`,null,[m(`th`,null,`名称`),m(`th`,null,`档位`),m(`th`,null,`后端`),m(`th`,null,`模型`),m(`th`,null,`单价 $/1M(入/出)`),m(`th`,null,`启用`),m(`th`,null,`操作`)])],-1),m(`tbody`,null,[(o(!0),p(n,null,s(y.value.entries,e=>(o(),p(`tr`,{key:e.id},[m(`td`,null,a(e.name),1),m(`td`,null,[m(`span`,{class:d([`tier-badge`,`tier-`+e.tier])},a(bn(e.tier)),3)]),m(`td`,null,a(e.backend),1),m(`td`,Oe,a(e.model||`—`),1),m(`td`,null,a(e.price_in)+` / `+a(e.price_out),1),m(`td`,null,[g(m(`input`,{type:`checkbox`,"onUpdate:modelValue":t=>e.enabled=t,onChange:t=>Dn(e)},null,40,ke),[[ve,e.enabled]])]),m(`td`,Ae,[m(`button`,{class:`btn-refresh`,disabled:C.value===e.id,onClick:t=>On(e)},a(C.value===e.id?`…`:`测试`),9,je),m(`button`,{class:`btn-refresh`,onClick:t=>wn(e)},`编辑`,8,Me),m(`button`,{class:`btn-refresh danger`,onClick:t=>En(e)},`删除`,8,Ne)])]))),128))])])):(o(),p(`div`,Pe,` 池为空——可添加本地 llama.cpp 模型(零成本档)、低价 API、旗舰 API 等,随时指派给 Architect / Worker / Agent。 `)),w.value?(o(),p(`div`,{key:2,class:d([`field-hint`,T.value?`ok`:`warn`])},a(w.value),3)):e(``,!0),x.value?(o(),p(`div`,Fe,[m(`div`,Ie,a(S.value?`添加模型`:`编辑模型`),1),m(`div`,Le,[m(`div`,Re,[i[32]||=m(`label`,null,`名称`,-1),g(m(`input`,{"onUpdate:modelValue":i[0]||=e=>x.value.name=e,placeholder:`如:DeepSeek 旗舰 / 本地 Qwen4B`},null,512),[[r,x.value.name]])]),m(`div`,ze,[i[34]||=m(`label`,null,`档位`,-1),g(m(`select`,{"onUpdate:modelValue":i[1]||=e=>x.value.tier=e},[...i[33]||=[m(`option`,{value:`local`},`local(本地 / 零边际成本)`,-1),m(`option`,{value:`budget`},`budget(低价 API)`,-1),m(`option`,{value:`premium`},`premium(旗舰 API)`,-1)]],512),[[u,x.value.tier]])]),m(`div`,Be,[i[36]||=m(`label`,null,`后端`,-1),g(m(`select`,{"onUpdate:modelValue":i[2]||=e=>x.value.backend=e},[...i[35]||=[m(`option`,{value:`openai`},`openai / 兼容 API`,-1),m(`option`,{value:`llama_server`},`llama_server(内置本地)`,-1),m(`option`,{value:`mock`},`mock(模拟)`,-1)]],512),[[u,x.value.backend]])]),m(`div`,Ve,[m(`label`,null,[i[37]||=c(` 模型 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:D.value,onClick:kn},a(D.value?`…`:`🔄 刷新列表`),9,He)]),g(m(`input`,{"onUpdate:modelValue":i[3]||=e=>x.value.model=e,list:`pool-model-options`,placeholder:`模型名`},null,512),[[r,x.value.model]]),m(`datalist`,Ue,[(o(!0),p(n,null,s(vn.value,e=>(o(),p(`option`,{key:e.id,value:e.id},null,8,We))),128))])]),x.value.backend===`mock`?e(``,!0):(o(),p(`div`,Ge,[i[38]||=m(`label`,null,`API 地址`,-1),g(m(`input`,{"onUpdate:modelValue":i[4]||=e=>x.value.base_url=e,placeholder:`https://api.deepseek.com 或 http://127.0.0.1:8901/v1`},null,512),[[r,x.value.base_url]])])),x.value.backend===`openai`?(o(),p(`div`,Ke,[m(`label`,null,`API Key`+a(x.value.api_key_set?`(已设置,留空保留)`:``),1),g(m(`input`,{"onUpdate:modelValue":i[5]||=e=>x.value.api_key=e,type:`password`,autocomplete:`off`,placeholder:`sk-…`},null,512),[[r,x.value.api_key]])])):e(``,!0),m(`div`,qe,[i[39]||=m(`label`,null,`输入单价 $/1M`,-1),g(m(`input`,{"onUpdate:modelValue":i[6]||=e=>x.value.price_in=e,type:`number`,min:`0`,step:`0.01`},null,512),[[r,x.value.price_in,void 0,{number:!0}]])]),m(`div`,Je,[i[40]||=m(`label`,null,`输出单价 $/1M`,-1),g(m(`input`,{"onUpdate:modelValue":i[7]||=e=>x.value.price_out=e,type:`number`,min:`0`,step:`0.01`},null,512),[[r,x.value.price_out,void 0,{number:!0}]])]),m(`div`,Ye,[i[41]||=m(`label`,null,`Temperature`,-1),g(m(`input`,{"onUpdate:modelValue":i[8]||=e=>x.value.temperature=e,type:`number`,min:`0`,max:`2`,step:`0.05`},null,512),[[r,x.value.temperature,void 0,{number:!0}]])]),m(`div`,Xe,[i[42]||=m(`label`,null,`Max Tokens`,-1),g(m(`input`,{"onUpdate:modelValue":i[9]||=e=>x.value.max_tokens=e,type:`number`,min:`256`,max:`32768`},null,512),[[r,x.value.max_tokens,void 0,{number:!0}]])])]),m(`div`,Ze,[m(`label`,Qe,[g(m(`input`,{type:`checkbox`,"onUpdate:modelValue":i[10]||=e=>x.value.enabled=e},null,512),[[ve,x.value.enabled]]),i[43]||=c(` 启用 `,-1)]),m(`button`,{class:`btn-primary`,disabled:E.value,onClick:Tn},a(E.value?`保存中…`:`保存条目`),9,$e),m(`button`,{class:`btn-secondary`,onClick:i[11]||=e=>x.value=null},`取消`)])])):e(``,!0)])]),m(`section`,et,[m(`div`,tt,[i[45]||=m(`span`,null,`🔧 小模型 (Worker · 本地 llama.cpp)`,-1),m(`div`,nt,[m(`span`,{class:d([`server-badge`,O.value.running?`badge-running`:`badge-stopped`])},a(O.value.running?`● 运行中`:`○ 已停止`),3)])]),m(`div`,rt,[m(`div`,it,[m(`div`,at,[O.value.running?(o(),p(n,{key:0},[m(`span`,ot,a(O.value.model?.split(/[/\\]/).pop()),1),m(`span`,st,`:`+a(O.value.port),1),m(`span`,ct,`PID `+a(O.value.pid),1)],64)):(o(),p(`span`,lt,`llama-server 未运行 — 点击「启动服务」即可启用`))]),m(`div`,ut,[O.value.running?(o(),p(`button`,{key:1,class:`btn-stop`,disabled:k.value||A.value,onClick:zn},a(A.value?`停止中…`:`■ 停止服务`),9,ft)):(o(),p(`button`,{key:0,class:`btn-start`,disabled:k.value||A.value,onClick:Rn},a(k.value?`启动中…`:`▶ 启动服务`),9,dt))])]),O.value.error?(o(),p(`div`,pt,a(O.value.error),1)):e(``,!0),m(`div`,mt,[m(`div`,ht,[m(`span`,null,`📁 本地模型 (`+a(j.value.length)+`)`,1),m(`button`,{class:`btn-refresh`,disabled:M.value,onClick:Z},a(M.value?`…`:`🔄`),9,gt)]),j.value.length===0&&!M.value?(o(),p(`div`,_t,` 暂无本地模型,请下载或放置 .gguf 文件到 models/ 目录 `)):(o(),p(`div`,vt,[(o(!0),p(n,null,s(j.value,e=>(o(),p(`div`,{key:e.id,class:d([`model-item`,N.value===e.id?`selected`:``]),onClick:t=>Bn(e)},[m(`span`,bt,a(e.name),1),m(`span`,xt,a(e.size_mb)+` MB`,1)],10,yt))),128))]))]),m(`div`,St,[i[46]||=m(`div`,{class:`download-header`},`⬇️ 下载模型`,-1),m(`div`,Ct,[g(m(`input`,{"onUpdate:modelValue":i[12]||=e=>F.value=e,class:`download-input`,placeholder:`HuggingFace 路径或直链,如:Qwen/Qwen3-4B-GGUF/Qwen3-4B-Q4_K_M.gguf`,disabled:P.value},null,8,wt),[[r,F.value]]),m(`button`,{class:`btn-download`,disabled:P.value||!F.value.trim(),onClick:Vn},a(P.value?I.value+`%`:`下载`),9,Tt)]),P.value?(o(),p(`div`,Et,[m(`div`,Dt,[m(`div`,{class:`progress-fill`,style:re({width:I.value+`%`})},null,4)]),m(`div`,Ot,[m(`span`,null,a(L.value),1),m(`span`,null,a(An.value),1),m(`span`,null,a(jn.value)+`/`+a(R.value||`?`),1)])])):e(``,!0),z.value?(o(),p(`div`,kt,a(z.value),1)):e(``,!0),Nn.value&&!z.value?(o(),p(`div`,At,` ✅ 下载完成:`+a(Mn.value),1)):e(``,!0)]),m(`div`,jt,[m(`div`,Mt,[i[48]||=m(`label`,null,`后端类型`,-1),g(m(`select`,{"onUpdate:modelValue":i[13]||=e=>X.worker.backend=e,onChange:Un},[...i[47]||=[m(`option`,{value:`mock`},`mock(模拟,不真实调用)`,-1),m(`option`,{value:`llama_server`},`llama_server(内置本地服务,推荐)`,-1),m(`option`,{value:`openai`},`openai / 兼容 API(Ollama 等)`,-1)]],544),[[u,X.worker.backend]])]),X.worker.backend===`mock`?e(``,!0):(o(),p(`div`,Nt,[m(`label`,null,[i[49]||=c(` API 地址 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:G.worker,onClick:Kn},a(G.worker?`…`:`🔗 连接测试`),9,Pt)]),m(`div`,Ft,[g(m(`input`,{"onUpdate:modelValue":i[14]||=e=>X.worker.base_url=e,placeholder:Pn.value,onBlur:Un},null,40,It),[[r,X.worker.base_url]]),K.worker===null?e(``,!0):(o(),p(`span`,{key:0,class:d([`ping-badge`,K.worker?`ping-ok`:`ping-err`])},a(K.worker?`✅ 正常`:`❌ `+q.worker),3))])])),X.worker.backend===`mock`?e(``,!0):(o(),p(`div`,Lt,[m(`label`,null,[i[50]||=c(` 模型 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:U.worker,onClick:Q},a(U.worker?`…`:`🔄 刷新列表`),9,Rt)]),X.worker.backend===`llama_server`?g((o(),p(`select`,{key:0,"onUpdate:modelValue":i[15]||=e=>X.worker.model=e},[i[51]||=m(`option`,{value:``,disabled:``},`—— 从本地模型中选择 ——`,-1),(o(!0),p(n,null,s(j.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name),9,zt))),128))],512)),[[u,X.worker.model]]):X.worker.backend===`openai`?g((o(),p(`select`,{key:1,"onUpdate:modelValue":i[16]||=e=>X.worker.model=e},[i[52]||=m(`option`,{value:``,disabled:``},`—— 从 API 获取 ——`,-1),(o(!0),p(n,null,s(V.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name||e.id),9,Bt))),128))],512)),[[u,X.worker.model]]):g((o(),p(`input`,{key:2,"onUpdate:modelValue":i[17]||=e=>X.worker.model=e,placeholder:`输入模型名称…`},null,512)),[[r,X.worker.model]]),W.worker?(o(),p(`span`,Vt,a(W.worker),1)):e(``,!0)])),X.worker.backend===`llama_server`?(o(),p(`div`,Ht,[i[53]||=m(`label`,null,`端口`,-1),g(m(`input`,{"onUpdate:modelValue":i[18]||=e=>X.worker.port=e,type:`number`,min:`1`,max:`65535`},null,512),[[r,X.worker.port,void 0,{number:!0}]])])):e(``,!0),m(`div`,Ut,[i[54]||=m(`label`,null,`Temperature`,-1),g(m(`input`,{"onUpdate:modelValue":i[19]||=e=>X.worker.temperature=e,type:`number`,min:`0`,max:`2`,step:`0.05`},null,512),[[r,X.worker.temperature,void 0,{number:!0}]])]),m(`div`,Wt,[i[55]||=m(`label`,null,`最大修复轮次`,-1),g(m(`input`,{"onUpdate:modelValue":i[20]||=e=>X.worker.max_fix_attempts=e,type:`number`,min:`0`,max:`10`},null,512),[[r,X.worker.max_fix_attempts,void 0,{number:!0}]])]),m(`div`,Gt,[i[56]||=m(`label`,null,`代码执行超时 (秒)`,-1),g(m(`input`,{"onUpdate:modelValue":i[21]||=e=>X.worker.code_timeout_s=e,type:`number`,min:`1`,max:`300`},null,512),[[r,X.worker.code_timeout_s,void 0,{number:!0}]])])])])]),m(`section`,Kt,[m(`div`,qt,[i[57]||=m(`span`,null,`🧠 大模型 (Architect · API 云端)`,-1),m(`div`,Jt,[K.architect===null?e(``,!0):(o(),p(`span`,{key:0,class:d([`ping-badge`,K.architect?`ping-ok`:`ping-err`])},a(K.architect?`✅ 已连接`:`❌ `+q.architect),3))])]),m(`div`,Yt,[m(`div`,Xt,[m(`div`,Zt,[m(`label`,null,[i[58]||=c(` API 端点 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:G.architect,onClick:qn},a(G.architect?`…`:`🔗 连接测试`),9,Qt)]),g(m(`input`,{"onUpdate:modelValue":i[22]||=e=>X.architect.base_url=e,placeholder:`https://api.deepseek.com`,onBlur:Wn},null,544),[[r,X.architect.base_url]])]),m(`div`,$t,[i[59]||=m(`label`,null,`API Key(保存在本地 config/settings.json,不入代码库;优先级高于 .env)`,-1),g(m(`input`,{"onUpdate:modelValue":i[23]||=e=>X.architect.api_key=e,type:`password`,placeholder:`sk-xxxxxxxxxxxxxxxx`,autocomplete:`off`},null,512),[[r,X.architect.api_key]])]),m(`div`,en,[m(`label`,null,[i[60]||=c(` 模型 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:U.architect,onClick:Gn},a(U.architect?`…`:`🔄 刷新列表`),9,tn)]),g(m(`select`,{"onUpdate:modelValue":i[24]||=e=>X.architect.model=e,class:`model-select`},[i[61]||=m(`option`,{value:``,disabled:``},`—— 从 API 获取模型列表 ——`,-1),(o(!0),p(n,null,s(H.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name||e.id),9,nn))),128))],512),[[u,X.architect.model]]),W.architect?(o(),p(`span`,rn,a(W.architect),1)):e(``,!0)])])])]),m(`section`,an,[i[67]||=m(`div`,{class:`section-title`},[m(`span`,null,`⚙️ 协作管线 (Pipeline)`)],-1),m(`div`,on,[m(`div`,sn,[m(`div`,cn,[m(`label`,ln,[g(m(`input`,{type:`checkbox`,"onUpdate:modelValue":i[25]||=e=>X.pipeline.fast_path=e},null,512),[[ve,X.pipeline.fast_path]]),i[62]||=c(` 启用快路径(简单查询跳过本地模型,直接由大模型回答,省 API 费用) `,-1)])]),m(`div`,un,[i[63]||=m(`label`,null,`最大协作轮次`,-1),g(m(`input`,{"onUpdate:modelValue":i[26]||=e=>X.pipeline.rounds_cap=e,type:`number`,min:`1`,max:`20`},null,512),[[r,X.pipeline.rounds_cap,void 0,{number:!0}]])]),m(`div`,dn,[i[64]||=m(`label`,null,`API Token 熔断上限`,-1),g(m(`input`,{"onUpdate:modelValue":i[27]||=e=>X.pipeline.api_token_cap=e,type:`number`,min:`100`,max:`100000`},null,512),[[r,X.pipeline.api_token_cap,void 0,{number:!0}]])]),m(`div`,fn,[i[66]||=m(`label`,null,`超限策略`,-1),g(m(`select`,{"onUpdate:modelValue":i[28]||=e=>X.pipeline.breach_policy=e},[...i[65]||=[m(`option`,{value:`architect_do`},`architect_do(超限交给大模型处理,推荐)`,-1),m(`option`,{value:`local_only`},`local_only(强制留在本地小模型)`,-1)]],512),[[u,X.pipeline.breach_policy]])])])])]),m(`div`,pn,[m(`button`,{class:`btn-primary`,disabled:h.value||!Fn.value,onClick:Yn},a(h.value?`保存中…`:`💾 保存设置`),9,mn),m(`button`,{class:`btn-secondary`,disabled:h.value,onClick:Xn},` 🔁 恢复默认 `,8,hn)]),v.value?(o(),p(`div`,{key:0,class:d([`toast`,v.value.ok?`toast-ok`:`toast-err`])},a(v.value.msg),3)):e(``,!0)]))}}),[[`__scopeId`,`data-v-7b21dc2a`]]);export{_ as default}; \ No newline at end of file +import{A as e,B as t,D as n,E as r,F as i,G as a,I as o,L as s,M as c,N as ee,O as l,P as te,S as ne,T as u,U as d,V as f,W as re,_ as ie,a as ae,b as oe,c as se,d as ce,g as le,h as ue,i as de,j as p,k as m,l as fe,m as pe,o as me,p as he,r as ge,t as h,u as _e,w as ve,x as ye,y as be,z as g}from"./index-C4nTxB0s.js";var xe={class:`settings-view`},Se={class:`settings-section`},Ce={class:`section-body`},we={class:`role-bar`},Te=[`onUpdate:modelValue`],Ee=[`value`],De={key:0,class:`pool-table`},Oe={class:`mono`},ke=[`onUpdate:modelValue`,`onChange`],Ae={class:`row-actions`},je=[`disabled`,`onClick`],Me=[`onClick`],Ne=[`onClick`],Pe={key:1,class:`no-models`},Fe={key:3,class:`pool-edit`},Ie={class:`pool-edit-title`},Le={class:`form-grid`},Re={class:`field`},ze={class:`field`},Be={class:`field`},Ve={class:`field`},He=[`disabled`],Ue={id:`pool-model-options`},We=[`value`],Ge={key:0,class:`field full-width`},Ke={key:1,class:`field`},qe={class:`field`},Je={class:`field`},Ye={class:`field`},Xe={class:`field`},Ze={class:`pool-edit-actions`},Qe={class:`checkbox-label`},$e=[`disabled`],et={class:`settings-section`},tt={class:`section-title`},nt={class:`title-right`},rt={class:`section-body`},it={class:`server-control-bar`},at={class:`server-info`},ot={class:`model-chip`},st={class:`model-chip port-chip`},ct={class:`model-chip pid-chip`},lt={key:1,class:`server-idle`},ut={class:`server-actions`},dt=[`disabled`],ft=[`disabled`],pt={key:0,class:`error-msg llama-error`},mt={class:`local-models`},ht={class:`local-models-header`},gt=[`disabled`],_t={key:0,class:`no-models`},vt={key:1,class:`model-list`},yt=[`onClick`],bt={class:`model-item-name`},xt={class:`model-item-size`},St={class:`download-section`},Ct={class:`download-form`},wt=[`disabled`],Tt=[`disabled`],Et={key:0,class:`progress-wrap`},Dt={class:`progress-bar`},Ot={class:`progress-info`},kt={key:1,class:`error-msg download-error`},At={key:2,class:`done-msg`},jt={class:`form-grid`,style:{"margin-top":`16px`}},Mt={class:`field full-width`},Nt={key:0,class:`field full-width`},Pt=[`disabled`],Ft={class:`input-row`},It=[`placeholder`],Lt={key:1,class:`field full-width`},Rt=[`disabled`],zt=[`value`],Bt=[`value`],Vt={key:3,class:`field-hint warn`},Ht={key:2,class:`field`},Ut={class:`field`},Wt={class:`field`},Gt={class:`field`},Kt={class:`settings-section`},qt={class:`section-title`},Jt={class:`title-right`},Yt={class:`section-body`},Xt={class:`form-grid`},Zt={class:`field full-width`},Qt=[`disabled`],$t={class:`field full-width`},en={class:`field full-width`},tn=[`disabled`],nn=[`value`],rn={key:0,class:`field-hint warn`},an={class:`settings-section`},on={class:`section-body`},sn={class:`form-grid`},cn={class:`field full-width`},ln={class:`checkbox-label`},un={class:`field`},dn={class:`field`},fn={class:`field full-width`},pn={class:`actions`},mn=[`disabled`],hn=[`disabled`],_=h(ee({__name:`SettingsView`,setup(ee){let h=f(!1),_=f(``),v=f(null),gn=[{key:`architect`,label:`🧠 Architect(决策/终审)`},{key:`worker`,label:`🔧 Worker(实现/自验证)`},{key:`agent`,label:`🤖 Agent(智能体工具)`}],_n={local:`本地/零成本`,budget:`低价 API`,premium:`旗舰 API`},y=f({roles:{architect:``,worker:``,agent:``},entries:[]}),b=t({architect:``,worker:``,agent:``}),x=f(null),S=f(!1),C=f(``),w=f(``),T=f(!1),E=f(!1),D=f(!1),vn=f([]),yn=l(()=>y.value.entries.filter(e=>e.enabled));function bn(e){return _n[e]??e}async function xn(){try{y.value=await se(),b.architect=y.value.roles.architect||``,b.worker=y.value.roles.worker||``,b.agent=y.value.roles.agent||``}catch{}}async function Sn(){try{y.value=await ue({...b}),v.value={ok:!0,msg:`✅ 角色已更新,管线已重建`}}catch(e){v.value={ok:!1,msg:`❌ 角色指派失败:`+(e?.response?.data?.detail||e?.message||e)},await xn()}setTimeout(()=>v.value=null,3e3)}function Cn(){S.value=!0,x.value={name:``,tier:`budget`,backend:`openai`,base_url:``,model:``,api_key:``,price_in:.1,price_out:.1,temperature:.3,max_tokens:4096,enabled:!0}}function wn(e){S.value=!1,x.value={...e,api_key:``}}async function Tn(){if(x.value){E.value=!0;try{y.value=await ye(x.value),x.value=null,v.value={ok:!0,msg:`✅ 模型条目已保存`}}catch(e){v.value={ok:!1,msg:`❌ 保存失败:`+(e?.response?.data?.detail||e?.message||e)}}finally{E.value=!1,setTimeout(()=>v.value=null,3e3)}}}async function En(e){confirm(`删除模型条目「${e.name}」?相关角色指派会一并清空。`)&&(y.value=await ge(e.id))}async function Dn(e){y.value=await ye({...e,api_key:``})}async function On(e){C.value=e.id,w.value=``;try{let t=await be(e.id);T.value=t.ok,w.value=t.ok?`✅ ${e.name} 连接正常`:`❌ ${e.name}: ${t.detail||`连接失败`}`}catch(e){T.value=!1,w.value=`❌ `+(e?.message||String(e))}finally{C.value=``}}async function kn(){if(x.value){D.value=!0;try{let e;e=!S.value&&x.value.id?await ce(x.value.id):x.value.backend===`mock`?{models:[{id:`mock`,name:`mock(内置模拟)`}]}:await _e(x.value.backend||`openai`,x.value.base_url||``,x.value.api_key||``),e.error?(T.value=!1,w.value=e.error,vn.value=[]):vn.value=e.models||[]}finally{D.value=!1}}}let O=f({running:!1}),k=f(!1),A=f(!1),j=f([]),M=f(!1),N=f(``),P=f(!1),F=f(``),I=f(0),L=f(``),An=f(``),jn=f(``),R=f(null),Mn=f(``),z=f(``),Nn=f(!1),B=null,V=f([]),H=f([]),U=t({worker:!1,architect:!1}),W=t({worker:``,architect:``}),G=t({worker:!1,architect:!1}),K=t({worker:null,architect:null}),q=t({worker:``,architect:``}),J=[{id:`deepseek-v4-flash`,name:`deepseek-v4-flash(推荐)`},{id:`deepseek-v4-pro`,name:`deepseek-v4-pro(推理模式)`},{id:`deepseek-coder`,name:`deepseek-coder`},{id:`gpt-4o-mini`,name:`gpt-4o-mini`},{id:`gpt-4o`,name:`gpt-4o`},{id:`claude-3-5-sonnet-20241022`,name:`claude-3.5-sonnet`},{id:`qwen-plus`,name:`qwen-plus`},{id:`qwen-max`,name:`qwen-max`}],Y=f(null),X=t({worker:{backend:`mock`,model:``,base_url:``,port:8901,temperature:.3,max_fix_attempts:2,code_timeout_s:10},architect:{model:`deepseek-v4-flash`,base_url:`https://api.deepseek.com`,api_key:``},pipeline:{fast_path:!0,rounds_cap:6,api_token_cap:8e3,breach_policy:`architect_do`}}),Pn=l(()=>X.worker.backend===`llama_server`?`http://127.0.0.1:${X.worker.port}/v1`:`http://127.0.0.1:11434/v1`),Fn=l(()=>Y.value?JSON.stringify(X)!==JSON.stringify(Y.value):!1);function In(e){return e>=1e9?(e/1e9).toFixed(1)+` GB`:e>=1e6?(e/1e6).toFixed(1)+` MB`:e>=1e3?(e/1e3).toFixed(0)+` KB`:e+` B`}async function Ln(){try{let e=await me();return O.value=e,e}catch{return O.value={running:!1},{running:!1}}}async function Z(){M.value=!0;try{j.value=await fe()}catch{j.value=[]}finally{M.value=!1}}async function Rn(){if(!X.worker.model){alert(`请先从上方「本地模型」列表中选择一个模型,再启动服务`);return}k.value=!0;try{let e=await le(X.worker.model,X.worker.port,99,4096);O.value=e,e.running&&(X.worker.backend=`llama_server`,X.worker.base_url=`http://127.0.0.1:${e.port}/v1`,await Z(),await Q())}catch(e){O.value={running:!1,error:String(e?.message||e)}}finally{k.value=!1}}async function zn(){A.value=!0;try{await ie(),O.value={running:!1}}catch{O.value={running:!1}}finally{A.value=!1}}function Bn(e){N.value=e.id,X.worker.model=e.id}function Vn(){F.value.trim()&&(z.value=``,Nn.value=!1,I.value=0,L.value=``,An.value=``,jn.value=`0 B`,R.value=null,P.value=!0,de(F.value.trim()).then(e=>{if(e.error){z.value=e.error,P.value=!1;return}if(e.done){Hn(e);return}B=ne(F.value.trim()),B.subscribe({onProgress:Hn,onDone:e=>{Hn(e),B?.close(),B=null}})}))}function Hn(e){I.value=Math.round(e.progress_pct),L.value=e.speed,An.value=e.eta,jn.value=In(e.downloaded_bytes),R.value=e.total_bytes?In(e.total_bytes):null,Mn.value=e.dest,e.done&&(P.value=!1,e.error?z.value=e.error:(Nn.value=!0,Z()))}async function Un(){W.worker=``,V.value=[],X.worker.backend!==`mock`&&await Q()}async function Wn(){W.architect=``,H.value=[],await Gn()}async function Q(){if(X.worker.backend!==`mock`){U.worker=!0,W.worker=``;try{let e=await _e(X.worker.backend,X.worker.base_url,``);e.error?X.worker.backend===`llama_server`?W.worker=`💡 llama-server 未启动,请先点击上方「启动服务」`:W.worker=e.error||`连接失败`:V.value=e.models||[]}catch{W.worker=`获取模型列表失败`}finally{U.worker=!1}}}async function Gn(){if(U.architect=!0,W.architect=``,!X.architect.base_url){H.value=[...J],U.architect=!1;return}try{let e=await _e(`openai`,X.architect.base_url,X.architect.api_key||``);e.error?(W.architect=e.error,H.value=[...J]):(e.models||[]).length>0?H.value=e.models||[]:H.value=[...J]}catch{W.architect=`获取模型列表失败`,H.value=[...J]}finally{U.architect=!1}}async function Kn(){if(X.worker.backend!==`mock`){G.worker=!0,K.worker=null,q.worker=``;try{let e=await he(X.worker.backend,X.worker.base_url,``);K.worker=e.ok,e.ok||(q.worker=e.detail||`连接失败`)}catch(e){K.worker=!1,q.worker=e?.message||String(e)}finally{G.worker=!1}}}async function qn(){if(!X.architect.base_url){K.architect=!1,q.architect=`请先填写 API 端点`;return}G.architect=!0,K.architect=null,q.architect=``;try{let e=await he(`openai`,X.architect.base_url,X.architect.api_key||``);K.architect=e.ok,e.ok||(q.architect=e.detail||`连接失败`)}catch(e){K.architect=!1,q.architect=e?.message||String(e)}finally{G.architect=!1}}function $(e,t){if(t)for(let n of Object.keys(e))t[n]!==void 0&&(typeof e[n]==`object`&&typeof t[n]==`object`&&e[n]!==null?$(e[n],t[n]):e[n]=t[n])}async function Jn(){_.value=``;try{let[e,t]=await Promise.all([ae(),Ln()]);O.value=t,xn(),e.worker&&$(X.worker,e.worker),e.architect&&$(X.architect,e.architect),e.pipeline&&$(X.pipeline,e.pipeline),Y.value=JSON.parse(JSON.stringify(X)),await Z(),H.value=[...J],X.worker.backend!==`mock`&&Q(),X.worker.model&&(N.value=X.worker.model)}catch(e){_.value=`加载配置失败:`+(e?.message||String(e))}}async function Yn(){h.value=!0,v.value=null;try{let e=JSON.parse(JSON.stringify(X));e.architect.api_key||delete e.architect.api_key;let t=await oe(e);$(X.worker,t.worker||{}),$(X.architect,t.architect||{}),$(X.pipeline,t.pipeline||{}),Y.value=JSON.parse(JSON.stringify(X)),v.value={ok:!0,msg:`✅ 设置已保存,管线已重建`},setTimeout(()=>v.value=null,3e3)}catch(e){v.value={ok:!1,msg:`❌ 保存失败:`+(e?.message||String(e))}}finally{h.value=!1}}async function Xn(){if(confirm(`确定恢复默认设置?`)){h.value=!0,v.value=null;try{let e=await pe();$(X.worker,e.worker||{}),$(X.architect,e.architect||{}),$(X.pipeline,e.pipeline||{}),Y.value=JSON.parse(JSON.stringify(X)),V.value=[],H.value=[...J],K.worker=null,K.architect=null,v.value={ok:!0,msg:`✅ 已恢复默认设置`},setTimeout(()=>v.value=null,3e3)}catch(e){v.value={ok:!1,msg:`❌ 重置失败:`+(e?.message||String(e))}}finally{h.value=!1}}}return te(Jn),i(()=>{B?.close()}),(t,i)=>(o(),p(`div`,xe,[i[68]||=m(`header`,{class:`settings-header`},[m(`h2`,null,`⚙️ 模型设置`),m(`p`,{class:`subtitle`},`配置小模型(Worker)与大模型(Architect)参数,保存后实时生效`)],-1),m(`section`,Se,[m(`div`,{class:`section-title`},[i[29]||=m(`span`,null,`🗄️ 模型池(多价位异构模型)`,-1),m(`div`,{class:`title-right`},[m(`button`,{class:`btn-refresh`,onClick:Cn},`+ 添加模型`)])]),m(`div`,Ce,[m(`div`,we,[(o(),p(n,null,s(gn,e=>m(`div`,{class:`role-item`,key:e.key},[m(`label`,null,a(e.label),1),g(m(`select`,{"onUpdate:modelValue":t=>b[e.key]=t,onChange:Sn},[i[30]||=m(`option`,{value:``},`经典设置(下方表单)`,-1),(o(!0),p(n,null,s(yn.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name),9,Ee))),128))],40,Te),[[u,b[e.key]]])])),64))]),i[44]||=m(`p`,{class:`role-hint`},` 按价位组织模型:本地 llama.cpp 为零成本档,低价 API 干批量活,旗舰 API 做决策—— 随时切换,保存后管线自动重建。 `,-1),y.value.entries.length?(o(),p(`table`,De,[i[31]||=m(`thead`,null,[m(`tr`,null,[m(`th`,null,`名称`),m(`th`,null,`档位`),m(`th`,null,`后端`),m(`th`,null,`模型`),m(`th`,null,`单价 $/1M(入/出)`),m(`th`,null,`启用`),m(`th`,null,`操作`)])],-1),m(`tbody`,null,[(o(!0),p(n,null,s(y.value.entries,e=>(o(),p(`tr`,{key:e.id},[m(`td`,null,a(e.name),1),m(`td`,null,[m(`span`,{class:d([`tier-badge`,`tier-`+e.tier])},a(bn(e.tier)),3)]),m(`td`,null,a(e.backend),1),m(`td`,Oe,a(e.model||`—`),1),m(`td`,null,a(e.price_in)+` / `+a(e.price_out),1),m(`td`,null,[g(m(`input`,{type:`checkbox`,"onUpdate:modelValue":t=>e.enabled=t,onChange:t=>Dn(e)},null,40,ke),[[ve,e.enabled]])]),m(`td`,Ae,[m(`button`,{class:`btn-refresh`,disabled:C.value===e.id,onClick:t=>On(e)},a(C.value===e.id?`…`:`测试`),9,je),m(`button`,{class:`btn-refresh`,onClick:t=>wn(e)},`编辑`,8,Me),m(`button`,{class:`btn-refresh danger`,onClick:t=>En(e)},`删除`,8,Ne)])]))),128))])])):(o(),p(`div`,Pe,` 池为空——可添加本地 llama.cpp 模型(零成本档)、低价 API、旗舰 API 等,随时指派给 Architect / Worker / Agent。 `)),w.value?(o(),p(`div`,{key:2,class:d([`field-hint`,T.value?`ok`:`warn`])},a(w.value),3)):e(``,!0),x.value?(o(),p(`div`,Fe,[m(`div`,Ie,a(S.value?`添加模型`:`编辑模型`),1),m(`div`,Le,[m(`div`,Re,[i[32]||=m(`label`,null,`名称`,-1),g(m(`input`,{"onUpdate:modelValue":i[0]||=e=>x.value.name=e,placeholder:`如:DeepSeek 旗舰 / 本地 Qwen4B`},null,512),[[r,x.value.name]])]),m(`div`,ze,[i[34]||=m(`label`,null,`档位`,-1),g(m(`select`,{"onUpdate:modelValue":i[1]||=e=>x.value.tier=e},[...i[33]||=[m(`option`,{value:`local`},`local(本地 / 零边际成本)`,-1),m(`option`,{value:`budget`},`budget(低价 API)`,-1),m(`option`,{value:`premium`},`premium(旗舰 API)`,-1)]],512),[[u,x.value.tier]])]),m(`div`,Be,[i[36]||=m(`label`,null,`后端`,-1),g(m(`select`,{"onUpdate:modelValue":i[2]||=e=>x.value.backend=e},[...i[35]||=[m(`option`,{value:`openai`},`openai / 兼容 API`,-1),m(`option`,{value:`llama_server`},`llama_server(内置本地)`,-1),m(`option`,{value:`mock`},`mock(模拟)`,-1)]],512),[[u,x.value.backend]])]),m(`div`,Ve,[m(`label`,null,[i[37]||=c(` 模型 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:D.value,onClick:kn},a(D.value?`…`:`🔄 刷新列表`),9,He)]),g(m(`input`,{"onUpdate:modelValue":i[3]||=e=>x.value.model=e,list:`pool-model-options`,placeholder:`模型名`},null,512),[[r,x.value.model]]),m(`datalist`,Ue,[(o(!0),p(n,null,s(vn.value,e=>(o(),p(`option`,{key:e.id,value:e.id},null,8,We))),128))])]),x.value.backend===`mock`?e(``,!0):(o(),p(`div`,Ge,[i[38]||=m(`label`,null,`API 地址`,-1),g(m(`input`,{"onUpdate:modelValue":i[4]||=e=>x.value.base_url=e,placeholder:`https://api.deepseek.com 或 http://127.0.0.1:8901/v1`},null,512),[[r,x.value.base_url]])])),x.value.backend===`openai`?(o(),p(`div`,Ke,[m(`label`,null,`API Key`+a(x.value.api_key_set?`(已设置,留空保留)`:``),1),g(m(`input`,{"onUpdate:modelValue":i[5]||=e=>x.value.api_key=e,type:`password`,autocomplete:`off`,placeholder:`sk-…`},null,512),[[r,x.value.api_key]])])):e(``,!0),m(`div`,qe,[i[39]||=m(`label`,null,`输入单价 $/1M`,-1),g(m(`input`,{"onUpdate:modelValue":i[6]||=e=>x.value.price_in=e,type:`number`,min:`0`,step:`0.01`},null,512),[[r,x.value.price_in,void 0,{number:!0}]])]),m(`div`,Je,[i[40]||=m(`label`,null,`输出单价 $/1M`,-1),g(m(`input`,{"onUpdate:modelValue":i[7]||=e=>x.value.price_out=e,type:`number`,min:`0`,step:`0.01`},null,512),[[r,x.value.price_out,void 0,{number:!0}]])]),m(`div`,Ye,[i[41]||=m(`label`,null,`Temperature`,-1),g(m(`input`,{"onUpdate:modelValue":i[8]||=e=>x.value.temperature=e,type:`number`,min:`0`,max:`2`,step:`0.05`},null,512),[[r,x.value.temperature,void 0,{number:!0}]])]),m(`div`,Xe,[i[42]||=m(`label`,null,`Max Tokens`,-1),g(m(`input`,{"onUpdate:modelValue":i[9]||=e=>x.value.max_tokens=e,type:`number`,min:`256`,max:`32768`},null,512),[[r,x.value.max_tokens,void 0,{number:!0}]])])]),m(`div`,Ze,[m(`label`,Qe,[g(m(`input`,{type:`checkbox`,"onUpdate:modelValue":i[10]||=e=>x.value.enabled=e},null,512),[[ve,x.value.enabled]]),i[43]||=c(` 启用 `,-1)]),m(`button`,{class:`btn-primary`,disabled:E.value,onClick:Tn},a(E.value?`保存中…`:`保存条目`),9,$e),m(`button`,{class:`btn-secondary`,onClick:i[11]||=e=>x.value=null},`取消`)])])):e(``,!0)])]),m(`section`,et,[m(`div`,tt,[i[45]||=m(`span`,null,`🔧 小模型 (Worker · 本地 llama.cpp)`,-1),m(`div`,nt,[m(`span`,{class:d([`server-badge`,O.value.running?`badge-running`:`badge-stopped`])},a(O.value.running?`● 运行中`:`○ 已停止`),3)])]),m(`div`,rt,[m(`div`,it,[m(`div`,at,[O.value.running?(o(),p(n,{key:0},[m(`span`,ot,a(O.value.model?.split(/[/\\]/).pop()),1),m(`span`,st,`:`+a(O.value.port),1),m(`span`,ct,`PID `+a(O.value.pid),1)],64)):(o(),p(`span`,lt,`llama-server 未运行 — 点击「启动服务」即可启用`))]),m(`div`,ut,[O.value.running?(o(),p(`button`,{key:1,class:`btn-stop`,disabled:k.value||A.value,onClick:zn},a(A.value?`停止中…`:`■ 停止服务`),9,ft)):(o(),p(`button`,{key:0,class:`btn-start`,disabled:k.value||A.value,onClick:Rn},a(k.value?`启动中…`:`▶ 启动服务`),9,dt))])]),O.value.error?(o(),p(`div`,pt,a(O.value.error),1)):e(``,!0),m(`div`,mt,[m(`div`,ht,[m(`span`,null,`📁 本地模型 (`+a(j.value.length)+`)`,1),m(`button`,{class:`btn-refresh`,disabled:M.value,onClick:Z},a(M.value?`…`:`🔄`),9,gt)]),j.value.length===0&&!M.value?(o(),p(`div`,_t,` 暂无本地模型,请下载或放置 .gguf 文件到 models/ 目录 `)):(o(),p(`div`,vt,[(o(!0),p(n,null,s(j.value,e=>(o(),p(`div`,{key:e.id,class:d([`model-item`,N.value===e.id?`selected`:``]),onClick:t=>Bn(e)},[m(`span`,bt,a(e.name),1),m(`span`,xt,a(e.size_mb)+` MB`,1)],10,yt))),128))]))]),m(`div`,St,[i[46]||=m(`div`,{class:`download-header`},`⬇️ 下载模型`,-1),m(`div`,Ct,[g(m(`input`,{"onUpdate:modelValue":i[12]||=e=>F.value=e,class:`download-input`,placeholder:`HuggingFace 路径或直链,如:Qwen/Qwen3-4B-GGUF/Qwen3-4B-Q4_K_M.gguf`,disabled:P.value},null,8,wt),[[r,F.value]]),m(`button`,{class:`btn-download`,disabled:P.value||!F.value.trim(),onClick:Vn},a(P.value?I.value+`%`:`下载`),9,Tt)]),P.value?(o(),p(`div`,Et,[m(`div`,Dt,[m(`div`,{class:`progress-fill`,style:re({width:I.value+`%`})},null,4)]),m(`div`,Ot,[m(`span`,null,a(L.value),1),m(`span`,null,a(An.value),1),m(`span`,null,a(jn.value)+`/`+a(R.value||`?`),1)])])):e(``,!0),z.value?(o(),p(`div`,kt,a(z.value),1)):e(``,!0),Nn.value&&!z.value?(o(),p(`div`,At,` ✅ 下载完成:`+a(Mn.value),1)):e(``,!0)]),m(`div`,jt,[m(`div`,Mt,[i[48]||=m(`label`,null,`后端类型`,-1),g(m(`select`,{"onUpdate:modelValue":i[13]||=e=>X.worker.backend=e,onChange:Un},[...i[47]||=[m(`option`,{value:`mock`},`mock(模拟,不真实调用)`,-1),m(`option`,{value:`llama_server`},`llama_server(内置本地服务,推荐)`,-1),m(`option`,{value:`openai`},`openai / 兼容 API(Ollama 等)`,-1)]],544),[[u,X.worker.backend]])]),X.worker.backend===`mock`?e(``,!0):(o(),p(`div`,Nt,[m(`label`,null,[i[49]||=c(` API 地址 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:G.worker,onClick:Kn},a(G.worker?`…`:`🔗 连接测试`),9,Pt)]),m(`div`,Ft,[g(m(`input`,{"onUpdate:modelValue":i[14]||=e=>X.worker.base_url=e,placeholder:Pn.value,onBlur:Un},null,40,It),[[r,X.worker.base_url]]),K.worker===null?e(``,!0):(o(),p(`span`,{key:0,class:d([`ping-badge`,K.worker?`ping-ok`:`ping-err`])},a(K.worker?`✅ 正常`:`❌ `+q.worker),3))])])),X.worker.backend===`mock`?e(``,!0):(o(),p(`div`,Lt,[m(`label`,null,[i[50]||=c(` 模型 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:U.worker,onClick:Q},a(U.worker?`…`:`🔄 刷新列表`),9,Rt)]),X.worker.backend===`llama_server`?g((o(),p(`select`,{key:0,"onUpdate:modelValue":i[15]||=e=>X.worker.model=e},[i[51]||=m(`option`,{value:``,disabled:``},`—— 从本地模型中选择 ——`,-1),(o(!0),p(n,null,s(j.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name),9,zt))),128))],512)),[[u,X.worker.model]]):X.worker.backend===`openai`?g((o(),p(`select`,{key:1,"onUpdate:modelValue":i[16]||=e=>X.worker.model=e},[i[52]||=m(`option`,{value:``,disabled:``},`—— 从 API 获取 ——`,-1),(o(!0),p(n,null,s(V.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name||e.id),9,Bt))),128))],512)),[[u,X.worker.model]]):g((o(),p(`input`,{key:2,"onUpdate:modelValue":i[17]||=e=>X.worker.model=e,placeholder:`输入模型名称…`},null,512)),[[r,X.worker.model]]),W.worker?(o(),p(`span`,Vt,a(W.worker),1)):e(``,!0)])),X.worker.backend===`llama_server`?(o(),p(`div`,Ht,[i[53]||=m(`label`,null,`端口`,-1),g(m(`input`,{"onUpdate:modelValue":i[18]||=e=>X.worker.port=e,type:`number`,min:`1`,max:`65535`},null,512),[[r,X.worker.port,void 0,{number:!0}]])])):e(``,!0),m(`div`,Ut,[i[54]||=m(`label`,null,`Temperature`,-1),g(m(`input`,{"onUpdate:modelValue":i[19]||=e=>X.worker.temperature=e,type:`number`,min:`0`,max:`2`,step:`0.05`},null,512),[[r,X.worker.temperature,void 0,{number:!0}]])]),m(`div`,Wt,[i[55]||=m(`label`,null,`最大修复轮次`,-1),g(m(`input`,{"onUpdate:modelValue":i[20]||=e=>X.worker.max_fix_attempts=e,type:`number`,min:`0`,max:`10`},null,512),[[r,X.worker.max_fix_attempts,void 0,{number:!0}]])]),m(`div`,Gt,[i[56]||=m(`label`,null,`代码执行超时 (秒)`,-1),g(m(`input`,{"onUpdate:modelValue":i[21]||=e=>X.worker.code_timeout_s=e,type:`number`,min:`1`,max:`300`},null,512),[[r,X.worker.code_timeout_s,void 0,{number:!0}]])])])])]),m(`section`,Kt,[m(`div`,qt,[i[57]||=m(`span`,null,`🧠 大模型 (Architect · API 云端)`,-1),m(`div`,Jt,[K.architect===null?e(``,!0):(o(),p(`span`,{key:0,class:d([`ping-badge`,K.architect?`ping-ok`:`ping-err`])},a(K.architect?`✅ 已连接`:`❌ `+q.architect),3))])]),m(`div`,Yt,[m(`div`,Xt,[m(`div`,Zt,[m(`label`,null,[i[58]||=c(` API 端点 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:G.architect,onClick:qn},a(G.architect?`…`:`🔗 连接测试`),9,Qt)]),g(m(`input`,{"onUpdate:modelValue":i[22]||=e=>X.architect.base_url=e,placeholder:`https://api.deepseek.com`,onBlur:Wn},null,544),[[r,X.architect.base_url]])]),m(`div`,$t,[i[59]||=m(`label`,null,`API Key(保存在本地 config/settings.json,不入代码库;优先级高于 .env)`,-1),g(m(`input`,{"onUpdate:modelValue":i[23]||=e=>X.architect.api_key=e,type:`password`,placeholder:`sk-xxxxxxxxxxxxxxxx`,autocomplete:`off`},null,512),[[r,X.architect.api_key]])]),m(`div`,en,[m(`label`,null,[i[60]||=c(` 模型 `,-1),m(`button`,{class:`btn-refresh btn-inline`,disabled:U.architect,onClick:Gn},a(U.architect?`…`:`🔄 刷新列表`),9,tn)]),g(m(`select`,{"onUpdate:modelValue":i[24]||=e=>X.architect.model=e,class:`model-select`},[i[61]||=m(`option`,{value:``,disabled:``},`—— 从 API 获取模型列表 ——`,-1),(o(!0),p(n,null,s(H.value,e=>(o(),p(`option`,{key:e.id,value:e.id},a(e.name||e.id),9,nn))),128))],512),[[u,X.architect.model]]),W.architect?(o(),p(`span`,rn,a(W.architect),1)):e(``,!0)])])])]),m(`section`,an,[i[67]||=m(`div`,{class:`section-title`},[m(`span`,null,`⚙️ 协作管线 (Pipeline)`)],-1),m(`div`,on,[m(`div`,sn,[m(`div`,cn,[m(`label`,ln,[g(m(`input`,{type:`checkbox`,"onUpdate:modelValue":i[25]||=e=>X.pipeline.fast_path=e},null,512),[[ve,X.pipeline.fast_path]]),i[62]||=c(` 启用快路径(简单查询跳过本地模型,直接由大模型回答,省 API 费用) `,-1)])]),m(`div`,un,[i[63]||=m(`label`,null,`最大协作轮次`,-1),g(m(`input`,{"onUpdate:modelValue":i[26]||=e=>X.pipeline.rounds_cap=e,type:`number`,min:`1`,max:`20`},null,512),[[r,X.pipeline.rounds_cap,void 0,{number:!0}]])]),m(`div`,dn,[i[64]||=m(`label`,null,`API Token 熔断上限`,-1),g(m(`input`,{"onUpdate:modelValue":i[27]||=e=>X.pipeline.api_token_cap=e,type:`number`,min:`100`,max:`100000`},null,512),[[r,X.pipeline.api_token_cap,void 0,{number:!0}]])]),m(`div`,fn,[i[66]||=m(`label`,null,`超限策略`,-1),g(m(`select`,{"onUpdate:modelValue":i[28]||=e=>X.pipeline.breach_policy=e},[...i[65]||=[m(`option`,{value:`architect_do`},`architect_do(超限交给大模型处理,推荐)`,-1),m(`option`,{value:`local_only`},`local_only(强制留在本地小模型)`,-1)]],512),[[u,X.pipeline.breach_policy]])])])])]),m(`div`,pn,[m(`button`,{class:`btn-primary`,disabled:h.value||!Fn.value,onClick:Yn},a(h.value?`保存中…`:`💾 保存设置`),9,mn),m(`button`,{class:`btn-secondary`,disabled:h.value,onClick:Xn},` 🔁 恢复默认 `,8,hn)]),v.value?(o(),p(`div`,{key:0,class:d([`toast`,v.value.ok?`toast-ok`:`toast-err`])},a(v.value.msg),3)):e(``,!0)]))}}),[[`__scopeId`,`data-v-7b21dc2a`]]);export{_ as default}; \ No newline at end of file diff --git a/gateway/static/assets/index-C8Za1808.js b/gateway/static/assets/index-C4nTxB0s.js similarity index 94% rename from gateway/static/assets/index-C8Za1808.js rename to gateway/static/assets/index-C4nTxB0s.js index 205f7d7..38b6d3f 100644 --- a/gateway/static/assets/index-C8Za1808.js +++ b/gateway/static/assets/index-C4nTxB0s.js @@ -1,4 +1,4 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CollaborationView-DHMzJVru.js","assets/CollaborationView-CfueFZKz.css","assets/ReviewView-Cm34POvM.js","assets/ReviewView-9PXrv1jO.css","assets/MetricsView-BMWM9u4c.js","assets/MetricsView-JgJGH4Og.css","assets/SettingsView-DMG9EXA2.js","assets/SettingsView-DWdd6um_.css"])))=>i.map(i=>d[i]); +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CollaborationView-BzBpxfYH.js","assets/CollaborationView-CfueFZKz.css","assets/ReviewView-wY3DEmtF.js","assets/ReviewView-9PXrv1jO.css","assets/MetricsView-Dm03Grst.js","assets/MetricsView-JgJGH4Og.css","assets/SettingsView-B4tzUqnq.js","assets/SettingsView-DWdd6um_.css"])))=>i.map(i=>d[i]); var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();function n(e){let t=Object.create(null);for(let n of e.split(`,`))t[n]=1;return e=>e in t}var r={},i=[],a=()=>{},o=()=>!1,s=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),c=e=>e.startsWith(`onUpdate:`),l=Object.assign,u=(e,t)=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)},d=Object.prototype.hasOwnProperty,f=(e,t)=>d.call(e,t),p=Array.isArray,m=e=>C(e)===`[object Map]`,h=e=>C(e)===`[object Set]`,g=e=>C(e)===`[object Date]`,_=e=>typeof e==`function`,v=e=>typeof e==`string`,y=e=>typeof e==`symbol`,b=e=>typeof e==`object`&&!!e,x=e=>(b(e)||_(e))&&_(e.then)&&_(e.catch),S=Object.prototype.toString,C=e=>S.call(e),w=e=>C(e).slice(8,-1),ee=e=>C(e)===`[object Object]`,te=e=>v(e)&&e!==`NaN`&&e[0]!==`-`&&``+parseInt(e,10)===e,ne=n(`,key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted`),re=e=>{let t=Object.create(null);return(n=>t[n]||(t[n]=e(n)))},ie=/-\w/g,T=re(e=>e.replace(ie,e=>e.slice(1).toUpperCase())),E=/\B([A-Z])/g,D=re(e=>e.replace(E,`-$1`).toLowerCase()),O=re(e=>e.charAt(0).toUpperCase()+e.slice(1)),ae=re(e=>e?`on${O(e)}`:``),k=(e,t)=>!Object.is(e,t),oe=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:r,value:n})},A=e=>{let t=parseFloat(e);return isNaN(t)?e:t},j,M=()=>j||=typeof globalThis<`u`?globalThis:typeof self<`u`?self:typeof window<`u`?window:typeof global<`u`?global:{};function ce(e){if(p(e)){let t={};for(let n=0;n{if(e){let n=e.split(ue);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function pe(e){let t=``;if(v(e))t=e;else if(p(e))for(let n=0;nye(e,t))}var xe=e=>!!(e&&e.__v_isRef===!0),N=e=>v(e)?e:e==null?``:p(e)||b(e)&&(e.toString===S||!_(e.toString))?xe(e)?N(e.value):JSON.stringify(e,Se,2):String(e),Se=(e,t)=>xe(t)?Se(e,t.value):m(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((e,[t,n],r)=>(e[Ce(t,r)+` =>`]=n,e),{})}:h(t)?{[`Set(${t.size})`]:[...t.values()].map(e=>Ce(e))}:y(t)?Ce(t):b(t)&&!p(t)&&!ee(t)?String(t):t,Ce=(e,t=``)=>y(e)?`Symbol(${e.description??t})`:e,P,we=class{constructor(e=!1){this.detached=e,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!e&&P&&(P.active?(this.parent=P,this.index=(P.scopes||(P.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let e,t;if(this.scopes){let n=this.scopes.slice();for(e=0,t=n.length;e0&&--this._on===0){if(P===this)P=this.prevScope;else{let e=P;for(;e;){if(e.prevScope===this){e.prevScope=this.prevScope;break}e=e.prevScope}}this.prevScope=void 0}}stop(e){if(this._active){this._active=!1;let t,n;for(t=0,n=this.effects.length;t0)return;if(Me){let e=Me;for(Me=void 0;e;){let t=e.next;e.next=void 0,e.flags&=-9,e=t}}let e;for(;je;){let t=je;for(je=void 0;t;){let n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(t){e||=t}t=n}}if(e)throw e}function Ie(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function Le(e){let t,n=e.depsTail,r=n;for(;r;){let e=r.prevDep;r.version===-1?(r===n&&(n=e),Be(r),Ve(r)):t=r,r.dep.activeLink=r.prevActiveLink,r.prevActiveLink=void 0,r=e}e.deps=t,e.depsTail=n}function Re(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(ze(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function ze(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===qe)||(e.globalVersion=qe,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Re(e))))return;e.flags|=2;let t=e.dep,n=F,r=He;F=e,He=!0;try{Ie(e);let n=e.fn(e._value);(t.version===0||k(n,e._value))&&(e.flags|=128,e._value=n,t.version++)}catch(e){throw t.version++,e}finally{F=n,He=r,Le(e),e.flags&=-3}}function Be(e,t=!1){let{dep:n,prevSub:r,nextSub:i}=e;if(r&&(r.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=r,e.nextSub=void 0),n.subs===e&&(n.subs=r,!r&&n.computed)){n.computed.flags&=-5;for(let e=n.computed.deps;e;e=e.nextDep)Be(e,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function Ve(e){let{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}var He=!0,Ue=[];function We(){Ue.push(He),He=!1}function Ge(){let e=Ue.pop();He=e===void 0||e}function Ke(e){let{cleanup:t}=e;if(e.cleanup=void 0,t){let e=F;F=void 0;try{t()}finally{F=e}}}var qe=0,Je=class{constructor(e,t){this.sub=e,this.dep=t,this.version=t.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}},Ye=class{constructor(e){this.computed=e,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(e){if(!F||!He||F===this.computed)return;let t=this.activeLink;if(t===void 0||t.sub!==F)t=this.activeLink=new Je(F,this),F.deps?(t.prevDep=F.depsTail,F.depsTail.nextDep=t,F.depsTail=t):F.deps=F.depsTail=t,Xe(t);else if(t.version===-1&&(t.version=this.version,t.nextDep)){let e=t.nextDep;e.prevDep=t.prevDep,t.prevDep&&(t.prevDep.nextDep=e),t.prevDep=F.depsTail,t.nextDep=void 0,F.depsTail.nextDep=t,F.depsTail=t,F.deps===t&&(F.deps=e)}return t}trigger(e){this.version++,qe++,this.notify(e)}notify(e){Pe();try{for(let e=this.subs;e;e=e.prevSub)e.sub.notify()&&e.sub.dep.notify()}finally{Fe()}}};function Xe(e){if(e.dep.sc++,e.sub.flags&4){let t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let e=t.deps;e;e=e.nextDep)Xe(e)}let n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}var Ze=new WeakMap,Qe=Symbol(``),$e=Symbol(``),et=Symbol(``);function tt(e,t,n){if(He&&F){let t=Ze.get(e);t||Ze.set(e,t=new Map);let r=t.get(n);r||(t.set(n,r=new Ye),r.map=t,r.key=n),r.track()}}function nt(e,t,n,r,i,a){let o=Ze.get(e);if(!o){qe++;return}let s=e=>{e&&e.trigger()};if(Pe(),t===`clear`)o.forEach(s);else{let i=p(e),a=i&&te(n);if(i&&n===`length`){let e=Number(r);o.forEach((t,n)=>{(n===`length`||n===et||!y(n)&&n>=e)&&s(t)})}else switch((n!==void 0||o.has(void 0))&&s(o.get(n)),a&&s(o.get(et)),t){case`add`:i?a&&s(o.get(`length`)):(s(o.get(Qe)),m(e)&&s(o.get($e)));break;case`delete`:i||(s(o.get(Qe)),m(e)&&s(o.get($e)));break;case`set`:m(e)&&s(o.get(Qe))}}Fe()}function rt(e,t){let n=Ze.get(e);return n&&n.get(t)}function it(e){let t=I(e);return t===e?t:(tt(t,`iterate`,et),Ut(e)?t:t.map(Kt))}function at(e){return tt(e=I(e),`iterate`,et),e}function ot(e,t){return Ht(e)?qt(Vt(e)?Kt(t):t):Kt(t)}var st={__proto__:null,[Symbol.iterator](){return ct(this,Symbol.iterator,e=>ot(this,e))},concat(...e){return it(this).concat(...e.map(e=>p(e)?it(e):e))},entries(){return ct(this,`entries`,e=>(e[1]=ot(this,e[1]),e))},every(e,t){return ut(this,`every`,e,t,void 0,arguments)},filter(e,t){return ut(this,`filter`,e,t,e=>e.map(e=>ot(this,e)),arguments)},find(e,t){return ut(this,`find`,e,t,e=>ot(this,e),arguments)},findIndex(e,t){return ut(this,`findIndex`,e,t,void 0,arguments)},findLast(e,t){return ut(this,`findLast`,e,t,e=>ot(this,e),arguments)},findLastIndex(e,t){return ut(this,`findLastIndex`,e,t,void 0,arguments)},forEach(e,t){return ut(this,`forEach`,e,t,void 0,arguments)},includes(...e){return ft(this,`includes`,e)},indexOf(...e){return ft(this,`indexOf`,e)},join(e){return it(this).join(e)},lastIndexOf(...e){return ft(this,`lastIndexOf`,e)},map(e,t){return ut(this,`map`,e,t,void 0,arguments)},pop(){return pt(this,`pop`)},push(...e){return pt(this,`push`,e)},reduce(e,...t){return dt(this,`reduce`,e,t)},reduceRight(e,...t){return dt(this,`reduceRight`,e,t)},shift(){return pt(this,`shift`)},some(e,t){return ut(this,`some`,e,t,void 0,arguments)},splice(...e){return pt(this,`splice`,e)},toReversed(){return it(this).toReversed()},toSorted(e){return it(this).toSorted(e)},toSpliced(...e){return it(this).toSpliced(...e)},unshift(...e){return pt(this,`unshift`,e)},values(){return ct(this,`values`,e=>ot(this,e))}};function ct(e,t,n){let r=at(e),i=r[t]();return r!==e&&!Ut(e)&&(i._next=i.next,i.next=()=>{let e=i._next();return e.done||(e.value=n(e.value)),e}),i}var lt=Array.prototype;function ut(e,t,n,r,i,a){let o=at(e),s=o!==e&&!Ut(e),c=o[t];if(c!==lt[t]){let t=c.apply(e,a);return s?Kt(t):t}let l=n;o!==e&&(s?l=function(t,r){return n.call(this,ot(e,t),r,e)}:n.length>2&&(l=function(t,r){return n.call(this,t,r,e)}));let u=c.call(o,l,r);return s&&i?i(u):u}function dt(e,t,n,r){let i=at(e),a=i!==e&&!Ut(e),o=n,s=!1;i!==e&&(a?(s=r.length===0,o=function(t,r,i){return s&&(s=!1,t=ot(e,t)),n.call(this,t,ot(e,r),i,e)}):n.length>3&&(o=function(t,r,i){return n.call(this,t,r,i,e)}));let c=i[t](o,...r);return s?ot(e,c):c}function ft(e,t,n){let r=I(e);tt(r,`iterate`,et);let i=r[t](...n);return(i===-1||i===!1)&&Wt(n[0])?(n[0]=I(n[0]),r[t](...n)):i}function pt(e,t,n=[]){We(),Pe();let r=I(e)[t].apply(e,n);return Fe(),Ge(),r}var mt=n(`__proto__,__v_isRef,__isVue`),ht=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!==`arguments`&&e!==`caller`).map(e=>Symbol[e]).filter(y));function gt(e){y(e)||(e=String(e));let t=I(this);return tt(t,`has`,e),t.hasOwnProperty(e)}var _t=class{constructor(e=!1,t=!1){this._isReadonly=e,this._isShallow=t}get(e,t,n){if(t===`__v_skip`)return e.__v_skip;let r=this._isReadonly,i=this._isShallow;if(t===`__v_isReactive`)return!r;if(t===`__v_isReadonly`)return r;if(t===`__v_isShallow`)return i;if(t===`__v_raw`)return n===(r?i?Ft:Pt:i?Nt:Mt).get(e)||Object.getPrototypeOf(e)===Object.getPrototypeOf(n)?e:void 0;let a=p(e);if(!r){let e;if(a&&(e=st[t]))return e;if(t===`hasOwnProperty`)return gt}let o=Reflect.get(e,t,L(e)?e:n);if((y(t)?ht.has(t):mt(t))||(r||tt(e,`get`,t),i))return o;if(L(o)){let e=a&&te(t)?o:o.value;return r&&b(e)?zt(e):e}return b(o)?r?zt(o):Lt(o):o}},vt=class extends _t{constructor(e=!1){super(!1,e)}set(e,t,n,r){let i=e[t],a=p(e)&&te(t);if(!this._isShallow){let e=Ht(i);if(!Ut(n)&&!Ht(n)&&(i=I(i),n=I(n)),!a&&L(i)&&!L(n))return e||(i.value=n),!0}let o=a?Number(t)e,wt=e=>Reflect.getPrototypeOf(e);function Tt(e,t,n){return function(...r){let i=this.__v_raw,a=I(i),o=m(a),s=e===`entries`||e===Symbol.iterator&&o,c=e===`keys`&&o,u=i[e](...r),d=n?Ct:t?qt:Kt;return!t&&tt(a,`iterate`,c?$e:Qe),l(Object.create(u),{next(){let{value:e,done:t}=u.next();return t?{value:e,done:t}:{value:s?[d(e[0]),d(e[1])]:d(e),done:t}}})}}function Et(e){return function(...t){return e===`delete`?!1:e===`clear`?void 0:this}}function Dt(e,t){let n={get(n){let r=this.__v_raw,i=I(r),a=I(n);e||(k(n,a)&&tt(i,`get`,n),tt(i,`get`,a));let{has:o}=wt(i),s=t?Ct:e?qt:Kt;if(o.call(i,n))return s(r.get(n));if(o.call(i,a))return s(r.get(a));r!==i&&r.get(n)},get size(){let t=this.__v_raw;return!e&&tt(I(t),`iterate`,Qe),t.size},has(t){let n=this.__v_raw,r=I(n),i=I(t);return e||(k(t,i)&&tt(r,`has`,t),tt(r,`has`,i)),t===i?n.has(t):n.has(t)||n.has(i)},forEach(n,r){let i=this,a=i.__v_raw,o=I(a),s=t?Ct:e?qt:Kt;return!e&&tt(o,`iterate`,Qe),a.forEach((e,t)=>n.call(r,s(e),s(t),i))}};return l(n,e?{add:Et(`add`),set:Et(`set`),delete:Et(`delete`),clear:Et(`clear`)}:{add(e){let n=I(this),r=wt(n),i=I(e),a=!t&&!Ut(e)&&!Ht(e)?i:e;return r.has.call(n,a)||k(e,a)&&r.has.call(n,e)||k(i,a)&&r.has.call(n,i)||(n.add(a),nt(n,`add`,a,a)),this},set(e,n){!t&&!Ut(n)&&!Ht(n)&&(n=I(n));let r=I(this),{has:i,get:a}=wt(r),o=i.call(r,e);o||=(e=I(e),i.call(r,e));let s=a.call(r,e);return r.set(e,n),o?k(n,s)&&nt(r,`set`,e,n,s):nt(r,`add`,e,n),this},delete(e){let t=I(this),{has:n,get:r}=wt(t),i=n.call(t,e);i||=(e=I(e),n.call(t,e));let a=r?r.call(t,e):void 0,o=t.delete(e);return i&&nt(t,`delete`,e,void 0,a),o},clear(){let e=I(this),t=e.size!==0,n=e.clear();return t&&nt(e,`clear`,void 0,void 0,void 0),n}}),[`keys`,`values`,`entries`,Symbol.iterator].forEach(r=>{n[r]=Tt(r,e,t)}),n}function Ot(e,t){let n=Dt(e,t);return(t,r,i)=>r===`__v_isReactive`?!e:r===`__v_isReadonly`?e:r===`__v_raw`?t:Reflect.get(f(n,r)&&r in t?n:t,r,i)}var kt={get:Ot(!1,!1)},At={get:Ot(!1,!0)},jt={get:Ot(!0,!1)},Mt=new WeakMap,Nt=new WeakMap,Pt=new WeakMap,Ft=new WeakMap;function It(e){switch(e){case`Object`:case`Array`:return 1;case`Map`:case`Set`:case`WeakMap`:case`WeakSet`:return 2;default:return 0}}function Lt(e){return Ht(e)?e:Bt(e,!1,bt,kt,Mt)}function Rt(e){return Bt(e,!1,St,At,Nt)}function zt(e){return Bt(e,!0,xt,jt,Pt)}function Bt(e,t,n,r,i){if(!b(e)||e.__v_raw&&!(t&&e.__v_isReactive)||e.__v_skip||!Object.isExtensible(e))return e;let a=i.get(e);if(a)return a;let o=It(w(e));if(o===0)return e;let s=new Proxy(e,o===2?r:n);return i.set(e,s),s}function Vt(e){return Ht(e)?Vt(e.__v_raw):!!(e&&e.__v_isReactive)}function Ht(e){return!!(e&&e.__v_isReadonly)}function Ut(e){return!!(e&&e.__v_isShallow)}function Wt(e){return e?!!e.__v_raw:!1}function I(e){let t=e&&e.__v_raw;return t?I(t):e}function Gt(e){return!f(e,`__v_skip`)&&Object.isExtensible(e)&&se(e,`__v_skip`,!0),e}var Kt=e=>b(e)?Lt(e):e,qt=e=>b(e)?zt(e):e;function L(e){return e?e.__v_isRef===!0:!1}function R(e){return Yt(e,!1)}function Jt(e){return Yt(e,!0)}function Yt(e,t){return L(e)?e:new Xt(e,t)}var Xt=class{constructor(e,t){this.dep=new Ye,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=t?e:I(e),this._value=t?e:Kt(e),this.__v_isShallow=t}get value(){return this.dep.track(),this._value}set value(e){let t=this._rawValue,n=this.__v_isShallow||Ut(e)||Ht(e);e=n?e:I(e),k(e,t)&&(this._rawValue=e,this._value=n?e:Kt(e),this.dep.trigger())}};function z(e){return L(e)?e.value:e}var Zt={get:(e,t,n)=>t===`__v_raw`?e:z(Reflect.get(e,t,n)),set:(e,t,n,r)=>{let i=e[t];return L(i)&&!L(n)?(i.value=n,!0):Reflect.set(e,t,n,r)}};function Qt(e){return Vt(e)?e:new Proxy(e,Zt)}function $t(e){let t=p(e)?Array(e.length):{};for(let n in e)t[n]=tn(e,n);return t}var en=class{constructor(e,t,n){this._object=e,this._defaultValue=n,this.__v_isRef=!0,this._value=void 0,this._key=y(t)?t:String(t),this._raw=I(e);let r=!0,i=e;if(!p(e)||y(this._key)||!te(this._key))do r=!Wt(i)||Ut(i);while(r&&(i=i.__v_raw));this._shallow=r}get value(){let e=this._object[this._key];return this._shallow&&(e=z(e)),this._value=e===void 0?this._defaultValue:e}set value(e){if(this._shallow&&L(this._raw[this._key])){let t=this._object[this._key];if(L(t)){t.value=e;return}}this._object[this._key]=e}get dep(){return rt(this._raw,this._key)}};function tn(e,t,n){return new en(e,t,n)}var nn=class{constructor(e,t,n){this.fn=e,this.setter=t,this._value=void 0,this.dep=new Ye(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=qe-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!t,this.isSSR=n}notify(){if(this.flags|=16,!(this.flags&8)&&F!==this)return Ne(this,!0),!0}get value(){let e=this.dep.track();return ze(this),e&&(e.version=this.dep.version),this._value}set value(e){this.setter&&this.setter(e)}};function rn(e,t,n=!1){let r,i;return _(e)?r=e:(r=e.get,i=e.set),new nn(r,i,n)}var an={},on=new WeakMap,sn=void 0;function cn(e,t=!1,n=sn){if(n){let t=on.get(n);t||on.set(n,t=[]),t.push(e)}}function ln(e,t,n=r){let{immediate:i,deep:o,once:s,scheduler:c,augmentJob:l,call:d}=n,f=e=>o?e:Ut(e)||o===!1||o===0?un(e,1):un(e),m,h,g,v,y=!1,b=!1;if(L(e)?(h=()=>e.value,y=Ut(e)):Vt(e)?(h=()=>f(e),y=!0):p(e)?(b=!0,y=e.some(e=>Vt(e)||Ut(e)),h=()=>e.map(e=>{if(L(e))return e.value;if(Vt(e))return f(e);if(_(e))return d?d(e,2):e()})):h=_(e)?t?d?()=>d(e,2):e:()=>{if(g){We();try{g()}finally{Ge()}}let t=sn;sn=m;try{return d?d(e,3,[v]):e(v)}finally{sn=t}}:a,t&&o){let e=h,t=o===!0?1/0:o;h=()=>un(e(),t)}let x=Ee(),S=()=>{m.stop(),x&&x.active&&u(x.effects,m)};if(s&&t){let e=t;t=(...t)=>{let n=e(...t);return S(),n}}let C=b?Array(e.length).fill(an):an,w=e=>{if(!(!(m.flags&1)||!m.dirty&&!e)){if(t){let n=m.run();if(e||o||y||(b?n.some((e,t)=>k(e,C[t])):k(n,C))){g&&g();let e=sn;sn=m;try{let e=[n,C===an?void 0:b&&C[0]===an?[]:C,v];C=n,d?d(t,3,e):t(...e)}finally{sn=e}}}else m.run()}};return l&&l(w),m=new ke(h),m.scheduler=c?()=>c(w,!1):w,v=e=>cn(e,!1,m),g=m.onStop=()=>{let e=on.get(m);if(e){if(d)d(e,4);else for(let t of e)t();on.delete(m)}},t?i?w(!0):C=m.run():c?c(w.bind(null,!0),!0):m.run(),S.pause=m.pause.bind(m),S.resume=m.resume.bind(m),S.stop=S,S}function un(e,t=1/0,n){if(t<=0||!b(e)||e.__v_skip||(n||=new Map,(n.get(e)||0)>=t))return e;if(n.set(e,t),t--,L(e))un(e.value,t,n);else if(p(e))for(let r=0;r{un(e,t,n)});else if(ee(e)){for(let r in e)un(e[r],t,n);for(let r of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,r)&&un(e[r],t,n)}return e}function dn(e,t,n,r){try{return r?e(...r):e()}catch(e){pn(e,t,n)}}function fn(e,t,n,r){if(_(e)){let i=dn(e,t,n,r);return i&&x(i)&&i.catch(e=>{pn(e,t,n)}),i}if(p(e)){let i=[];for(let a=0;a>>1,i=hn[r],a=kn(i);a=kn(n)?hn.push(e):hn.splice(Cn(t),0,e),e.flags|=1,Tn()}}function Tn(){xn||=bn.then(An)}function En(e){if(!p(e))vn&&e.id===-1?vn.splice(yn+1,0,e):e.flags&1||(_n.push(e),e.flags|=1);else for(let t=0;tkn(e)-kn(t));if(_n.length=0,vn){for(let t=0;te.id==null?e.flags&2?-1:1/0:e.id;function An(e){try{for(gn=0;gn{r._d&&Ji(-1);let i=Nn(t),a=Wi.length,o;try{o=e(...n)}finally{for(let e=Wi.length;e>a;e--)Ki();Nn(i),r._d&&Ji(1)}return o};return r._n=!0,r._c=!0,r._d=!0,r}function Fn(e,t){if(jn===null)return e;let n=Oa(jn),i=e.dirs||=[];for(let e=0;e1)return n&&_(t)?t.call(r&&r.proxy):t}}function zn(){return!!(ha()||Zr)}var Bn=Symbol.for(`v-scx`),Vn=()=>Rn(Bn);function Hn(e,t,n){return Un(e,t,n)}function Un(e,t,n=r){let{immediate:i,deep:o,flush:s,once:c}=n,u=l({},n),d=t&&i||!t&&s!==`post`,f;if(xa){if(s===`sync`){let e=Vn();f=e.__watcherHandles||=[]}else if(!d){let e=()=>{};return e.stop=a,e.resume=a,e.pause=a,e}}let p=ma;u.call=(e,t,n)=>fn(e,p,t,n);let m=!1;s===`post`?u.scheduler=e=>{Oi(e,p&&p.suspense)}:s!==`sync`&&(m=!0,u.scheduler=(e,t)=>{t?e():wn(e)}),u.augmentJob=e=>{t&&(e.flags|=4),m&&(e.flags|=2,p&&(e.id=p.uid,e.i=p))};let h=ln(e,t,u);return xa&&(f?f.push(h):d&&h()),h}function Wn(e,t,n){let r=this.proxy,i=v(e)?e.includes(`.`)?Gn(r,e):()=>r[e]:e.bind(r,r),a;_(t)?a=t:(a=t.handler,n=t);let o=va(this),s=Un(i,a.bind(r),n);return o(),s}function Gn(e,t){let n=t.split(`.`);return()=>{let t=e;for(let e=0;ee.__isTeleport,Jn=Symbol(`_leaveCb`);function Yn(e){let t=e[0];if(e.length>1){for(let n of e)if(n.type!==Hi){t=n;break}}return t}function Xn(e){if(!ar(e))return qn(e.type)&&e.children?Yn(e.children):e;if(e.component)return e.component.subTree;let{shapeFlag:t,children:n}=e;if(n){if(t&16)return n[0];if(t&32&&_(n.default))return n.default()}}function Zn(e,t){if(e.shapeFlag&6&&e.component){e.transition=t;let n=e.component.subTree;Zn(qn(n.type)&&Xn(n)||n,t)}else e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Qn(e,t){return _(e)?l({name:e.name},t,{setup:e}):e}function $n(e){e.ids=[e.ids[0]+e.ids[2]+++`-`,0,0]}function er(e,t){let n;return!!((n=Object.getOwnPropertyDescriptor(e,t))&&!n.configurable)}var tr=new WeakMap;function nr(e,t,n,i,a=!1){if(p(e)){e.forEach((e,r)=>nr(e,t&&(p(t)?t[r]:t),n,i,a));return}if(ir(i)&&!a){i.shapeFlag&512&&i.type.__asyncResolved&&i.component.subTree.component&&nr(e,t,n,i.component.subTree);return}let s=i.shapeFlag&4?Oa(i.component):i.el,c=a?null:s,{i:l,r:d}=e,m=t&&t.r,h=l.refs===r?l.refs={}:l.refs,g=l.setupState,y=I(g),b=g===r?o:e=>!er(h,e)&&f(y,e),x=(e,t)=>!(t&&er(h,t));if(m!=null&&m!==d){if(rr(t),v(m))h[m]=null,b(m)&&(g[m]=null);else if(L(m)){let e=t;x(m,e.k)&&(m.value=null),e.k&&(h[e.k]=null)}}if(_(d))dn(d,l,12,[c,h]);else{let t=v(d),r=L(d);if(t||r){let i=()=>{if(e.f){let n=t?b(d)?g[d]:h[d]:x(d)||!e.k?d.value:h[e.k];if(a)p(n)&&u(n,s);else if(p(n))n.includes(s)||n.push(s);else if(t)h[d]=[s],b(d)&&(g[d]=h[d]);else{let t=[s];x(d,e.k)&&(d.value=t),e.k&&(h[e.k]=t)}}else t?(h[d]=c,b(d)&&(g[d]=c)):r&&(x(d,e.k)&&(d.value=c),e.k&&(h[e.k]=c))};if(c){let t=()=>{i(),tr.delete(e)};t.id=-1,tr.set(e,t),Oi(t,n)}else rr(e),i()}}}function rr(e){let t=tr.get(e);t&&(t.flags|=8,tr.delete(e))}M().requestIdleCallback,M().cancelIdleCallback;var ir=e=>!!e.type.__asyncLoader,ar=e=>e.type.__isKeepAlive;function or(e,t){cr(e,`a`,t)}function sr(e,t){cr(e,`da`,t)}function cr(e,t,n=ma){let r=e.__wdc||=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}return e()};if(ur(t,r,n),n){let e=n.parent;for(;e&&e.parent;)ar(e.parent.vnode)&&lr(r,t,n,e),e=e.parent}}function lr(e,t,n,r){let i=ur(t,e,r,!0);_r(()=>{u(r[t],i)},n)}function ur(e,t,n=ma,r=!1){if(n){let i=n[e]||(n[e]=[]),a=t.__weh||=(...r)=>{We();let i=va(n),a=fn(t,n,e,r);return i(),Ge(),a};return r?i.unshift(a):i.push(a),a}}var dr=e=>(t,n=ma)=>{(!xa||e===`sp`)&&ur(e,(...e)=>t(...e),n)},fr=dr(`bm`),pr=dr(`m`),mr=dr(`bu`),hr=dr(`u`),gr=dr(`bum`),_r=dr(`um`),vr=dr(`sp`),yr=dr(`rtg`),br=dr(`rtc`);function xr(e,t=ma){ur(`ec`,e,t)}var Sr=`components`;function Cr(e,t){return Tr(Sr,e,!0,t)||e}var wr=Symbol.for(`v-ndc`);function Tr(e,t,n=!0,r=!1){let i=jn||ma;if(i){let n=i.type;if(e===Sr){let e=ka(n,!1);if(e&&(e===t||e===T(t)||e===O(T(t))))return n}let a=Er(i[e]||n[e],t)||Er(i.appContext[e],t);return!a&&r?n:a}}function Er(e,t){return e&&(e[t]||e[T(t)]||e[O(T(t))])}function Dr(e,t,n,r){let i,a=n&&n[r],o=p(e);if(o||v(e)){let n=o&&Vt(e),r=!1,s=!1;n&&(r=!Ut(e),s=Ht(e),e=at(e)),i=Array(e.length);for(let n=0,o=e.length;nt(e,n,void 0,a&&a[n]));else{let n=Object.keys(e);i=Array(n.length);for(let r=0,o=n.length;re?ba(e)?Oa(e):Or(e.parent):null,kr=l(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Or(e.parent),$root:e=>Or(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>Rr(e),$forceUpdate:e=>e.f||=()=>{wn(e.update)},$nextTick:e=>e.n||=Sn.bind(e.proxy),$watch:e=>Wn.bind(e)}),Ar=(e,t)=>e!==r&&!e.__isScriptSetup&&f(e,t),jr={get({_:e},t){if(t===`__v_skip`)return!0;let{ctx:n,setupState:i,data:a,props:o,accessCache:s,type:c,appContext:l}=e;if(t[0]!==`$`){let e=s[t];if(e!==void 0)switch(e){case 1:return i[t];case 2:return a[t];case 4:return n[t];case 3:return o[t]}else if(Ar(i,t))return s[t]=1,i[t];else if(a!==r&&f(a,t))return s[t]=2,a[t];else if(f(o,t))return s[t]=3,o[t];else if(n!==r&&f(n,t))return s[t]=4,n[t];else Nr&&(s[t]=0)}let u=kr[t],d,p;if(u)return t===`$attrs`&&tt(e.attrs,`get`,``),u(e);if((d=c.__cssModules)&&(d=d[t]))return d;if(n!==r&&f(n,t))return s[t]=4,n[t];if(p=l.config.globalProperties,f(p,t))return p[t]},set({_:e},t,n){let{data:i,setupState:a,ctx:o}=e;return Ar(a,t)?(a[t]=n,!0):i!==r&&f(i,t)?(i[t]=n,!0):f(e.props,t)||t[0]===`$`&&t.slice(1)in e?!1:(o[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:i,appContext:a,props:o,type:s}},c){let l;return!!(n[c]||e!==r&&c[0]!==`$`&&f(e,c)||Ar(t,c)||f(o,c)||f(i,c)||f(kr,c)||f(a.config.globalProperties,c)||(l=s.__cssModules)&&l[c])},defineProperty(e,t,n){return n.get==null?f(n,`value`)&&this.set(e,t,n.value,null):e._.accessCache[t]=0,Reflect.defineProperty(e,t,n)}};function Mr(e){return p(e)?e.reduce((e,t)=>(e[t]=null,e),{}):e}var Nr=!0;function Pr(e){let t=Rr(e),n=e.proxy,r=e.ctx;Nr=!1,t.beforeCreate&&Ir(t.beforeCreate,e,`bc`);let{data:i,computed:o,methods:s,watch:c,provide:l,inject:u,created:d,beforeMount:f,mounted:m,beforeUpdate:h,updated:g,activated:v,deactivated:y,beforeDestroy:x,beforeUnmount:S,destroyed:C,unmounted:w,render:ee,renderTracked:te,renderTriggered:ne,errorCaptured:re,serverPrefetch:ie,expose:T,inheritAttrs:E,components:D,directives:O,filters:ae}=t;if(u&&Fr(u,r,null),s)for(let e in s){let t=s[e];_(t)&&(r[e]=t.bind(n))}if(i){let t=i.call(n,n);b(t)&&(e.data=Lt(t))}if(Nr=!0,o)for(let e in o){let t=o[e],i=G({get:_(t)?t.bind(n,n):_(t.get)?t.get.bind(n,n):a,set:!_(t)&&_(t.set)?t.set.bind(n):a});Object.defineProperty(r,e,{enumerable:!0,configurable:!0,get:()=>i.value,set:e=>i.value=e})}if(c)for(let e in c)Lr(c[e],r,n,e);if(l){let e=_(l)?l.call(n):l;Reflect.ownKeys(e).forEach(t=>{Ln(t,e[t])})}d&&Ir(d,e,`c`);function k(e,t){p(t)?t.forEach(t=>e(t.bind(n))):t&&e(t.bind(n))}if(k(fr,f),k(pr,m),k(mr,h),k(hr,g),k(or,v),k(sr,y),k(xr,re),k(br,te),k(yr,ne),k(gr,S),k(_r,w),k(vr,ie),p(T)){if(T.length){let t=e.exposed||={};T.forEach(e=>{Object.defineProperty(t,e,{get:()=>n[e],set:t=>n[e]=t,enumerable:!0})})}else e.exposed||={}}ee&&e.render===a&&(e.render=ee),E!=null&&(e.inheritAttrs=E),D&&(e.components=D),O&&(e.directives=O),ie&&$n(e)}function Fr(e,t,n=a){p(e)&&(e=Ur(e));for(let n in e){let r=e[n],i;i=b(r)?`default`in r?Rn(r.from||n,r.default,!0):Rn(r.from||n):Rn(r),L(i)?Object.defineProperty(t,n,{enumerable:!0,configurable:!0,get:()=>i.value,set:e=>i.value=e}):t[n]=i}}function Ir(e,t,n){fn(p(e)?e.map(e=>e.bind(t.proxy)):e.bind(t.proxy),t,n)}function Lr(e,t,n,r){let i=r.includes(`.`)?Gn(n,r):()=>n[r];if(v(e)){let n=t[e];_(n)&&Hn(i,n)}else if(_(e))Hn(i,e.bind(n));else if(b(e)){if(p(e))e.forEach(e=>Lr(e,t,n,r));else{let r=_(e.handler)?e.handler.bind(n):t[e.handler];_(r)&&Hn(i,r,e)}}}function Rr(e){let t=e.type,{mixins:n,extends:r}=t,{mixins:i,optionsCache:a,config:{optionMergeStrategies:o}}=e.appContext,s=a.get(t),c;return s?c=s:!i.length&&!n&&!r?c=t:(c={},i.length&&i.forEach(e=>zr(c,e,o,!0)),zr(c,t,o)),b(t)&&a.set(t,c),c}function zr(e,t,n,r=!1){let{mixins:i,extends:a}=t;a&&zr(e,a,n,!0),i&&i.forEach(t=>zr(e,t,n,!0));for(let i in t)if(!(r&&i===`expose`)){let r=Br[i]||n&&n[i];e[i]=r?r(e[i],t[i]):t[i]}return e}var Br={data:Vr,props:Kr,emits:Kr,methods:Gr,computed:Gr,beforeCreate:Wr,created:Wr,beforeMount:Wr,mounted:Wr,beforeUpdate:Wr,updated:Wr,beforeDestroy:Wr,beforeUnmount:Wr,destroyed:Wr,unmounted:Wr,activated:Wr,deactivated:Wr,errorCaptured:Wr,serverPrefetch:Wr,components:Gr,directives:Gr,watch:qr,provide:Vr,inject:Hr};function Vr(e,t){return t?e?function(){return l(_(e)?e.call(this,this):e,_(t)?t.call(this,this):t)}:t:e}function Hr(e,t){return Gr(Ur(e),Ur(t))}function Ur(e){if(p(e)){let t={};for(let n=0;nt===`modelValue`||t===`model-value`?e.modelModifiers:e[`${t}Modifiers`]||e[`${T(t)}Modifiers`]||e[`${D(t)}Modifiers`];function $r(e,t,...n){if(e.isUnmounted)return;let i=e.vnode.props||r,a=n,o=t.startsWith(`update:`),s=o&&Qr(i,t.slice(7));s&&(s.trim&&(a=n.map(e=>v(e)?e.trim():e)),s.number&&(a=a.map(A)));let c,l=i[c=ae(t)]||i[c=ae(T(t))];!l&&o&&(l=i[c=ae(D(t))]),l&&fn(l,e,6,a);let u=i[c+`Once`];if(u){if(!e.emitted)e.emitted={};else if(e.emitted[c])return;e.emitted[c]=!0,fn(u,e,6,a)}}var ei=new WeakMap;function ti(e,t,n=!1){let r=n?ei:t.emitsCache,i=r.get(e);if(i!==void 0)return i;let a=e.emits,o={},s=!1;if(!_(e)){let r=e=>{let n=ti(e,t,!0);n&&(s=!0,l(o,n))};!n&&t.mixins.length&&t.mixins.forEach(r),e.extends&&r(e.extends),e.mixins&&e.mixins.forEach(r)}return!a&&!s?(b(e)&&r.set(e,null),null):(p(a)?a.forEach(e=>o[e]=null):l(o,a),b(e)&&r.set(e,o),o)}function ni(e,t){return!e||!s(t)?!1:(t=t.slice(2),t=t===`Once`?t:t.replace(/Once$/,``),f(e,t[0].toLowerCase()+t.slice(1))||f(e,D(t))||f(e,t))}function ri(e){let{type:t,vnode:n,proxy:r,withProxy:i,propsOptions:[a],slots:o,attrs:s,emit:l,render:u,renderCache:d,props:f,data:p,setupState:m,ctx:h,inheritAttrs:g}=e,_=Nn(e),v,y;try{if(n.shapeFlag&4){let e=i||r,t=e;v=oa(u.call(t,e,d,f,m,p,h)),y=s}else{let e=t;v=oa(e.length>1?e(f,{attrs:s,slots:o,emit:l}):e(f,null)),y=t.props?s:ii(s)}}catch(t){Wi.length=0,pn(t,e,1),v=ta(Hi)}let b=v;if(y&&g!==!1){let e=Object.keys(y),{shapeFlag:t}=b;e.length&&t&7&&(a&&e.some(c)&&(y=ai(y,a)),b=ia(b,y,!1,!0))}return n.dirs&&(b=ia(b,null,!1,!0),b.dirs=b.dirs?b.dirs.concat(n.dirs):n.dirs),n.transition&&Zn(qn(b.type)&&Xn(b)||b,n.transition),v=b,Nn(_),v}var ii=e=>{let t;for(let n in e)(n===`class`||n===`style`||s(n))&&((t||={})[n]=e[n]);return t},ai=(e,t)=>{let n={};for(let r in e)(!c(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function oi(e,t,n){let{props:r,children:i,component:a}=e,{props:o,children:s,patchFlag:c}=t,l=a.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&c>=0){if(c&1024)return!0;if(c&16)return r?si(r,o,l):!!o;if(c&8){let e=t.dynamicProps;for(let t=0;tObject.create(ui),fi=e=>Object.getPrototypeOf(e)===ui;function pi(e,t,n,r=!1){let i={},a=di();e.propsDefaults=Object.create(null),hi(e,t,i,a);for(let t in e.propsOptions[0])t in i||(i[t]=void 0);e.props=n?r?i:Rt(i):e.type.props?i:a,e.attrs=a}function mi(e,t,n,r){let{props:i,attrs:a,vnode:{patchFlag:o}}=e,s=I(i),[c]=e.propsOptions,l=!1;if((r||o>0)&&!(o&16)){if(o&8){let n=e.vnode.dynamicProps;for(let r=0;r{d=!0;let[n,r]=vi(e,t,!0);l(c,n),r&&u.push(...r)};!n&&t.mixins.length&&t.mixins.forEach(r),e.extends&&r(e.extends),e.mixins&&e.mixins.forEach(r)}if(!s&&!d)return b(e)&&a.set(e,i),i;if(p(s))for(let e=0;ee===`_`||e===`_ctx`||e===`$stable`,xi=e=>p(e)?e.map(oa):[oa(e)],Si=(e,t,n)=>{if(t._n)return t;let r=Pn((...e)=>xi(t(...e)),n);return r._c=!1,r},Ci=(e,t,n)=>{let r=e._ctx;for(let n in e){if(bi(n))continue;let i=e[n];if(_(i))t[n]=Si(n,i,r);else if(i!=null){let e=xi(i);t[n]=()=>e}}},wi=(e,t)=>{let n=xi(t);e.slots.default=()=>n},Ti=(e,t,n)=>{for(let r in t)(n||!bi(r))&&(e[r]=t[r])},Ei=(e,t,n)=>{let r=e.slots=di();if(e.vnode.shapeFlag&32){let e=t._;e?(Ti(r,t,n),n&&se(r,`_`,e,!0)):Ci(t,r)}else t&&wi(e,t)},Di=(e,t,n)=>{let{vnode:i,slots:a}=e,o=!0,s=r;if(i.shapeFlag&32){let e=t._;e?n&&e===1?o=!1:Ti(a,t,n):(o=!t.$stable,Ci(t,a)),s=t}else t&&(wi(e,t),s={default:1});if(o)for(let e in a)!bi(e)&&s[e]==null&&delete a[e]},Oi=Bi;function ki(e){return Ai(e)}function Ai(e,t){let n=M();n.__VUE__=!0;let{insert:o,remove:s,patchProp:c,createElement:l,createText:u,createComment:d,setText:f,setElementText:p,parentNode:m,nextSibling:h,setScopeId:g=a,insertStaticContent:_}=e,v=(e,t,n,r=null,i=null,a=null,o=void 0,s=null,c=!!t.dynamicChildren)=>{if(e===t)return;e&&!Qi(e,t)&&(r=ge(e),de(e,i,a,!0),e=null),t.patchFlag===-2&&(c=!1,t.dynamicChildren=null);let{type:l,ref:u,shapeFlag:d}=t;switch(l){case Vi:y(e,t,n,r);break;case Hi:b(e,t,n,r);break;case Ui:e??x(t,n,r,o);break;case B:D(e,t,n,r,i,a,o,s,c);break;default:d&1?w(e,t,n,r,i,a,o,s,c):d&6?O(e,t,n,r,i,a,o,s,c):(d&64||d&128)&&l.process(e,t,n,r,i,a,o,s,c,ye)}u!=null&&i?nr(u,e&&e.ref,a,t||e,!t):u==null&&e&&e.ref!=null&&nr(e.ref,null,a,e,!0)},y=(e,t,n,r)=>{if(e==null)o(t.el=u(t.children),n,r);else{let n=t.el=e.el;t.children!==e.children&&f(n,t.children)}},b=(e,t,n,r)=>{e==null?o(t.el=d(t.children||``),n,r):t.el=e.el},x=(e,t,n,r)=>{[e.el,e.anchor]=_(e.children,t,n,r,e.el,e.anchor)},S=({el:e,anchor:t},n,r)=>{let i;for(;e&&e!==t;)i=h(e),o(e,n,r),e=i;o(t,n,r)},C=({el:e,anchor:t})=>{let n;for(;e&&e!==t;)n=h(e),s(e),e=n;s(t)},w=(e,t,n,r,i,a,o,s,c)=>{if(t.type===`svg`?o=`svg`:t.type===`math`&&(o=`mathml`),e==null)ee(t,n,r,i,a,o,s,c);else{let n=e.el&&e.el._isVueCE?e.el:null;try{n&&n._beginPatch(),ie(e,t,i,a,o,s,c)}finally{n&&n._endPatch()}}},ee=(e,t,n,r,i,a,s,u)=>{let d,f,{props:m,shapeFlag:h,transition:g,dirs:_}=e;if(d=e.el=l(e.type,a,m&&m.is,m),h&8?p(d,e.children):h&16&&re(e.children,d,null,r,i,ji(e,a),s,u),_&&In(e,null,r,`created`),te(d,e,e.scopeId,s,r),m){for(let e in m)e!==`value`&&!ne(e)&&c(d,e,null,m[e],a,r);`value`in m&&c(d,`value`,null,m.value,a),(f=m.onVnodeBeforeMount)&&ua(f,r,e)}_&&In(e,null,r,`beforeMount`);let v=Ni(i,g);v&&g.beforeEnter(d),o(d,t,n),((f=m&&m.onVnodeMounted)||v||_)&&Oi(()=>{try{f&&ua(f,r,e),v&&g.enter(d),_&&In(e,null,r,`mounted`)}finally{}},i)},te=(e,t,n,r,i)=>{if(n&&g(e,n),r)for(let t=0;t{for(let l=c;l{let l=t.el=e.el,{patchFlag:u,dynamicChildren:d,dirs:f}=t;u|=e.patchFlag&16;let m=e.props||r,h=t.props||r,g;if(n&&Mi(n,!1),(g=h.onVnodeBeforeUpdate)&&ua(g,n,t,e),f&&In(t,e,n,`beforeUpdate`),n&&Mi(n,!0),d&&(!e.dynamicChildren||e.dynamicChildren.length!==d.length)&&(u=0,s=!1,d=null),(m.innerHTML&&h.innerHTML==null||m.textContent&&h.textContent==null)&&p(l,``),d?T(e.dynamicChildren,d,l,n,i,ji(t,a),o):s||j(e,t,l,null,n,i,ji(t,a),o,!1),u>0){if(u&16)E(l,m,h,n,a);else if(u&2&&m.class!==h.class&&c(l,`class`,null,h.class,a),u&4&&c(l,`style`,m.style,h.style,a),u&8){let e=t.dynamicProps;for(let t=0;t{g&&ua(g,n,t,e),f&&In(t,e,n,`updated`)},i)},T=(e,t,n,r,i,a,o)=>{for(let s=0;s{if(t!==n){if(t!==r)for(let r in t)!ne(r)&&!(r in n)&&c(e,r,t[r],null,a,i);for(let r in n){if(ne(r))continue;let o=n[r],s=t[r];o!==s&&r!==`value`&&c(e,r,s,o,a,i)}`value`in n&&c(e,`value`,t.value,n.value,a)}},D=(e,t,n,r,i,a,s,c,l)=>{let d=t.el=e?e.el:u(``),f=t.anchor=e?e.anchor:u(``),{patchFlag:p,dynamicChildren:m,slotScopeIds:h}=t;h&&(c=c?c.concat(h):h),e==null?(o(d,n,r),o(f,n,r),re(t.children||[],n,f,i,a,s,c,l)):p>0&&p&64&&m&&e.dynamicChildren&&e.dynamicChildren.length===m.length?(T(e.dynamicChildren,m,n,i,a,s,c),(t.key!=null||i&&t===i.subTree)&&Pi(e,t,!0)):j(e,t,n,f,i,a,s,c,l)},O=(e,t,n,r,i,a,o,s,c)=>{t.slotScopeIds=s,e==null?t.shapeFlag&512?i.ctx.activate(t,n,r,o,c):ae(t,n,r,i,a,o,c):k(e,t,c)},ae=(e,t,n,r,i,a,o)=>{let s=e.component=pa(e,r,i);if(ar(e)&&(s.ctx.renderer=ye),Sa(s,!1,o),s.asyncDep){if(i&&i.registerDep(s,se,o),!e.el){let r=s.subTree=ta(Hi);b(null,r,t,n),e.placeholder=r.el}}else se(s,e,t,n,i,a,o)},k=(e,t,n)=>{let r=t.component=e.component;if(oi(e,t,n)){if(r.asyncDep&&!r.asyncResolved){A(r,t,n);return}r.next=t,r.update()}else t.el=e.el,r.vnode=t},se=(e,t,n,r,i,a,o)=>{let s=()=>{if(e.isMounted){let{next:t,bu:n,u:r,parent:s,vnode:c}=e;{let n=Ii(e);if(n){t&&(t.el=c.el,A(e,t,o)),n.asyncDep.then(()=>{Oi(()=>{e.isUnmounted||l()},i)});return}}let u=t,d;Mi(e,!1),t?(t.el=c.el,A(e,t,o)):t=c,n&&oe(n),(d=t.props&&t.props.onVnodeBeforeUpdate)&&ua(d,s,t,c),Mi(e,!0);let f=ri(e),p=e.subTree;e.subTree=f,v(p,f,m(p.el),ge(p),e,i,a),t.el=f.el,u===null&&li(e,f.el),r&&Oi(r,i),(d=t.props&&t.props.onVnodeUpdated)&&Oi(()=>ua(d,s,t,c),i)}else{let o,{el:s,props:c}=t,{bm:l,m:u,parent:d,root:f,type:p}=e,m=ir(t);if(Mi(e,!1),l&&oe(l),!m&&(o=c&&c.onVnodeBeforeMount)&&ua(o,d,t),Mi(e,!0),s&&xe){let t=()=>{e.subTree=ri(e),xe(s,e.subTree,e,i,null)};m&&p.__asyncHydrate?p.__asyncHydrate(s,e,t):t()}else{f.ce&&f.ce._hasShadowRoot()&&f.ce._injectChildStyle(p,e.parent?e.parent.type:void 0);let o=e.subTree=ri(e);v(null,o,n,r,e,i,a),t.el=o.el}if(u&&Oi(u,i),!m&&(o=c&&c.onVnodeMounted)){let e=t;Oi(()=>ua(o,d,e),i)}(t.shapeFlag&256||d&&ir(d.vnode)&&d.vnode.shapeFlag&256)&&e.a&&Oi(e.a,i),e.isMounted=!0,t=n=r=null}};e.scope.on();let c=e.effect=new ke(s);e.scope.off();let l=e.update=c.run.bind(c),u=e.job=c.runIfDirty.bind(c);u.i=e,u.id=e.uid,c.scheduler=()=>wn(u),Mi(e,!0),l()},A=(e,t,n)=>{t.component=e;let r=e.vnode.props;e.vnode=t,e.next=null,mi(e,t.props,r,n),Di(e,t.children,n),We(),Dn(e),Ge()},j=(e,t,n,r,i,a,o,s,c=!1)=>{let l=e&&e.children,u=e?e.shapeFlag:0,d=t.children,{patchFlag:f,shapeFlag:m}=t;if(f>0){if(f&128){le(l,d,n,r,i,a,o,s,c);return}if(f&256){ce(l,d,n,r,i,a,o,s,c);return}}m&8?(u&16&&he(l,i,a),d!==l&&p(n,d)):u&16?m&16?le(l,d,n,r,i,a,o,s,c):he(l,i,a,!0):(u&8&&p(n,``),m&16&&re(d,n,r,i,a,o,s,c))},ce=(e,t,n,r,a,o,s,c,l)=>{e||=i,t||=i;let u=e.length,d=t.length,f=Math.min(u,d),p;for(p=0;pd?he(e,a,o,!0,!1,f):re(t,n,r,a,o,s,c,l,f)},le=(e,t,n,r,a,o,s,c,l)=>{let u=0,d=t.length,f=e.length-1,p=d-1;for(;u<=f&&u<=p;){let r=e[u],i=t[u]=l?sa(t[u]):oa(t[u]);if(Qi(r,i))v(r,i,n,null,a,o,s,c,l);else break;u++}for(;u<=f&&u<=p;){let r=e[f],i=t[p]=l?sa(t[p]):oa(t[p]);if(Qi(r,i))v(r,i,n,null,a,o,s,c,l);else break;f--,p--}if(u>f){if(u<=p){let e=p+1,i=ep)for(;u<=f;)de(e[u],a,o,!0),u++;else{let m=u,h=u,g=new Map;for(u=h;u<=p;u++){let e=t[u]=l?sa(t[u]):oa(t[u]);e.key!=null&&g.set(e.key,u)}let _,y=0,b=p-h+1,x=!1,S=0,C=Array(b);for(u=0;u=b){de(r,a,o,!0);continue}let i;if(r.key!=null)i=g.get(r.key);else for(_=h;_<=p;_++)if(C[_-h]===0&&Qi(r,t[_])){i=_;break}i===void 0?de(r,a,o,!0):(C[i-h]=u+1,i>=S?S=i:x=!0,v(r,t[i],n,null,a,o,s,c,l),y++)}let w=x?Fi(C):i;for(_=w.length-1,u=b-1;u>=0;u--){let e=h+u,i=t[e],f=t[e+1],p=e+1{let{el:a,type:c,transition:l,children:u,shapeFlag:d}=e;if(d&6){ue(e.component.subTree,t,n,r);return}if(d&128){e.suspense.move(t,n,r);return}if(d&64){c.move(e,t,n,ye);return}if(c===B){o(a,t,n);for(let e=0;el.enter(a),i));else{let{leave:r,delayLeave:i,afterLeave:c}=l,u=()=>{e.ctx.isUnmounted?s(a):o(a,t,n)},d=()=>{let e=a._isLeaving||!!a[Jn];a._isLeaving&&a[Jn](!0),l.persisted&&!e?u():r(a,()=>{u(),c&&c()})};i?i(a,u,d):d()}}else o(a,t,n)},de=(e,t,n,r=!1,i=!1)=>{let{type:a,props:o,ref:s,children:c,dynamicChildren:l,shapeFlag:u,patchFlag:d,dirs:f,cacheIndex:p,memo:m}=e;if(d===-2&&(i=!1),s!=null&&(We(),nr(s,null,n,e,!0),Ge()),p!=null&&(t.renderCache[p]=void 0),u&256){t.ctx.deactivate(e);return}let h=u&1&&f,g=!ir(e),_;if(g&&(_=o&&o.onVnodeBeforeUnmount)&&ua(_,t,e),u&6)me(e.component,n,r);else{if(u&128){e.suspense.unmount(n,r);return}h&&In(e,null,t,`beforeUnmount`),u&64?e.type.remove(e,t,n,ye,r):l&&!l.hasOnce&&(a!==B||d>0&&d&64)?he(l,t,n,!1,!0):(a===B&&d&384||!i&&u&16)&&he(c,t,n),r&&fe(e)}let v=m!=null&&p==null;(g&&(_=o&&o.onVnodeUnmounted)||h||v)&&Oi(()=>{_&&ua(_,t,e),h&&In(e,null,t,`unmounted`),v&&(e.el=null)},n)},fe=e=>{let{type:t,el:n,anchor:r,transition:i}=e;if(t===B){pe(n,r);return}if(t===Ui){C(e);return}let a=()=>{s(n),i&&!i.persisted&&i.afterLeave&&i.afterLeave()};if(e.shapeFlag&1&&i&&!i.persisted){let{leave:t,delayLeave:r}=i,o=()=>t(n,a);r?r(e.el,a,o):o()}else a()},pe=(e,t)=>{let n;for(;e!==t;)n=h(e),s(e),e=n;s(t)},me=(e,t,n)=>{let{bum:r,scope:i,job:a,subTree:o,um:s,m:c,a:l}=e;Li(c),Li(l),r&&oe(r),i.stop(),a&&(a.flags|=8,de(o,e,t,n)),s&&Oi(s,t),Oi(()=>{e.isUnmounted=!0},t)},he=(e,t,n,r=!1,i=!1,a=0)=>{for(let o=a;o{if(e.shapeFlag&6)return ge(e.component.subTree);if(e.shapeFlag&128)return e.suspense.next();let t=h(e.anchor||e.el),n=t&&t[Kn];return n?h(n):t},_e=!1,ve=(e,t,n)=>{let r;e==null?t._vnode&&(de(t._vnode,null,null,!0),r=t._vnode.component):v(t._vnode||null,e,t,null,null,null,n),t._vnode=e,_e||=(_e=!0,Dn(r),On(),!1)},ye={p:v,um:de,m:ue,r:fe,mt:ae,mc:re,pc:j,pbc:T,n:ge,o:e},be,xe;return t&&([be,xe]=t(ye)),{render:ve,hydrate:be,createApp:Xr(ve,be)}}function ji({type:e,props:t},n){return n===`svg`&&e===`foreignObject`||n===`mathml`&&e===`annotation-xml`&&t&&t.encoding&&t.encoding.includes(`html`)?void 0:n}function Mi({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function Ni(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Pi(e,t,n=!1){let r=e.children,i=t.children;if(p(r)&&p(i))for(let e=0;e>1,e[n[s]]0&&(t[r]=n[a-1]),n[a]=r)}}for(a=n.length,o=n[a-1];a-->0;)n[a]=o,o=t[o];return n}function Ii(e){let t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:Ii(t)}function Li(e){if(e)for(let t=0;te.__isSuspense;function Bi(e,t){t&&t.pendingBranch?p(e)?t.effects.push(...e):t.effects.push(e):En(e)}var B=Symbol.for(`v-fgt`),Vi=Symbol.for(`v-txt`),Hi=Symbol.for(`v-cmt`),Ui=Symbol.for(`v-stc`),Wi=[],Gi=null;function V(e=!1){Wi.push(Gi=e?null:[])}function Ki(){Wi.pop(),Gi=Wi[Wi.length-1]||null}var qi=1;function Ji(e,t=!1){qi+=e,e<0&&Gi&&t&&(Gi.hasOnce=!0)}function Yi(e){return e.dynamicChildren=qi>0?Gi||i:null,Ki(),qi>0&&Gi&&Gi.push(e),e}function H(e,t,n,r,i,a){return Yi(U(e,t,n,r,i,a,!0))}function Xi(e,t,n,r,i){return Yi(ta(e,t,n,r,i,!0))}function Zi(e){return e?e.__v_isVNode===!0:!1}function Qi(e,t){return e.type===t.type&&e.key===t.key}var $i=({key:e})=>e??null,ea=({ref:e,ref_key:t,ref_for:n})=>(typeof e==`number`&&(e=``+e),e==null?null:v(e)||L(e)||_(e)?{i:jn,r:e,k:t,f:!!n}:e);function U(e,t=null,n=null,r=0,i=null,a=e===B?0:1,o=!1,s=!1){let c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&$i(t),ref:t&&ea(t),scopeId:Mn,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:a,patchFlag:r,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:jn};return s?(ca(c,n),a&128&&e.normalize(c)):n&&(c.shapeFlag|=v(n)?8:16),qi>0&&!o&&Gi&&(c.patchFlag>0||a&6)&&c.patchFlag!==32&&Gi.push(c),c}var ta=na;function na(e,t=null,n=null,r=0,i=null,a=!1){if((!e||e===wr)&&(e=Hi),Zi(e)){let r=ia(e,t,!0);return n&&ca(r,n),qi>0&&!a&&Gi&&(r.shapeFlag&6?Gi[Gi.indexOf(e)]=r:Gi.push(r)),r.patchFlag=-2,r}if(Aa(e)&&(e=e.__vccOpts),t){t=ra(t);let{class:e,style:n}=t;e&&!v(e)&&(t.class=pe(e)),b(n)&&(Wt(n)&&!p(n)&&(n=l({},n)),t.style=ce(n))}let o=v(e)?1:zi(e)?128:qn(e)?64:b(e)?4:_(e)?2:0;return U(e,t,n,r,i,o,a,!0)}function ra(e){return e?Wt(e)||fi(e)?l({},e):e:null}function ia(e,t,n=!1,r=!1){let{props:i,ref:a,patchFlag:o,children:s,transition:c}=e,l=t?la(i||{},t):i,u={__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&$i(l),ref:t&&t.ref?n&&a?p(a)?a.concat(ea(t)):[a,ea(t)]:ea(t):a,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:s,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==B?o===-1?16:o|16:o,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:c,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&ia(e.ssContent),ssFallback:e.ssFallback&&ia(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return c&&r&&Zn(u,c.clone(u)),u}function aa(e=` `,t=0){return ta(Vi,null,e,t)}function W(e=``,t=!1){return t?(V(),Xi(Hi,null,e)):ta(Hi,null,e)}function oa(e){return e==null||typeof e==`boolean`?ta(Hi):p(e)?ta(B,null,e.slice()):Zi(e)?sa(e):ta(Vi,null,String(e))}function sa(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:ia(e)}function ca(e,t){let n=0,{shapeFlag:r}=e;if(t==null)t=null;else if(p(t))n=16;else if(typeof t==`object`){if(r&65){let n=t.default;n&&(n._c&&(n._d=!1),ca(e,n()),n._c&&(n._d=!0));return}{n=32;let r=t._;!r&&!fi(t)?t._ctx=jn:r===3&&jn&&(jn.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}}else if(_(t)){if(r&65){ca(e,{default:t});return}t={default:t,_ctx:jn},n=32}else t=String(t),r&64?(n=16,t=[aa(t)]):n=8;e.children=t,e.shapeFlag|=n}function la(...e){let t={};for(let n=0;nma||jn,ga,_a;{let e=M(),t=(t,n)=>{let r;return(r=e[t])||(r=e[t]=[]),r.push(n),e=>{r.length>1?r.forEach(t=>t(e)):r[0](e)}};ga=t(`__VUE_INSTANCE_SETTERS__`,e=>ma=e),_a=t(`__VUE_SSR_SETTERS__`,e=>xa=e)}var va=e=>{let t=ma;return ga(e),e.scope.on(),()=>{e.scope.off(),ga(t)}},ya=()=>{ma&&ma.scope.off(),ga(null)};function ba(e){return e.vnode.shapeFlag&4}var xa=!1;function Sa(e,t=!1,n=!1){t&&_a(t);let{props:r,children:i}=e.vnode,a=ba(e);pi(e,r,a,t),Ei(e,i,n||t);let o=a?Ca(e,t):void 0;return t&&_a(!1),o}function Ca(e,t){let n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,jr);let{setup:r}=n;if(r){We();let n=e.setupContext=r.length>1?Da(e):null,i=va(e),a=dn(r,e,0,[e.props,n]),o=x(a);if(Ge(),i(),(o||e.sp)&&!ir(e)&&$n(e),o){if(a.then(ya,ya),t)return a.then(n=>{_a(!0);try{wa(e,n,t)}finally{_a(!1)}}).catch(t=>{pn(t,e,0)});e.asyncDep=a}else wa(e,a,t)}else Ta(e,t)}function wa(e,t,n){_(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:b(t)&&(e.setupState=Qt(t)),Ta(e,n)}function Ta(e,t,n){let r=e.type;e.render||=r.render||a;{let t=va(e);We();try{Pr(e)}finally{Ge(),t()}}}var Ea={get(e,t){return tt(e,`get`,``),e[t]}};function Da(e){return{attrs:new Proxy(e.attrs,Ea),slots:e.slots,emit:e.emit,expose:t=>{e.exposed=t||{}}}}function Oa(e){return e.exposed?e.exposeProxy||=new Proxy(Qt(Gt(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in kr)return kr[n](e)},has(e,t){return t in e||t in kr}}):e.proxy}function ka(e,t=!0){return _(e)?e.displayName||e.name:e.name||t&&e.__name}function Aa(e){return _(e)&&`__vccOpts`in e}var G=(e,t)=>rn(e,t,xa);function ja(e,t,n){try{Ji(-1);let r=arguments.length;return r===2?b(t)&&!p(t)?Zi(t)?ta(e,null,[t]):ta(e,t):ta(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&Zi(n)&&(n=[n]),ta(e,t,n))}finally{Ji(1)}}var Ma=`3.5.42`,Na=void 0,Pa=typeof window<`u`&&window.trustedTypes;if(Pa)try{Na=Pa.createPolicy(`vue`,{createHTML:e=>e})}catch{}var Fa=Na?e=>Na.createHTML(e):e=>e,Ia=`http://www.w3.org/2000/svg`,La=`http://www.w3.org/1998/Math/MathML`,Ra=typeof document<`u`?document:null,za=Ra&&Ra.createElement(`template`),Ba={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{let t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{let i=t===`svg`?Ra.createElementNS(Ia,e):t===`mathml`?Ra.createElementNS(La,e):n?Ra.createElement(e,{is:n}):Ra.createElement(e);return e===`select`&&r&&r.multiple!=null&&i.setAttribute(`multiple`,r.multiple),i},createText:e=>Ra.createTextNode(e),createComment:e=>Ra.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Ra.querySelector(e),setScopeId(e,t){e.setAttribute(t,``)},insertStaticContent(e,t,n,r,i,a){let o=n?n.previousSibling:t.lastChild;if(i&&(i===a||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),n),!(i===a||!(i=i.nextSibling)););else{za.innerHTML=Fa(r===`svg`?`${e}`:r===`mathml`?`${e}`:e);let i=za.content;if(r===`svg`||r===`mathml`){let e=i.firstChild;for(;e.firstChild;)i.appendChild(e.firstChild);i.removeChild(e)}t.insertBefore(i,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Va=Symbol(`_vtc`);function Ha(e,t,n){let r=e[Va];r&&(t=(t?[t,...r]:[...r]).join(` `)),t==null?e.removeAttribute(`class`):n?e.setAttribute(`class`,t):e.className=t}var Ua=Symbol(`_vod`),Wa=Symbol(`_vsh`),Ga=Symbol(``),Ka=/(?:^|;)\s*display\s*:/;function qa(e,t,n){let r=e.style,i=v(n),a=!1;if(n&&!i){if(t){if(v(t))for(let e of t.split(`;`)){let t=e.slice(0,e.indexOf(`:`)).trim();n[t]??Ya(r,t,``)}else for(let e in t)n[e]??Ya(r,e,``)}for(let i in n){i===`display`&&(a=!0);let o=n[i];o==null?Ya(r,i,``):$a(e,i,!v(t)&&t?t[i]:void 0,o)||Ya(r,i,o)}}else if(i){if(t!==n){let e=r[Ga];e&&(n+=`;`+e),r.cssText=n,a=Ka.test(n)}}else t&&e.removeAttribute(`style`);Ua in e&&(e[Ua]=a?r.display:``,e[Wa]&&(r.display=`none`))}var Ja=/\s*!important$/;function Ya(e,t,n){if(p(n))n.forEach(n=>Ya(e,t,n));else if(n??=``,t.startsWith(`--`))Ja.test(n)?e.setProperty(t,n.replace(Ja,``),`important`):e.setProperty(t,n);else{let r=Qa(e,t);Ja.test(n)?e.setProperty(D(r),n.replace(Ja,``),`important`):e[r]=n}}var Xa=[`Webkit`,`Moz`,`ms`],Za={};function Qa(e,t){let n=Za[t];if(n)return n;let r=T(t);if(r!==`filter`&&r in e)return Za[t]=r;r=O(r);for(let n=0;nuo||=(fo.then(()=>uo=0),Date.now());function mo(e,t){let n=e=>{if(!e._vts)e._vts=Date.now();else if(e._vts<=n.attached)return;let r=n.value;if(p(r)){let n=e.stopImmediatePropagation;e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0};let i=r.slice(),a=[e];for(let n=0;ne.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,go=(e,t,n,r,i,a)=>{let o=i===`svg`;t===`class`?Ha(e,r,o):t===`style`?qa(e,n,r):s(t)?c(t)||oo(e,t,n,r,a):(t[0]===`.`?(t=t.slice(1),!0):t[0]===`^`?(t=t.slice(1),!1):_o(e,t,r,o))?(no(e,t,r),!e.tagName.includes(`-`)&&(t===`value`||t===`checked`||t===`selected`)&&to(e,t,r,o,a,t!==`value`)):e._isVueCE&&(vo(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!v(r)))?no(e,T(t),r,a,t):(t===`true-value`?e._trueValue=r:t===`false-value`&&(e._falseValue=r),to(e,t,r,o))};function _o(e,t,n,r){if(r)return!!(t===`innerHTML`||t===`textContent`||t in e&&ho(t)&&_(n));if(t===`spellcheck`||t===`draggable`||t===`translate`||t===`autocorrect`||t===`sandbox`&&e.tagName===`IFRAME`||t===`form`||t===`list`&&e.tagName===`INPUT`||t===`type`&&e.tagName===`TEXTAREA`)return!1;if(t===`width`||t===`height`){let t=e.tagName;if(t===`IMG`||t===`VIDEO`||t===`CANVAS`||t===`SOURCE`)return!1}return ho(t)&&v(n)?!1:t in e}function vo(e,t){let n=e._def.props;if(!n)return!1;let r=T(t);return Array.isArray(n)?n.some(e=>T(e)===r):Object.keys(n).some(e=>T(e)===r)}var yo=e=>{let t=e.props[`onUpdate:modelValue`]||!1;return p(t)?e=>oe(t,e):t};function bo(e){e.target.composing=!0}function xo(e){let t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event(`input`)))}var So=Symbol(`_assign`),Co=Symbol(`_initialValue`);function wo(e,t,n){return t&&(e=e.trim()),n&&(e=A(e)),e}var To={created(e,{modifiers:{lazy:t,trim:n,number:r}},i){e.parentNode&&(e.type===`text`?e[Co]=e.defaultValue.replace(/[\r\n]/g,``):e.type===`textarea`&&(e[Co]=e.defaultValue.replace(/\r\n?/g,` `))),e[So]=yo(i);let a=r||i.props&&i.props.type===`number`;ro(e,t?`change`:`input`,t=>{t.target.composing||e[So](wo(e.value,n,a))}),(n||a)&&ro(e,`change`,()=>{e.value=wo(e.value,n,a)}),t||(ro(e,`compositionstart`,bo),ro(e,`compositionend`,xo),ro(e,`change`,xo))},mounted(e,{value:t,modifiers:{trim:n,number:r}}){let i=t??``,a=e[Co];delete e[Co],a!==void 0&&(e.type===`text`||e.type===`textarea`)&&e.value!==a?e[So](wo(e.value,n,r)):e.value=i},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:r,trim:i,number:a}},o){if(e[So]=yo(o),e.composing)return;let s=(a||e.type===`number`)&&!/^0\d/.test(e.value)?A(e.value):e.value,c=t??``;if(s===c)return;let l=e.getRootNode();(l instanceof Document||l instanceof ShadowRoot)&&l.activeElement===e&&e.type!==`range`&&(r&&t===n||i&&e.value.trim()===c)||(e.value=c)}},Eo={deep:!0,created(e,t,n){e[So]=yo(n),ro(e,`change`,()=>{let t=e._modelValue,n=jo(e),r=e.checked,i=e[So];if(p(t)){let e=be(t,n),a=e!==-1;if(r&&!a)i(t.concat(n));else if(!r&&a){let n=[...t];n.splice(e,1),i(n)}}else if(h(t)){let e=new Set(t);r?e.add(n):e.delete(n),i(e)}else i(Mo(e,r))})},mounted:Do,beforeUpdate(e,t,n){e[So]=yo(n),Do(e,t,n)}};function Do(e,{value:t,oldValue:n},r){e._modelValue=t;let i;if(p(t))i=be(t,r.props.value)>-1;else if(h(t))i=t.has(r.props.value);else{if(t===n)return;i=ye(t,Mo(e,!0))}e.checked!==i&&(e.checked=i)}var Oo={deep:!0,created(e,{value:t,modifiers:{number:n}},r){e._modelValue=t,ro(e,`change`,()=>{let t=Array.prototype.filter.call(e.options,e=>e.selected).map(e=>n?A(jo(e)):jo(e)),r=e.multiple,i=r?h(e._modelValue)?new Set(t):t:t[0],a=e._pendingValue=[r,r?p(i)?t.slice():t:i];try{e[So](i)}finally{Sn(()=>{e._pendingValue===a&&(e._pendingValue=void 0)})}}),e[So]=yo(r)},mounted(e,{value:t}){Ao(e,t)},beforeUpdate(e,{value:t},n){e._modelValue=t,e[So]=yo(n)},updated(e,{value:t}){let n=e._pendingValue;e._pendingValue=void 0,(!n||n[0]!==e.multiple||!ko(t,n[1],n[0]))&&Ao(e,t)}};function ko(e,t,n){if(!n||p(e))return ye(e,t);if(h(e)){if(e.size!==t.length)return!1;for(let n of t)if(!e.has(n))return!1;return!0}return!1}function Ao(e,t){let n=e.multiple,r=p(t);if(!(n&&!r&&!h(t))){for(let i=0,a=e.options.length;iString(e)===String(o)):be(t,o)>-1}else a.selected=t.has(o)}else if(ye(jo(a),t)){e.selectedIndex!==i&&(e.selectedIndex=i);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function jo(e){return`_value`in e?e._value:e.value}function Mo(e,t){let n=t?`_trueValue`:`_falseValue`;return n in e?e[n]:t}var No=[`ctrl`,`shift`,`alt`,`meta`],Po={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>`button`in e&&e.button!==0,middle:e=>`button`in e&&e.button!==1,right:e=>`button`in e&&e.button!==2,exact:(e,t)=>No.some(n=>e[`${n}Key`]&&!t.includes(n))},Fo=(e,t)=>{if(!e)return e;let n=e._withMods||={},r=t.join(`.`);return n[r]||(n[r]=((n,...r)=>{for(let e=0;e{let n=e._withKeys||={},r=t.join(`.`);return n[r]||(n[r]=(n=>{if(!(`key`in n))return;let r=D(n.key);if(t.some(e=>e===r||Io[e]===r))return e(n)}))},Ro=l({patchProp:go},Ba),zo;function Bo(){return zo||=ki(Ro)}var Vo=((...e)=>{let t=Bo().createApp(...e),{mount:n}=t;return t.mount=e=>{let r=Uo(e);if(!r)return;let i=t._component;!_(i)&&!i.render&&!i.template&&(i.template=r.innerHTML),r.nodeType===1&&(r.textContent=``);let a=n(r,!1,Ho(r));return r instanceof Element&&(r.removeAttribute(`v-cloak`),r.setAttribute(`data-v-app`,``)),a},t});function Ho(e){if(e instanceof SVGElement)return`svg`;if(typeof MathMLElement==`function`&&e instanceof MathMLElement)return`mathml`}function Uo(e){return v(e)?document.querySelector(e):e}var Wo=typeof window<`u`,Go,Ko=e=>Go=e,qo=Symbol();function Jo(e){return e&&typeof e==`object`&&Object.prototype.toString.call(e)===`[object Object]`&&typeof e.toJSON!=`function`}var Yo=typeof window==`object`&&window.window===window?window:typeof self==`object`&&self.self===self?self:typeof global==`object`&&global.global===global?global:typeof globalThis==`object`?globalThis:{HTMLElement:null};function Xo(e,{autoBom:t=!1}={}){return t&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)?new Blob([``,e],{type:e.type}):e}function Zo(e,t,n){let r=new XMLHttpRequest;r.open(`GET`,e),r.responseType=`blob`,r.onload=function(){ns(r.response,t,n)},r.onerror=function(){console.error(`could not download file`)},r.send()}function Qo(e){let t=new XMLHttpRequest;t.open(`HEAD`,e,!1);try{t.send()}catch{}return t.status>=200&&t.status<=299}function $o(e){try{e.dispatchEvent(new MouseEvent(`click`))}catch{let t=new MouseEvent(`click`,{bubbles:!0,cancelable:!0,view:window,detail:0,screenX:80,screenY:20,clientX:80,clientY:20,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null});e.dispatchEvent(t)}}var es=typeof navigator==`object`?navigator:{userAgent:``},ts=/Macintosh/.test(es.userAgent)&&/AppleWebKit/.test(es.userAgent)&&!/Safari/.test(es.userAgent),ns=Wo?typeof HTMLAnchorElement<`u`&&`download`in HTMLAnchorElement.prototype&&!ts?rs:`msSaveOrOpenBlob`in es?is:as:()=>{};function rs(e,t=`download`,n){let r=document.createElement(`a`);r.download=t,r.rel=`noopener`,typeof e==`string`?(r.href=e,r.origin===location.origin?$o(r):Qo(r.href)?Zo(e,t,n):(r.target=`_blank`,$o(r))):(r.href=URL.createObjectURL(e),setTimeout(function(){URL.revokeObjectURL(r.href)},4e4),setTimeout(function(){$o(r)},0))}function is(e,t=`download`,n){if(typeof e==`string`){if(Qo(e))Zo(e,t,n);else{let t=document.createElement(`a`);t.href=e,t.target=`_blank`,setTimeout(function(){$o(t)})}}else navigator.msSaveOrOpenBlob(Xo(e,n),t)}function as(e,t,n,r){if(r||=open(``,`_blank`),r&&(r.document.title=r.document.body.innerText=`downloading...`),typeof e==`string`)return Zo(e,t,n);let i=e.type===`application/octet-stream`,a=/constructor/i.test(String(Yo.HTMLElement))||`safari`in Yo,o=/CriOS\/[\d]+/.test(navigator.userAgent);if((o||i&&a||ts)&&typeof FileReader<`u`){let t=new FileReader;t.onloadend=function(){let e=t.result;if(typeof e!=`string`)throw r=null,Error(`Wrong reader.result type`);e=o?e:e.replace(/^data:[^;]*;/,`data:attachment/file;`),r?r.location.href=e:location.assign(e),r=null},t.readAsDataURL(e)}else{let t=URL.createObjectURL(e);r?r.location.assign(t):location.href=t,r=null,setTimeout(function(){URL.revokeObjectURL(t)},4e4)}}var{assign:os}=Object;function ss(){let e=Te(!0),t=e.run(()=>R({})),n=[],r=[],i=Gt({install(e){Ko(i),i._a=e,e.provide(qo,i),e.config.globalProperties.$pinia=i,r.forEach(e=>n.push(e)),r=[]},use(e){return this._a?n.push(e):r.push(e),this},_p:n,_a:null,_e:e,_s:new Map,state:t});return i}var cs=()=>{};function ls(e,t,n,r=cs){e.add(t);let i=()=>{e.delete(t)&&r()};return!n&&Ee()&&De(i),i}function us(e,...t){e.forEach(e=>{e(...t)})}var ds=e=>e(),fs=Symbol(),ps=Symbol();function ms(e,t){e instanceof Map&&t instanceof Map?t.forEach((t,n)=>e.set(n,t)):e instanceof Set&&t instanceof Set&&t.forEach(e.add,e);for(let n in t){if(!Object.hasOwn(t,n))continue;let r=t[n],i=e[n];e[n]=Jo(i)&&Jo(r)&&Object.hasOwn(e,n)&&!L(r)&&!Vt(r)?ms(i,r):r}return e}var hs=Symbol();function gs(e){return!e||typeof e!=`object`||!Object.hasOwn(e,hs)}var{assign:_s}=Object;function vs(e){return!!(L(e)&&e.effect)}function ys(e,t,n,r){let{state:i,actions:a,getters:o}=t,s=n.state.value[e],c;function l(){return s||(n.state.value[e]=i?i():{}),_s($t(n.state.value[e]),a,Object.keys(o||{}).reduce((t,r)=>(t[r]=Gt(G(()=>{Ko(n);let t=n._s.get(e);return o[r].call(t,t)})),t),{}))}return c=bs(e,l,t,n,r,!0),c}function bs(e,t,n={},r,i,a){let o,s=_s({actions:{}},n),c={deep:!0},l,u,d=new Set,f=new Set,p,m=r.state.value[e];!a&&!m&&(r.state.value[e]={});let h;function g(t){let n;l=u=!1,typeof t==`function`?(t(r.state.value[e]),n={type:`patch function`,storeId:e,events:p}):(ms(r.state.value[e],t),n={type:`patch object`,payload:t,storeId:e,events:p});let i=h=Symbol();Sn().then(()=>{h===i&&(l=!0)}),u=!0,us(d,n,r.state.value[e])}let _=a?function(){let{state:e}=n,t=e?e():{};this.$patch(e=>{_s(e,t)})}:cs;function v(){o.stop(),d.clear(),f.clear(),r._s.delete(e)}let y=(t,n=``)=>{if(fs in t)return t[ps]=n,t;let i=function(){Ko(r);let n=Array.from(arguments),a=new Set,o=new Set;function s(e){a.add(e)}function c(e){o.add(e)}us(f,{args:n,name:i[ps],store:b,after:s,onError:c});let l;try{l=t.apply(this&&this.$id===e?this:b,n)}catch(e){throw us(o,e),e}return l instanceof Promise?l.then(e=>(us(a,e),e)).catch(e=>(us(o,e),Promise.reject(e))):(us(a,l),l)};return i[fs]=!0,i[ps]=n,i},b=Lt({_p:r,$id:e,$onAction:ls.bind(null,f),$patch:g,$reset:_,$subscribe(t,n={}){if(d.has(t))return cs;let i=ls(d,t,n.detached,()=>a()),a=o.run(()=>Hn(()=>r.state.value[e],r=>{(n.flush===`sync`?u:l)&&t({storeId:e,type:`direct`,events:p},r)},_s({},c,n)));return i},$dispose:v});r._s.set(e,b);let x=(r._a&&r._a.runWithContext||ds)(()=>r._e.run(()=>(o=Te()).run(()=>t({action:y}))));for(let t in x){let n=x[t];L(n)&&!vs(n)||Vt(n)?a||(m&&gs(n)&&(L(n)?n.value=m[t]:((n instanceof Set||n instanceof Map)&&n.clear(),ms(n,m[t]))),r.state.value[e][t]=n):typeof n==`function`&&(x[t]=y(n,t),s.actions[t]=n)}return _s(b,x),_s(I(b),x),Object.defineProperty(b,"$state",{get:()=>r.state.value[e],set:e=>{g(t=>{_s(t,e)})}}),r._p.forEach(e=>{let t=o.run(()=>e({store:b,app:r._a,pinia:r,options:s}));_s(b,t)}),m&&a&&n.hydrate&&n.hydrate(b.$state,m),l=!0,u=!0,b}function xs(e,t,n){let r,i=typeof t==`function`;r=i?n:t;function a(n,a){let o=zn();return n||=o?Rn(qo,null):null,n&&Ko(n),n=Go,n._s.has(e)||(i?bs(e,t,r,n):ys(e,r,n)),n._s.get(e)}return a.$id=e,a}var Ss={class:`app`},Cs={class:`side`},ws={class:`nav`},Ts={class:`nav-icon`},Es={class:`nav-label`},Ds={class:`main-col`},Os=Qn({__name:`App`,setup(e){let t=[{to:`/chat`,icon:`💬`,label:`对话`},{to:`/collaboration`,icon:`🔄`,label:`协作过程`},{to:`/agent`,icon:`🤖`,label:`智能体`},{to:`/review`,icon:`🔍`,label:`人工检验`},{to:`/metrics`,icon:`📊`,label:`指标`},{to:`/settings`,icon:`⚙️`,label:`设置`}];return(e,n)=>{let r=Cr(`router-link`),i=Cr(`router-view`);return V(),H(`div`,Ss,[U(`aside`,Cs,[n[0]||=U(`div`,{class:`brand`},[U(`div`,{class:`brand-logo`},`🤖`),U(`div`,{class:`brand-text`},[U(`b`,null,`端云协同`),U(`span`,null,`LLM 协作系统`)])],-1),U(`nav`,ws,[(V(),H(B,null,Dr(t,e=>ta(r,{key:e.to,to:e.to,class:`nav-item`},{default:Pn(()=>[U(`span`,Ts,N(e.icon),1),U(`span`,Es,N(e.label),1)]),_:2},1032,[`to`])),64))]),n[1]||=U(`div`,{class:`side-foot`},[U(`div`,{class:`foot-dot`}),U(`span`,null,`本地网关 · :8000`)],-1)]),U(`div`,Ds,[ta(i,{class:`content`})])])}}}),ks=typeof document<`u`;function As(e){return typeof e==`object`||`displayName`in e||`props`in e||`__vccOpts`in e}function js(e){return e.__esModule||e[Symbol.toStringTag]===`Module`||e.default&&As(e.default)}var K=Object.assign;function Ms(e,t){let n={};for(let r in t){let i=t[r];n[r]=Ps(i)?i.map(e):e(i)}return n}var Ns=()=>{},Ps=Array.isArray;function Fs(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}var Is=/#/g,Ls=/&/g,Rs=/\//g,zs=/=/g,Bs=/\?/g,Vs=/\+/g,Hs=/%5B/g,Us=/%5D/g,Ws=/%5E/g,Gs=/%60/g,Ks=/%7B/g,qs=/%7C/g,Js=/%7D/g,Ys=/%20/g;function Xs(e){return e==null?``:encodeURI(``+e).replace(qs,`|`).replace(Hs,`[`).replace(Us,`]`)}function Zs(e){return Xs(e).replace(Ks,`{`).replace(Js,`}`).replace(Ws,`^`)}function Qs(e){return Xs(e).replace(Vs,`%2B`).replace(Ys,`+`).replace(Is,`%23`).replace(Ls,`%26`).replace(Gs,"`").replace(Ks,`{`).replace(Js,`}`).replace(Ws,`^`)}function $s(e){return Qs(e).replace(zs,`%3D`)}function ec(e){return Xs(e).replace(Is,`%23`).replace(Bs,`%3F`)}function tc(e){return ec(e).replace(Rs,`%2F`)}function nc(e){if(e==null)return null;try{return decodeURIComponent(``+e)}catch{}return``+e}var rc=/\/$/,ic=e=>e.replace(rc,``);function ac(e,t,n=`/`){let r,i={},a=``,o=``,s=t.indexOf(`#`),c=t.indexOf(`?`);return c=s>=0&&c>s?-1:c,c>=0&&(r=t.slice(0,c),a=t.slice(c,s>0?s:t.length),i=e(a.slice(1))),s>=0&&(r||=t.slice(0,s),o=t.slice(s,t.length)),r=pc(r??t,n),{fullPath:r+a+o,path:r,query:i,hash:nc(o)}}function oc(e,t){let n=t.query?e(t.query):``;return t.path+(n&&`?`)+n+(t.hash||``)}function sc(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||`/`}function cc(e,t,n){let r=t.matched.length-1,i=n.matched.length-1;return r>-1&&r===i&&lc(t.matched[r],n.matched[i])&&uc(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function lc(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function uc(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var n in e)if(!dc(e[n],t[n]))return!1;return!0}function dc(e,t){return Ps(e)?fc(e,t):Ps(t)?fc(t,e):e?.valueOf()===t?.valueOf()}function fc(e,t){return Ps(t)?e.length===t.length&&e.every((e,n)=>e===t[n]):e.length===1&&e[0]===t}function pc(e,t){if(e.startsWith(`/`))return e;if(!e)return t;let n=t.split(`/`),r=e.split(`/`),i=r[r.length-1];(i===`..`||i===`.`)&&r.push(``);let a=n.length-1,o,s;for(o=0;o1&&a--;else break}return n.slice(0,a).join(`/`)+`/`+r.slice(o).join(`/`)}var mc={path:`/`,name:void 0,params:{},query:{},hash:``,fullPath:`/`,matched:[],meta:{},redirectedFrom:void 0},hc=function(e){return e.pop=`pop`,e.push=`push`,e}({}),gc=function(e){return e.back=`back`,e.forward=`forward`,e.unknown=``,e}({});function _c(e){if(!e){if(ks){let t=document.querySelector(`base`);e=t&&t.getAttribute(`href`)||`/`,e=e.replace(/^\w+:\/\/[^\/]+/,``)}else e=`/`}return e[0]!==`/`&&e[0]!==`#`&&(e=`/`+e),ic(e)}var vc=/^[^#]+#/;function yc(e,t){return e.replace(vc,`#`)+t}function bc(e,t){let n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}var xc=()=>({left:window.scrollX,top:window.scrollY});function Sc(e){let t;if(`el`in e){let n=e.el,r=typeof n==`string`&&n.startsWith(`#`),i=typeof n==`string`?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!i)return;t=bc(i,e)}else t=e;`scrollBehavior`in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left==null?window.scrollX:t.left,t.top==null?window.scrollY:t.top)}function Cc(e,t){return(history.state?history.state.position-t:-1)+e}var wc=new Map;function Tc(e,t){wc.set(e,t)}function Ec(e){let t=wc.get(e);return wc.delete(e),t}function Dc(e){return typeof e==`string`||e&&typeof e==`object`}function Oc(e){return typeof e==`string`||typeof e==`symbol`}var q=function(e){return e[e.MATCHER_NOT_FOUND=1]=`MATCHER_NOT_FOUND`,e[e.NAVIGATION_GUARD_REDIRECT=2]=`NAVIGATION_GUARD_REDIRECT`,e[e.NAVIGATION_ABORTED=4]=`NAVIGATION_ABORTED`,e[e.NAVIGATION_CANCELLED=8]=`NAVIGATION_CANCELLED`,e[e.NAVIGATION_DUPLICATED=16]=`NAVIGATION_DUPLICATED`,e}({}),kc=Symbol(``);q.MATCHER_NOT_FOUND,q.NAVIGATION_GUARD_REDIRECT,q.NAVIGATION_ABORTED,q.NAVIGATION_CANCELLED,q.NAVIGATION_DUPLICATED;function Ac(e,t){return K(Error(),{type:e,[kc]:!0},t)}function jc(e,t){return e instanceof Error&&kc in e&&(t==null||!!(e.type&t))}function Mc(e){let t={};if(e===``||e===`?`)return t;let n=(e[0]===`?`?e.slice(1):e).split(`&`);for(let e=0;ee&&Qs(e)):[r&&Qs(r)]).forEach(e=>{e!==void 0&&(t+=(t.length?`&`:``)+n,e!=null&&(t+=`=`+e))})}return t}function Pc(e){let t={};for(let n in e){let r=e[n];r!==void 0&&(t[n]=Ps(r)?r.map(e=>e==null?null:``+e):r==null?r:``+r)}return t}var Fc=Symbol(``),Ic=Symbol(``),Lc=Symbol(``),Rc=Symbol(``),zc=Symbol(``);function Bc(){let e=[];function t(t){return e.push(t),()=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Vc(e,t,n,r,i,a=e=>e()){let o=r&&(r.enterCallbacks[i]=r.enterCallbacks[i]||[]);return()=>new Promise((s,c)=>{let l=e=>{e===!1?c(Ac(q.NAVIGATION_ABORTED,{from:n,to:t})):e instanceof Error?c(e):Dc(e)?c(Ac(q.NAVIGATION_GUARD_REDIRECT,{from:t,to:e})):(o&&r.enterCallbacks[i]===o&&typeof e==`function`&&o.push(e),s())},u=a(()=>e.call(r&&r.instances[i],t,n,l)),d=Promise.resolve(u);e.length<3&&(d=d.then(l)),d.catch(e=>c(e))})}function Hc(e,t,n,r,i=e=>e()){let a=[];for(let o of e)for(let e in o.components){let s=o.components[e];if(!(t!==`beforeRouteEnter`&&!o.instances[e])){if(As(s)){let c=(s.__vccOpts||s)[t];c&&a.push(Vc(c,n,r,o,e,i))}else{let c=s();a.push(()=>c.then(a=>{if(!a)throw Error(`Couldn't resolve component "${e}" at "${o.path}"`);let s=js(a)?a.default:a;o.mods[e]=a,o.components[e]=s;let c=(s.__vccOpts||s)[t];return c&&Vc(c,n,r,o,e,i)()}))}}}return a}function Uc(e,t){let n=[],r=[],i=[],a=Math.max(t.matched.length,e.matched.length);for(let o=0;olc(e,a))?r.push(a):n.push(a));let s=e.matched[o];s&&(t.matched.find(e=>lc(e,s))||i.push(s))}return[n,r,i]}var Wc=()=>location.protocol+`//`+location.host;function Gc(e,t){let{pathname:n,search:r,hash:i}=t,a=e.indexOf(`#`);if(a>-1){let t=i.includes(e.slice(a))?e.slice(a).length:1,n=i.slice(t);return n[0]!==`/`&&(n=`/`+n),sc(n,``)}return sc(n,e)+r+i}function Kc(e,t,n,r){let i=[],a=[],o=null,s=({state:a})=>{let s=Gc(e,location),c=n.value,l=t.value,u=0;if(a){if(n.value=s,t.value=a,o&&o===c){o=null;return}u=l?a.position-l.position:0}else r(s);i.forEach(e=>{e(n.value,c,{delta:u,type:hc.pop,direction:u?u>0?gc.forward:gc.back:gc.unknown})})};function c(){o=n.value}function l(e){i.push(e);let t=()=>{let t=i.indexOf(e);t>-1&&i.splice(t,1)};return a.push(t),t}function u(){if(document.visibilityState===`hidden`){let{history:e}=window;if(!e.state)return;e.replaceState(K({},e.state,{scroll:xc()}),``)}}function d(){for(let e of a)e();a=[],window.removeEventListener(`popstate`,s),window.removeEventListener(`pagehide`,u),document.removeEventListener(`visibilitychange`,u)}return window.addEventListener(`popstate`,s),window.addEventListener(`pagehide`,u),document.addEventListener(`visibilitychange`,u),{pauseListeners:c,listen:l,destroy:d}}function qc(e,t,n,r=!1,i=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:i?xc():null}}function Jc(e){let{history:t,location:n}=window,r={value:Gc(e,n)},i={value:t.state};i.value||a(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function a(r,a,o){let s=e.indexOf(`#`),c=s>-1?(n.host&&document.querySelector(`base`)?e:e.slice(s))+r:Wc()+e+r;try{t[o?`replaceState`:`pushState`](a,``,c),i.value=a}catch(e){console.error(e),n[o?`replace`:`assign`](c)}}function o(e,n){a(e,K({},t.state,qc(i.value.back,e,i.value.forward,!0),n,{position:i.value.position}),!0),r.value=e}function s(e,n){let o=K({},i.value,t.state,{forward:e,scroll:xc()});a(o.current,o,!0),a(e,K({},qc(r.value,e,null),{position:o.position+1},n),!1),r.value=e}return{location:r,state:i,push:s,replace:o}}function Yc(e){e=_c(e);let t=Jc(e),n=Kc(e,t.state,t.location,t.replace);function r(e,t=!0){t||n.pauseListeners(),history.go(e)}let i=K({location:``,base:e,go:r,createHref:yc.bind(null,e)},t,n);return Object.defineProperty(i,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(i,"state",{enumerable:!0,get:()=>t.state.value}),i}var Xc=function(e){return e[e.Static=0]=`Static`,e[e.Param=1]=`Param`,e[e.Group=2]=`Group`,e}({}),J=function(e){return e[e.Static=0]=`Static`,e[e.Param=1]=`Param`,e[e.ParamRegExp=2]=`ParamRegExp`,e[e.ParamRegExpEnd=3]=`ParamRegExpEnd`,e[e.EscapeNext=4]=`EscapeNext`,e}(J||{}),Zc={type:Xc.Static,value:``},Qc=/[a-zA-Z0-9_]/;function $c(e){if(!e)return[[]];if(e===`/`)return[[Zc]];if(!e.startsWith(`/`))throw Error(`Invalid path "${e}"`);function t(e){throw Error(`ERR (${n})/"${l}": ${e}`)}let n=J.Static,r=n,i=[],a;function o(){a&&i.push(a),a=[]}let s=0,c,l=``,u=``;function d(){l&&=(n===J.Static?a.push({type:Xc.Static,value:l}):n===J.Param||n===J.ParamRegExp||n===J.ParamRegExpEnd?(a.length>1&&(c===`*`||c===`+`)&&t(`A repeatable param (${l}) must be alone in its segment. eg: '/:ids+.`),a.push({type:Xc.Param,value:l,regexp:u,repeatable:c===`*`||c===`+`,optional:c===`*`||c===`?`})):t(`Invalid state to consume buffer`),``)}function f(){l+=c}for(;st.length?t.length===1&&t[0]===nl.Static+nl.Segment?1:-1:0}function ol(e,t){let n=0,r=e.score,i=t.score;for(;n0&&t[t.length-1]<0}var cl={strict:!1,end:!0,sensitive:!1};function ll(e,t,n){let r=K(il($c(e.path),n),{record:e,parent:t,children:[],alias:[]});return t&&!r.record.aliasOf==!t.record.aliasOf&&t.children.push(r),r}function ul(e,t){let n=[],r=new Map;t=Fs(cl,t);function i(e){return r.get(e)}function a(e,n,r){let i=!r,s=fl(e);s.aliasOf=r&&r.record;let l=Fs(t,e),u=[s];if(`alias`in e){let t=typeof e.alias==`string`?[e.alias]:e.alias;for(let e of t)u.push(fl(K({},s,{components:r?r.record.components:s.components,path:e,aliasOf:r?r.record:s})))}let d,f;for(let t of u){let{path:u}=t;if(n&&u[0]!==`/`){let e=n.record.path,r=e[e.length-1]===`/`?``:`/`;t.path=n.record.path+(u&&r+u)}if(d=ll(t,n,l),r?r.alias.push(d):(f||=d,f!==d&&f.alias.push(d),i&&e.name&&!ml(d)&&o(e.name)),vl(d)&&c(d),s.children){let e=s.children;for(let t=0;t{o(f)}:Ns}function o(e){if(Oc(e)){let t=r.get(e);t&&(r.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(o),t.alias.forEach(o))}else{let t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&r.delete(e.record.name),e.children.forEach(o),e.alias.forEach(o))}}function s(){return n}function c(e){let t=gl(e,n);n.splice(t,0,e),e.record.name&&!ml(e)&&r.set(e.record.name,e)}function l(e,t){let i,a={},o,s;if(`name`in e&&e.name){if(i=r.get(e.name),!i)throw Ac(q.MATCHER_NOT_FOUND,{location:e});s=i.record.name,a=K(dl(t.params,i.keys.filter(e=>!e.optional).concat(i.parent?i.parent.keys.filter(e=>e.optional):[]).map(e=>e.name)),e.params&&dl(e.params,i.keys.map(e=>e.name))),o=i.stringify(a)}else if(e.path!=null)o=e.path,i=n.find(e=>e.re.test(o)),i&&(a=i.parse(o),s=i.record.name);else{if(i=t.name?r.get(t.name):n.find(e=>e.re.test(t.path)),!i)throw Ac(q.MATCHER_NOT_FOUND,{location:e,currentLocation:t});s=i.record.name,a=K({},t.params,e.params),o=i.stringify(a)}let c=[],l=i;for(;l;)c.unshift(l.record),l=l.parent;return{name:s,path:o,params:a,matched:c,meta:hl(c)}}e.forEach(e=>a(e));function u(){n.length=0,r.clear()}return{addRoute:a,resolve:l,removeRoute:o,clearRoutes:u,getRoutes:s,getRecordMatcher:i}}function dl(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}function fl(e){let t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:pl(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:`components`in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function pl(e){let t={},n=e.props||!1;if(`component`in e)t.default=n;else for(let r in e.components)t[r]=typeof n==`object`?n[r]:n;return t}function ml(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function hl(e){return e.reduce((e,t)=>K(e,t.meta),{})}function gl(e,t){let n=0,r=t.length;for(;n!==r;){let i=n+r>>1;ol(e,t[i])<0?r=i:n=i+1}let i=_l(e);return i&&(r=t.lastIndexOf(i,r-1)),r}function _l(e){let t=e;for(;t=t.parent;)if(vl(t)&&ol(e,t)===0)return t}function vl({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function yl(e){let t=Rn(Lc),n=Rn(Rc),r=G(()=>{let n=z(e.to);return t.resolve(n)}),i=G(()=>{let{matched:e}=r.value,{length:t}=e,i=e[t-1],a=n.matched;if(!i||!a.length)return-1;let o=a.findIndex(lc.bind(null,i));if(o>-1)return o;let s=wl(e[t-2]);return t>1&&wl(i)===s&&a[a.length-1].path!==s?a.findIndex(lc.bind(null,e[t-2])):o}),a=G(()=>i.value>-1&&Cl(n.params,r.value.params)),o=G(()=>i.value>-1&&i.value===n.matched.length-1&&uc(n.params,r.value.params));function s(n={}){if(Sl(n)){let n=t[z(e.replace)?`replace`:`push`](z(e.to)).catch(Ns);return e.viewTransition&&typeof document<`u`&&`startViewTransition`in document&&document.startViewTransition(()=>n),n}return Promise.resolve()}return{route:r,href:G(()=>r.value.href),isActive:a,isExactActive:o,navigate:s}}function bl(e){return e.length===1?e[0]:e}var xl=Qn({name:`RouterLink`,compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:`page`},viewTransition:Boolean},useLink:yl,setup(e,{slots:t}){let n=Lt(yl(e)),{options:r}=Rn(Lc),i=G(()=>({[Tl(e.activeClass,r.linkActiveClass,`router-link-active`)]:n.isActive,[Tl(e.exactActiveClass,r.linkExactActiveClass,`router-link-exact-active`)]:n.isExactActive}));return()=>{let r=t.default&&bl(t.default(n));return e.custom?r:ja(`a`,{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:i.value},r)}}});function Sl(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&(e.button===void 0||e.button===0)){if(e.currentTarget&&e.currentTarget.getAttribute){let t=e.currentTarget.getAttribute(`target`);if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function Cl(e,t){for(let n in t){let r=t[n],i=e[n];if(typeof r==`string`){if(r!==i)return!1}else if(!Ps(i)||i.length!==r.length||r.some((e,t)=>e.valueOf()!==i[t].valueOf()))return!1}return!0}function wl(e){return e?e.aliasOf?e.aliasOf.path:e.path:``}var Tl=(e,t,n)=>e??t??n,El=Qn({name:`RouterView`,inheritAttrs:!1,props:{name:{type:String,default:`default`},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){let r=Rn(zc),i=G(()=>e.route||r.value),a=Rn(Ic,0),o=G(()=>{let e=z(a),{matched:t}=i.value,n;for(;(n=t[e])&&!n.components;)e++;return e}),s=G(()=>i.value.matched[o.value]);Ln(Ic,G(()=>o.value+1)),Ln(Fc,s),Ln(zc,i);let c=R();return Hn(()=>[c.value,s.value,e.name],([e,t,n],[r,i,a])=>{t&&(t.instances[n]=e,i&&i!==t&&e&&e===r&&(t.leaveGuards.size||(t.leaveGuards=i.leaveGuards),t.updateGuards.size||(t.updateGuards=i.updateGuards))),e&&t&&(!i||!lc(t,i)||!r)&&(t.enterCallbacks[n]||[]).forEach(t=>t(e))},{flush:`post`}),()=>{let r=i.value,a=e.name,o=s.value,l=o&&o.components[a];if(!l)return Dl(n.default,{Component:l,route:r});let u=o.props[a],d=ja(l,K({},u?u===!0?r.params:typeof u==`function`?u(r):u:null,t,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(o.instances[a]=null)},ref:c}));return Dl(n.default,{Component:d,route:r})||d}}});function Dl(e,t){if(!e)return null;let n=e(t);return n.length===1?n[0]:n}var Ol=El;function kl(e){let t=ul(e.routes,e),n=e.parseQuery||Mc,r=e.stringifyQuery||Nc,i=e.history,a=Bc(),o=Bc(),s=Bc(),c=Jt(mc),l=mc;ks&&e.scrollBehavior&&`scrollRestoration`in history&&(history.scrollRestoration=`manual`);let u=Ms.bind(null,e=>``+e),d=Ms.bind(null,tc),f=Ms.bind(null,nc);function p(e,n){let r,i;return Oc(e)?(r=t.getRecordMatcher(e),i=n):i=e,t.addRoute(i,r)}function m(e){let n=t.getRecordMatcher(e);n&&t.removeRoute(n)}function h(){return t.getRoutes().map(e=>e.record)}function g(e){return!!t.getRecordMatcher(e)}function _(e,a){if(a=K({},a||c.value),typeof e==`string`){let r=ac(n,e,a.path),o=t.resolve({path:r.path},a),s=i.createHref(r.fullPath);return K(r,o,{params:f(o.params),hash:nc(r.hash),redirectedFrom:void 0,href:s})}let o;if(e.path!=null)o=K({},e,{path:ac(n,e.path,a.path).path});else{let t=K({},e.params);for(let e in t)t[e]??delete t[e];o=K({},e,{params:d(t)}),a.params=d(a.params)}let s=t.resolve(o,a),l=e.hash||``;s.params=u(f(s.params));let p=oc(r,K({},e,{hash:Zs(l),path:s.path})),m=i.createHref(p);return K({fullPath:p,hash:l,query:r===Nc?Pc(e.query):e.query||{}},s,{redirectedFrom:void 0,href:m})}function v(e){return typeof e==`string`?ac(n,e,c.value.path):K({},e)}function y(e,t){if(l!==e)return Ac(q.NAVIGATION_CANCELLED,{from:t,to:e})}function b(e){return C(e)}function x(e){return b(K(v(e),{replace:!0}))}function S(e,t){let n=e.matched[e.matched.length-1];if(n&&n.redirect){let{redirect:r}=n,i=typeof r==`function`?r(e,t):r;return typeof i==`string`&&(i=i.includes(`?`)||i.includes(`#`)?i=v(i):{path:i},i.params={}),K({query:e.query,hash:e.hash,params:i.path==null?e.params:{}},i)}}function C(e,t){let n=l=_(e),i=c.value,a=e.state,o=e.force,s=e.replace===!0,u=S(n,i);if(u)return C(K(v(u),{state:typeof u==`object`?K({},a,u.state):a,force:o,replace:s}),t||n);let d=n;d.redirectedFrom=t;let f;return!o&&cc(r,i,n)&&(f=Ac(q.NAVIGATION_DUPLICATED,{to:d,from:i}),se(i,i,!0,!1)),(f?Promise.resolve(f):te(d,i)).catch(e=>jc(e)?jc(e,q.NAVIGATION_GUARD_REDIRECT)?e:oe(e):ae(e,d,i)).then(e=>{if(e){if(jc(e,q.NAVIGATION_GUARD_REDIRECT))return C(K({replace:s},v(e.to),{state:typeof e.to==`object`?K({},a,e.to.state):a,force:o}),t||d)}else e=re(d,i,!0,s,a);return ne(d,i,e),e})}function w(e,t){let n=y(e,t);return n?Promise.reject(n):Promise.resolve()}function ee(e){let t=M.values().next().value;return t&&typeof t.runWithContext==`function`?t.runWithContext(e):e()}function te(e,t){let n,[r,i,s]=Uc(e,t);n=Hc(r.reverse(),`beforeRouteLeave`,e,t);for(let i of r)i.leaveGuards.forEach(r=>{n.push(Vc(r,e,t))});let c=w.bind(null,e,t);return n.push(c),le(n).then(()=>{n=[];for(let r of a.list())n.push(Vc(r,e,t));return n.push(c),le(n)}).then(()=>{n=Hc(i,`beforeRouteUpdate`,e,t);for(let r of i)r.updateGuards.forEach(r=>{n.push(Vc(r,e,t))});return n.push(c),le(n)}).then(()=>{n=[];for(let r of s)if(r.beforeEnter){if(Ps(r.beforeEnter))for(let i of r.beforeEnter)n.push(Vc(i,e,t));else n.push(Vc(r.beforeEnter,e,t))}return n.push(c),le(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Hc(s,`beforeRouteEnter`,e,t,ee),n.push(c),le(n))).then(()=>{n=[];for(let r of o.list())n.push(Vc(r,e,t));return n.push(c),le(n)}).catch(e=>jc(e,q.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function ne(e,t,n){s.list().forEach(r=>ee(()=>r(e,t,n)))}function re(e,t,n,r,a){let o=y(e,t);if(o)return o;let s=t===mc,l=ks?history.state:{};n&&(r||s?i.replace(e.fullPath,K({scroll:s&&l&&l.scroll},a)):i.push(e.fullPath,a)),c.value=e,se(e,t,n,s),oe()}let ie;function T(){ie||=i.listen((e,t,n)=>{if(!ce.listening)return;let r=_(e),a=S(r,ce.currentRoute.value);if(a){C(K(a,{replace:!0,force:!0}),r).catch(Ns);return}l=r;let o=c.value;ks&&Tc(Cc(o.fullPath,n.delta),xc()),te(r,o).catch(e=>jc(e,q.NAVIGATION_ABORTED|q.NAVIGATION_CANCELLED)?e:jc(e,q.NAVIGATION_GUARD_REDIRECT)?(C(K(v(e.to),{force:!0}),r).then(e=>{jc(e,q.NAVIGATION_ABORTED|q.NAVIGATION_DUPLICATED)&&!n.delta&&n.type===hc.pop&&i.go(-1,!1)}).catch(Ns),Promise.reject()):(n.delta&&i.go(-n.delta,!1),ae(e,r,o))).then(e=>{e||=re(r,o,!1),e&&(n.delta&&!jc(e,q.NAVIGATION_CANCELLED)?i.go(-n.delta,!1):n.type===hc.pop&&jc(e,q.NAVIGATION_ABORTED|q.NAVIGATION_DUPLICATED)&&i.go(-1,!1)),ne(r,o,e)}).catch(Ns)})}let E=Bc(),D=Bc(),O;function ae(e,t,n){oe(e);let r=D.list();return r.length?r.forEach(r=>r(e,t,n)):console.error(e),Promise.reject(e)}function k(){return O&&c.value!==mc?Promise.resolve():new Promise((e,t)=>{E.add([e,t])})}function oe(e){return O||(O=!e,T(),E.list().forEach(([t,n])=>e?n(e):t()),E.reset()),e}function se(t,n,r,i){let{scrollBehavior:a}=e;if(!ks||!a)return Promise.resolve();let o=!r&&Ec(Cc(t.fullPath,0))||(i||!r)&&history.state&&history.state.scroll||null;return Sn().then(()=>a(t,n,o)).then(e=>e&&Sc(e)).catch(e=>ae(e,t,n))}let A=e=>i.go(e),j,M=new Set,ce={currentRoute:c,listening:!0,addRoute:p,removeRoute:m,clearRoutes:t.clearRoutes,hasRoute:g,getRoutes:h,resolve:_,options:e,push:b,replace:x,go:A,back:()=>A(-1),forward:()=>A(1),beforeEach:a.add,beforeResolve:o.add,afterEach:s.add,onError:D.add,isReady:k,install(e){e.component(`RouterLink`,xl),e.component(`RouterView`,Ol),e.config.globalProperties.$router=ce,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>z(c)}),ks&&!j&&c.value===mc&&(j=!0,b(i.location).catch(e=>{}));let t={};for(let e in mc)Object.defineProperty(t,e,{get:()=>c.value[e],enumerable:!0});e.provide(Lc,ce),e.provide(Rc,Rt(t)),e.provide(zc,c);let n=e.unmount;M.add(e),e.unmount=function(){M.delete(e),M.size<1&&(l=mc,ie&&ie(),ie=null,c.value=mc,j=!1,O=!1),n()}}};function le(e){return e.reduce((e,t)=>e.then(()=>ee(t)),Promise.resolve())}return ce}function Al(e,t){return function(){return e.apply(t,arguments)}}var{toString:jl}=Object.prototype,{getPrototypeOf:Ml}=Object,{iterator:Nl,toStringTag:Pl}=Symbol,Fl=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),Il=e=>typeof e==`string`&&(e===`__proto__`||e===`constructor`||e===`prototype`),Ll=(e,t,n)=>e===Object.prototype||!n&&t===null,Rl=e=>{if(!Object.isExtensible(e))return!1;let t=Object.getOwnPropertyNames(e);return Object.getOwnPropertySymbols&&t.push(...Object.getOwnPropertySymbols(e)),t.every(t=>{if(Il(t))return!1;let n=Object.getOwnPropertyDescriptor(e,t);return!!n&&n.configurable&&n.writable===!0})},zl=(e,t)=>{let n=e,r=[];for(;n!=null;){if(r.indexOf(n)!==-1)return!1;r.push(n);let i=Ml(n);if(Ll(n,i,n===e))return!1;if(Fl(n,t))return!0;n=i}return!1},Bl=(e,t)=>e!=null&&zl(e,t)?e[t]:void 0,Vl=e=>{if(e==null||typeof e!=`object`&&typeof e!=`function`)return e;let t=Ml(e);if(t===null&&Rl(e))return e;let n=Object.create(null),r=Object.create(null),i=[],a=e;for(;a!=null&&i.indexOf(a)===-1;){i.push(a);let o=a===e?t:Ml(a);if(Ll(a,o,a===e))break;let s=Object.getOwnPropertyNames(a);Object.getOwnPropertySymbols&&s.push(...Object.getOwnPropertySymbols(a));for(let t of s)Il(t)||Fl(r,t)||(n[t]=e[t],r[t]=!0);a=o}return n},Hl=(e=>t=>{let n=jl.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),Ul=e=>(e=e.toLowerCase(),t=>Hl(t)===e),Wl=e=>t=>typeof t===e,{isArray:Gl}=Array,Kl=Wl(`undefined`);function ql(e){return e!==null&&!Kl(e)&&e.constructor!==null&&!Kl(e.constructor)&&Zl(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}var Jl=Ul(`ArrayBuffer`);function Yl(e){let t;return t=typeof ArrayBuffer<`u`&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&Jl(e.buffer),t}var Xl=Wl(`string`),Zl=Wl(`function`),Ql=Wl(`number`),$l=e=>typeof e==`object`&&!!e,eu=e=>e===!0||e===!1,tu=e=>{if(!$l(e))return!1;let t=Ml(e);return(t===null||t===Object.prototype||Ml(t)===null)&&!zl(e,Pl)&&!zl(e,Nl)},nu=e=>{if(!$l(e)||ql(e))return!1;try{return Object.keys(e).length===0&&Object.getPrototypeOf(e)===Object.prototype}catch{return!1}},ru=Ul(`Date`),iu=Ul(`File`),au=e=>!!(e&&e.uri!==void 0),ou=e=>e&&e.getParts!==void 0,su=Ul(`Blob`),cu=Ul(`FileList`),lu=Ul(`Set`),uu=e=>$l(e)&&Zl(e.pipe);function du(){return typeof globalThis<`u`?globalThis:typeof self<`u`?self:typeof window<`u`?window:typeof global<`u`?global:{}}var fu=du(),pu=fu.FormData===void 0?void 0:fu.FormData,mu=e=>{if(!e)return!1;if(pu&&e instanceof pu)return!0;let t=Ml(e);if(!t||t===Object.prototype||!Zl(e.append))return!1;let n=Hl(e);return n===`formdata`||n===`object`&&Zl(e.toString)&&e.toString()===`[object FormData]`},hu=Ul(`URLSearchParams`),[gu,_u,vu,yu]=[`ReadableStream`,`Request`,`Response`,`Headers`].map(Ul),bu=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,``);function xu(e,t,{allOwnKeys:n=!1}={}){if(e==null)return;let r,i;if(typeof e!=`object`&&(e=[e]),Gl(e))for(r=0,i=e.length;r0;)if(i=n[r],t===i.toLowerCase())return i;return null}var Cu=typeof globalThis<`u`?globalThis:typeof self<`u`?self:typeof window<`u`?window:global,wu=e=>!Kl(e)&&e!==Cu;function Tu(...e){let{caseless:t,skipUndefined:n}=wu(this)&&this||{},r={},i=(e,i)=>{if(i===`__proto__`||i===`constructor`||i===`prototype`)return;let a=t&&typeof i==`string`&&Su(r,i)||i,o=Fl(r,a)?r[a]:void 0;tu(o)&&tu(e)?r[a]=Tu(o,e):tu(e)?r[a]=Tu({},e):Gl(e)?r[a]=e.slice():(!n||!Kl(e))&&(r[a]=e)};for(let t=0,n=e.length;t(xu(t,(t,r)=>{n&&Zl(t)?Object.defineProperty(e,r,{__proto__:null,value:Al(t,n),writable:!0,enumerable:!0,configurable:!0}):Object.defineProperty(e,r,{__proto__:null,value:t,writable:!0,enumerable:!0,configurable:!0})},{allOwnKeys:r}),e),Du=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),Ou=(e,t,n,r)=>{e.prototype=Object.create(t.prototype,r),Object.defineProperty(e.prototype,"constructor",{__proto__:null,value:e,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(e,"super",{__proto__:null,value:t.prototype}),n&&Object.assign(e.prototype,n)},ku=(e,t,n,r)=>{let i,a,o,s={};if(t||={},e==null)return t;do{for(i=Object.getOwnPropertyNames(e),a=i.length;a-->0;)o=i[a],(!r||r(o,e,t))&&!s[o]&&(t[o]=e[o],s[o]=!0);e=n!==!1&&Ml(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},Au=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;let r=e.indexOf(t,n);return r!==-1&&r===n},ju=e=>{if(!e)return null;if(Gl(e))return e;let t=e.length;if(!Ql(t))return null;let n=Array(t);for(;t-->0;)n[t]=e[t];return n},Mu=(e=>t=>e&&t instanceof e)(typeof Uint8Array<`u`&&Ml(Uint8Array)),Nu=(e,t)=>{let n=(e&&e[Nl]).call(e),r;for(;(r=n.next())&&!r.done;){let n=r.value;t.call(e,n[0],n[1])}},Pu=(e,t)=>{let n,r=[];for(;(n=e.exec(t))!==null;)r.push(n);return r},Fu=Ul(`HTMLFormElement`),Iu=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(e,t,n){return t.toUpperCase()+n}),{propertyIsEnumerable:Lu}=Object.prototype,Ru=Ul(`RegExp`),zu=(e,t)=>{let n=Object.getOwnPropertyDescriptors(e),r={};xu(n,(n,i)=>{let a;(a=t(n,i,e))!==!1&&(r[i]=a||n)}),Object.defineProperties(e,r)},Bu=e=>{zu(e,(t,n)=>{if(Zl(e)&&[`arguments`,`caller`,`callee`].includes(n))return!1;let r=e[n];if(Zl(r)){if(t.enumerable=!1,`writable`in t){t.writable=!1;return}t.set||=()=>{throw Error(`Can not rewrite read-only method '`+n+`'`)}}})},Vu=(e,t)=>{let n={},r=e=>{e.forEach(e=>{n[e]=!0})};return Gl(e)?r(e):r(String(e).split(t)),n},Hu=()=>{},Uu=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t;function Wu(e){return!!(e&&Zl(e.append)&&e[Pl]===`FormData`&&e[Nl])}var Gu=e=>{let t=new WeakSet,n=e=>{if($l(e)){if(t.has(e))return;if(ql(e))return e;if(!(`toJSON`in e)){t.add(e);let r;if(lu(e)){r=[];for(let t of e){let e=n(t);!Kl(e)&&r.push(e)}}else r=Gl(e)?[]:{},xu(e,(e,t)=>{let i=n(e);!Kl(i)&&(r[t]=i)});return t.delete(e),r}}return e};return n(e)},Ku=Ul(`AsyncFunction`),qu=e=>e&&($l(e)||Zl(e))&&Zl(e.then)&&Zl(e.catch),Ju=((e,t)=>e?setImmediate:t?((e,t)=>(Cu.addEventListener(`message`,({source:n,data:r})=>{n===Cu&&r===e&&t.length&&t.shift()()},!1),n=>{t.push(n),Cu.postMessage(e,`*`)}))(`axios@${Math.random()}`,[]):e=>setTimeout(e))(typeof setImmediate==`function`,Zl(Cu.postMessage)),Yu=typeof queueMicrotask<`u`?queueMicrotask.bind(Cu):typeof process<`u`&&process.nextTick||Ju,Xu=e=>e!=null&&Zl(e[Nl]),Y={isArray:Gl,isArrayBuffer:Jl,isBuffer:ql,isFormData:mu,isArrayBufferView:Yl,isString:Xl,isNumber:Ql,isBoolean:eu,isObject:$l,isPlainObject:tu,isEmptyObject:nu,isReadableStream:gu,isRequest:_u,isResponse:vu,isHeaders:yu,isUndefined:Kl,isDate:ru,isFile:iu,isReactNativeBlob:au,isReactNative:ou,isBlob:su,isRegExp:Ru,isFunction:Zl,isStream:uu,isURLSearchParams:hu,isTypedArray:Mu,isFileList:cu,forEach:xu,merge:Tu,extend:Eu,trim:bu,stripBOM:Du,inherits:Ou,toFlatObject:ku,kindOf:Hl,kindOfTest:Ul,endsWith:Au,toArray:ju,forEachEntry:Nu,matchAll:Pu,isHTMLForm:Fu,hasOwnProperty:Fl,hasOwnProp:Fl,hasOwnInPrototypeChain:zl,getSafeProp:Bl,toSafeFlatObject:Vl,reduceDescriptors:zu,freezeMethods:Bu,toObjectSet:Vu,toCamelCase:Iu,noop:Hu,toFiniteNumber:Uu,findKey:Su,global:Cu,isContextDefined:wu,isSpecCompliantForm:Wu,toJSONObject:Gu,isAsyncFn:Ku,isThenable:qu,setImmediate:Ju,asap:Yu,isIterable:Xu,isSafeIterable:e=>e!=null&&zl(e,Nl)&&Xu(e)},Zu=Y.toObjectSet([`age`,`authorization`,`content-length`,`content-type`,`etag`,`expires`,`from`,`host`,`if-modified-since`,`if-unmodified-since`,`last-modified`,`location`,`max-forwards`,`proxy-authorization`,`referer`,`retry-after`,`user-agent`]),Qu=e=>{let t={},n,r,i;return e&&e.split(` `).forEach(function(e){i=e.indexOf(`:`),n=e.substring(0,i).trim().toLowerCase(),r=e.substring(i+1).trim();let a=Y.hasOwnProp(t,n);!n||a&&Y.hasOwnProp(Zu,n)||(n===`set-cookie`?a?t[n].push(r):t[n]=[r]:t[n]=a?t[n]+`, `+r:r)}),t};function $u(e){let t=0,n=e.length;for(;tt;){let t=e.charCodeAt(n-1);if(t!==9&&t!==32)break;--n}return t===0&&n===e.length?e:e.slice(t,n)}var ed=RegExp(`[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+`,`g`),td=RegExp(`[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+`,`g`);function nd(e,t){return Y.isArray(e)?e.map(e=>nd(e,t)):$u(String(e).replace(t,``))}var rd=e=>nd(e,ed),id=e=>nd(e,td);function ad(e){let t=Object.create(null);return Y.forEach(e.toJSON(),(e,n)=>{t[n]=id(e)}),t}var od=Symbol(`internals`);function sd(e){return e&&String(e).trim().toLowerCase()}function cd(e){return e===!1||e==null?e:Y.isArray(e)?e.map(cd):rd(String(e))}function ld(e){let t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g,r;for(;r=n.exec(e);)t[r[1]]=r[2];return t}var ud=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;function dd(e){let t=0,n=e.length;for(;tt;){let t=e.charCodeAt(n-1);if(t!==9&&t!==32)break;--n}return t===0&&n===e.length?e:e.slice(t,n)}function fd(e){let t=e.length-1;if(t<1||e.charCodeAt(0)!==34||e.charCodeAt(t)!==34)return e;let n=``;for(let r=1;r=t))return e;n+=e[r]}return n}function pd(e){let t=Object.create(null),n=String(e),r=0,i=!1,a=!1;function o(e){let i=dd(n.slice(r,e)),a=i.indexOf(`=`);if(a<1)return;let o=dd(i.slice(0,a));if(!ud.test(o))return;let s=o.toLowerCase();if(s===`__proto__`||s===`constructor`||s===`prototype`)return;let c=dd(i.slice(a+1));t[s]=fd(c)}for(let e=0;e/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function hd(e,t,n,r,i){if(Y.isFunction(r))return r.call(this,t,n);if(i&&(t=n),Y.isString(t)){if(Y.isString(r))return t.indexOf(r)!==-1;if(Y.isRegExp(r))return r.test(t)}}function gd(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(e,t,n)=>t.toUpperCase()+n)}function _d(e,t){let n=Y.toCamelCase(` `+t);[`get`,`set`,`has`].forEach(r=>{Object.defineProperty(e,r+n,{__proto__:null,value:function(e,n,i){return this[r].call(this,t,e,n,i)},configurable:!0})})}var vd=class{constructor(e){e&&this.set(e)}set(e,t,n){let r=this;function i(e,t,n){let i=sd(t);if(!i)return;let a=Y.findKey(r,i);(!a||r[a]===void 0||n===!0||n===void 0&&r[a]!==!1)&&(r[a||t]=cd(e))}let a=(e,t)=>Y.forEach(e,(e,n)=>i(e,n,t));if(Y.isPlainObject(e)||e instanceof this.constructor)a(e,t);else if(Y.isString(e)&&(e=e.trim())&&!md(e))a(Qu(e),t);else if(Y.isObject(e)&&Y.isSafeIterable(e)){let n=Object.create(null),r,i;for(let t of e){if(!Y.isArray(t))throw TypeError(`Object iterator must return a key-value pair`);i=t[0],Y.hasOwnProp(n,i)?(r=n[i],n[i]=Y.isArray(r)?[...r,t[1]]:[r,t[1]]):n[i]=t[1]}a(n,t)}else e!=null&&i(t,e,n);return this}get(e,t){if(e=sd(e),e){let n=Y.findKey(this,e);if(n){let e=this[n];if(!t)return e;if(t===!0)return ld(e);if(Y.isFunction(t))return t.call(this,e,n);if(Y.isRegExp(t))return t.exec(e);throw TypeError(`parser must be boolean|regexp|function`)}}}has(e,t){if(e=sd(e),e){let n=Y.findKey(this,e);return!!(n&&this[n]!==void 0&&(!t||hd(this,this[n],n,t)))}return!1}delete(e,t){let n=this,r=!1;function i(e){if(e=sd(e),e){let i=Y.findKey(n,e);i&&(!t||hd(n,n[i],i,t))&&(delete n[i],r=!0)}}return Y.isArray(e)?e.forEach(i):i(e),r}clear(e){let t=Object.keys(this),n=t.length,r=!1;for(;n--;){let i=t[n];(!e||hd(this,this[i],i,e,!0))&&(delete this[i],r=!0)}return r}normalize(e){let t=this,n={};return Y.forEach(this,(r,i)=>{let a=Y.findKey(n,i);if(a){t[a]=cd(r),delete t[i];return}let o=e?gd(i):String(i).trim();o!==i&&delete t[i],t[o]=cd(r),n[o]=!0}),this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){let t=Object.create(null);return Y.forEach(this,(n,r)=>{n!=null&&n!==!1&&(t[r]=e&&Y.isArray(n)?n.join(`, `):n)}),t}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([e,t])=>e+`: `+t).join(` @@ -8,4 +8,4 @@ var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],en `);r=e===-1?``:n.slice(e+1)}if(!e.stack)e.stack=r;else if(r){let t=r.indexOf(` `),n=t===-1?-1:r.indexOf(` `,t+1),i=n===-1?``:r.slice(n+1);String(e.stack).endsWith(i)||(e.stack+=` -`+r)}}catch{}throw e}}_request(e,t){typeof e==`string`?(t||={},t.url=e):t=e||{},t=Of(this.defaults,t);let{transitional:n,paramsSerializer:r,headers:i}=t;n!==void 0&&gp.assertOptions(n,{silentJSONParsing:_p.transitional(_p.boolean),forcedJSONParsing:_p.transitional(_p.boolean),clarifyTimeoutError:_p.transitional(_p.boolean),legacyInterceptorReqResOrdering:_p.transitional(_p.boolean),advertiseZstdAcceptEncoding:_p.transitional(_p.boolean),validateStatusUndefinedResolves:_p.transitional(_p.boolean)},!1),r!=null&&(Y.isFunction(r)?t.paramsSerializer={serialize:r}:gp.assertOptions(r,{encode:_p.function,serialize:_p.function},!0)),t.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls===void 0?t.allowAbsoluteUrls=!0:t.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls),gp.assertOptions(t,{baseUrl:_p.spelling(`baseURL`),withXsrfToken:_p.spelling(`withXSRFToken`)},!0),t.method=(Y.getSafeProp(t,`method`)||Y.getSafeProp(this.defaults,`method`)||`get`).toLowerCase();let a=i&&Y.merge(i.common,i[t.method]);i&&Y.forEach(ef.concat(`common`),e=>{delete i[e]}),t.headers=vd.concat(a,i);let o=[],s=!0;this.interceptors.request.forEach(function(e){if(typeof e.runWhen==`function`&&e.runWhen(t)===!1)return;s&&=e.synchronous;let n=t.transitional||Bd;n&&n.legacyInterceptorReqResOrdering?o.unshift(e.fulfilled,e.rejected):o.push(e.fulfilled,e.rejected)});let c=[];this.interceptors.response.forEach(function(e){c.push(e.fulfilled,e.rejected)});let l,u=0,d;if(!s){let e=[fp.bind(this),void 0];for(e.unshift(...o),e.push(...c),d=e.length,l=Promise.resolve(t);ufp.call(this,f)))}catch(e){l=Promise.reject(e)}break}}if(!l)try{l=fp.call(this,f)}catch(e){l=Promise.reject(e)}for(u=0,d=c.length;u{if(!n._listeners)return;let t=n._listeners.length;for(;t-->0;)n._listeners[t](e);n._listeners=null}),this.promise.then=e=>{let t,r=new Promise(e=>{n.subscribe(e),t=e}).then(e);return r.cancel=function(){n.unsubscribe(t)},r},e(function(e,r,i){n.reason||(n.reason=new sf(e,r,i),t(n.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;let t=this._listeners.indexOf(e);t!==-1&&this._listeners.splice(t,1)}toAbortSignal(){let e=new AbortController,t=t=>{e.abort(t)};return this.subscribe(t),e.signal.unsubscribe=()=>this.unsubscribe(t),e.signal}static source(){let t;return{token:new e(function(e){t=e}),cancel:t}}};function bp(e){return function(t){return e.apply(null,t)}}function xp(e){return Y.isObject(e)&&e.isAxiosError===!0}var Sp={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,ContentTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,UnprocessableContent:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerReturnsAnUnknownError:520,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Sp).forEach(([e,t])=>{Sp[t]===void 0&&(Sp[t]=e)});function Cp(e){let t=new vp(e),n=Al(vp.prototype.request,t);return Y.extend(n,vp.prototype,t,{allOwnKeys:!0}),Y.extend(n,t,null,{allOwnKeys:!0}),n.create=function(t){return Cp(Of(e,t))},n}var Q=Cp(rf);Q.Axios=vp,Q.CanceledError=sf,Q.CancelToken=yp,Q.isCancel=of,Q.VERSION=Yf,Q.toFormData=kd,Q.AxiosError=X,Q.Cancel=Q.CanceledError,Q.all=function(e){return Promise.all(e)},Q.spread=bp,Q.isAxiosError=xp,Q.mergeConfig=Of,Q.AxiosHeaders=vd,Q.formToJSON=e=>$d(Y.isHTMLForm(e)?new FormData(e):e),Q.getAdapter=up.getAdapter,Q.HttpStatusCode=Sp,Q.default=Q;var $=Q.create({timeout:1e4});async function wp(e,t){let{data:n}=await $.post(`/chat`,{query:e,domain_group:t});return n}async function Tp(e){let{data:t}=await $.get(`/runs/${e}/status`);return t}function Ep(e){let t=new EventSource(`/runs/${e}/stream`);return{subscribe(e){t.addEventListener(`message`,t=>{let n=JSON.parse(t.data);n.type===`workspace`?e.onWorkspace(n.workspace):n.type===`status`?(e.onStatus(n.value),(n.value===`done`||n.value===`failed`)&&e.onDone()):n.type===`error`&&e.onError(n.detail)}),t.addEventListener(`error`,()=>{})},close(){t.close()}}}async function Dp(e){let t=e?{status:e}:{},{data:n}=await $.get(`/review/queue`,{params:t});return n}async function Op(e,t,n){let{data:r}=await $.post(`/review/${e}`,null,{params:{verdict:t,correction:n}});return r}async function kp(){let{data:e}=await $.get(`/api/metrics`);return e}async function Ap(){let{data:e}=await $.get(`/config`);return e}async function jp(e){let{data:t}=await $.put(`/config`,e);return t}async function Mp(){let{data:e}=await $.post(`/config/reset`);return e}async function Np(e,t,n){let r={backend:e};t&&(r.base_url=t),n&&(r.api_key=n);let{data:i}=await $.get(`/config/models`,{params:r});return i}async function Pp(e,t,n){let r={backend:e};t&&(r.base_url=t),n&&(r.api_key=n);let{data:i}=await $.get(`/config/ping`,{params:r});return i}async function Fp(){let{data:e}=await $.get(`/llama/status`);return e}async function Ip(){let{data:e}=await $.get(`/llama/models`);return e.models}async function Lp(e,t=8901,n=99,r=4096){let{data:i}=await $.post(`/llama/start`,null,{params:{model:e,port:t,ngl:n,ctx:r}});return i}async function Rp(){let{data:e}=await $.post(`/llama/stop`);return e}async function zp(e,t){let n={url:e};t&&(n.dest=t);let{data:r}=await $.post(`/llama/download`,null,{params:n});return r}function Bp(e){let t=new EventSource(`/llama/download/stream?url=${encodeURIComponent(e)}`);return{subscribe(e){t.addEventListener(`message`,t=>{let n=JSON.parse(t.data);e.onProgress(n),n.done&&e.onDone(n)}),t.addEventListener(`error`,()=>{t.close()})},close(){t.close()}}}async function Vp(){let{data:e}=await $.get(`/pool`);return e}async function Hp(e){let{data:t}=await $.post(`/pool`,e);return t}async function Up(e){let{data:t}=await $.delete(`/pool/${e}`);return t}async function Wp(e){let{data:t}=await $.put(`/pool/roles`,e);return t}async function Gp(e){let{data:t}=await $.post(`/pool/${e}/test`);return t}async function Kp(e){let{data:t}=await $.get(`/pool/${e}/models`);return t}async function qp(e,t,n){let{data:r}=await $.post(`/agent/${e}/approve`,{approval_id:t,allowed:n});return r}async function Jp(e,t,n,r,i){let{data:a}=await $.post(`/agent`,{task:e,pool_id:t||void 0,workspace:n||void 0,executor_pool_id:r||void 0,session_id:i||void 0});return a}async function Yp(e){let{data:t}=await $.post(`/agent/${e}/cancel`);return t}async function Xp(e,t,n){let{data:r}=await $.post(`/agent/sessions`,{title:n||void 0,workspace:e||void 0,executor_pool_id:t||void 0});return r}async function Zp(){let{data:e}=await $.get(`/agent/sessions`);return e}async function Qp(e){let{data:t}=await $.get(`/agent/sessions/${e}`);return t}async function $p(e){let{data:t}=await $.delete(`/agent/sessions/${e}`);return t}async function em(e){let{data:t}=await $.get(`/agent/${e}/status`);return t}async function tm(e=``){let{data:t}=await $.get(`/agent/fs`,{params:e?{path:e}:{}});return t}async function nm(){let{data:e}=await $.get(`/agent/workspaces`);return e}async function rm(e,t=!1){let{data:n}=await $.post(`/agent/workspaces`,{path:e,create:t});return n}function im(e){let t=new EventSource(`/agent/${e}/stream`),n=!1;return{subscribe(e){t.addEventListener(`message`,r=>{if(n)return;let i=JSON.parse(r.data);e.onEvent(i),i.type===`final`&&(n=!0,t.close(),e.onDone())}),t.addEventListener(`error`,()=>{})},close(){t.close()}}}async function am(e,{timeout:t=6e4,interval:n=500}={}){let r=Date.now();for(;Date.now()-rsetTimeout(e,n))}throw Error(`poll timeout`)}var om=xs(`chat`,()=>{let e=R([]),t=R(null),n=()=>e.value.find(e=>e.requestId===t.value)??null;async function r(n){let r=await wp(n),i={requestId:r.request_id,query:n,init:r,status:null,workspace:null,error:null};return e.value.unshift(i),t.value=r.request_id,i}async function i(t){let n=await Tp(t),r=e.value.find(e=>e.requestId===t);return r&&(r.status=n),n}async function a(t){let n=await am(t),r=e.value.find(e=>e.requestId===t);return r&&(r.status=n),n}function o(t,n){let r=e.value.find(e=>e.requestId===t);r&&(r.workspace=n)}function s(e){t.value=e}return{sessions:e,currentId:t,current:n,sendQuery:r,pollStatus:i,waitForDone:a,updateWorkspace:o,setCurrent:s}}),sm={class:`chat-view`},cm={class:`sidebar`},lm={class:`session-list`},um=[`onClick`],dm={class:`s-query`},fm={class:`main`},pm={key:0,class:`empty`},mm={class:`user-msg`},hm={class:`status-bar`},gm={key:0,class:`badge pending`},_m={key:1,class:`badge running`},vm={key:2,class:`badge done`},ym={key:3,class:`badge failed`},bm={key:4,class:`route-path`},xm={key:0,class:`ws-meta`},Sm={key:1,class:`assistant-msg`},Cm={key:2,class:`ws-preview`},wm={key:0,class:`brief-block`},Tm={class:`tags`},Em={key:1,class:`plan-list`},Dm={class:`step-id`},Om={key:0,class:`deps`},km={key:2,class:`progress-list`},Am={key:3,class:`error-msg`},jm=[`disabled`],Mm=[`disabled`],Nm=Qn({__name:`ChatView`,setup(e){let t=om(),n=R(``),r=R(!1),i=G(()=>t.current()),a=G(()=>i.value?.status?.status??`pending`),o=G(()=>i.value?.workspace),s=G(()=>i.value?.status?.response??null),c=null;function l(e){c?.close(),c=Ep(e),c.subscribe({onWorkspace(n){t.updateWorkspace(e,n)},onStatus(n){t.pollStatus(e)},onError(n){let r=t.sessions.find(t=>t.requestId===e);r&&(r.error=n)},onDone(){t.pollStatus(e)}})}Hn(()=>t.currentId,e=>{e&&(l(e),i.value?.status?.status===`done`&&t.pollStatus(e))},{immediate:!0});async function u(){if(!n.value.trim()||r.value)return;let e=n.value.trim();n.value=``,r.value=!0;try{l((await t.sendQuery(e)).requestId)}finally{r.value=!1}}return(e,i)=>(V(),H(`div`,sm,[U(`aside`,cm,[i[1]||=U(`h3`,null,`会话记录`,-1),U(`ul`,lm,[(V(!0),H(B,null,Dr(z(t).sessions,e=>(V(),H(`li`,{key:e.requestId,class:pe([`session-item`,{active:e.requestId===z(t).currentId}]),onClick:n=>z(t).setCurrent(e.requestId)},[U(`span`,dm,N(e.query.slice(0,28))+N(e.query.length>28?`…`:``),1),U(`span`,{class:pe([`s-status`,e.status?.status??`pending`])},N(e.status?.status??`pending`),3)],10,um))),128))])]),U(`main`,fm,[z(t).current()?(V(),H(B,{key:1},[U(`div`,mm,[i[3]||=U(`span`,{class:`role-label`},`你`,-1),U(`p`,null,N(z(t).current().query),1)]),U(`div`,hm,[a.value===`pending`?(V(),H(`span`,gm,`⏳ 排队中…`)):a.value===`running`?(V(),H(`span`,_m,` 🔄 协作中 (`+N(o.value?.meta.round??0)+`/`+N(o.value?.meta.rounds_cap??6)+`) `,1)):a.value===`done`?(V(),H(`span`,vm,`✅ 完成`)):a.value===`failed`?(V(),H(`span`,ym,`❌ 失败`)):W(``,!0),o.value?(V(),H(`span`,bm,` 路由:`+N(z(t).current().status?.route?.join(` → `)??`—`),1)):W(``,!0)]),o.value?(V(),H(`div`,xm,[U(`span`,null,`tokens: `+N(o.value.meta.api_input_tokens)+` in / `+N(o.value.meta.api_output_tokens)+` out`,1),U(`span`,null,`延迟: `+N(z(t).current().status?.latency_ms?.toFixed(0))+` ms`,1),U(`span`,null,`模型: `+N(z(t).current().status?.model_used??`—`),1)])):W(``,!0),s.value?(V(),H(`div`,Sm,[i[4]||=U(`span`,{class:`role-label`},`系统`,-1),U(`pre`,null,N(s.value),1)])):W(``,!0),o.value?(V(),H(`details`,Cm,[i[6]||=U(`summary`,null,`📄 交流文本预览`,-1),o.value.brief?(V(),H(`div`,wm,[i[5]||=U(`strong`,null,`Brief:`,-1),aa(` `+N(o.value.brief.goal)+` `,1),U(`span`,Tm,N(o.value.brief.tags.join(`, `)),1)])):W(``,!0),o.value.plan?.length?(V(),H(`ul`,Em,[(V(!0),H(B,null,Dr(o.value.plan,e=>(V(),H(`li`,{key:e.id,class:pe(e.status)},[U(`span`,Dm,N(e.id),1),U(`span`,null,N(e.task),1),e.deps.length?(V(),H(`span`,Om,`←`+N(e.deps.join(`,`)),1)):W(``,!0)],2))),128))])):W(``,!0),o.value.progress?.length?(V(),H(`ul`,km,[(V(!0),H(B,null,Dr(o.value.progress,e=>(V(),H(`li`,{key:e.step,class:pe(e.status)},N(e.step)+`: `+N(e.status),3))),128))])):W(``,!0)])):W(``,!0),z(t).current().error?(V(),H(`div`,Am,N(z(t).current().error),1)):W(``,!0)],64)):(V(),H(`div`,pm,[...i[2]||=[U(`p`,null,`输入问题,开启端云协同协作之旅。`,-1),U(`p`,{class:`hint`},`结果通过 SSE 实时推送,可切换「协作」页面查看交流文本可视化。`,-1)]])),U(`form`,{class:`input-bar`,onSubmit:Fo(u,[`prevent`])},[Fn(U(`input`,{"onUpdate:modelValue":i[0]||=e=>n.value=e,placeholder:`输入你的问题…`,disabled:r.value,autofocus:``},null,8,jm),[[To,n.value]]),U(`button`,{type:`submit`,disabled:r.value||!n.value.trim()},N(r.value?`发送中…`:`发送`),9,Mm)],32)])]))}}),Pm=(e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n},Fm=Pm(Nm,[[`__scopeId`,`data-v-d79f05ea`]]),Im={class:`agent-view`},Lm={class:`sess-panel`},Rm={class:`sess-list`},zm=[`onClick`],Bm={class:`sess-title`},Vm={class:`sess-meta`},Hm=[`onClick`],Um={key:0,class:`sess-empty`},Wm={class:`chat-col`},Gm={key:0,class:`hero`},Km={class:`hero-tips`},qm=[`onClick`],Jm={class:`stream-inner`},Ym={key:0,class:`row user`},Xm={class:`bubble-user`},Zm={key:1,class:`row assistant`},Qm={class:`bubble-ai`},$m=[`open`],eh={class:`fold-body`},th={key:0,class:`mini-phase`},nh={key:2,class:`mini-row`},rh={class:`mini-args`},ih={key:4,class:`mini-row delta-row`},ah={key:1,class:`tool-summary`},oh={key:2,class:`approval-card`},sh={class:`ap-head`},ch={class:`ap-args`},lh={class:`ap-actions`},uh=[`onClick`],dh=[`onClick`],fh={key:4,class:`ai-stream`},ph={key:5,class:`ai-text`},mh={key:6,class:`ai-error`},hh={key:7,class:`ai-running`},gh={class:`composer-wrap`},_h={class:`composer`},vh={class:`composer-bar`},yh=[`value`],bh={class:`chip toggle-chip`,title:`开启后智能体可执行 shell 命令`},xh={key:0,class:`composer-err`},Sh={class:`composer-main`},Ch=[`placeholder`,`disabled`,`onKeydown`],wh=[`disabled`],Th={class:`modal`},Eh={class:`crumb`},Dh={class:`dir-list`},Oh=[`onClick`],kh={key:1,class:`dir-item empty`},Ah={class:`path-row`},jh={class:`create-toggle`},Mh={key:0,class:`recent-row`},Nh=[`title`,`onClick`],Ph={key:1,class:`picker-msg`},Fh={class:`modal-actions`},Ih=Pm(Qn({__name:`AgentView`,setup(e){let t=[`浏览这个项目,总结目录结构和入口文件`,`运行测试,修复失败的用例,再跑一遍确认`,`给 README 补充安装与运行说明`],n=R([]),r=R(``),i=R([]),a=R(``),o=R(!1),s=R(``),c=R(``),l=R(``),u=R(``),d=R(!1),f=R(`dangerous`),p=R([]),m=R([]),h=R(!1),g=R(``),_=R({ok:!0,path:``,parent:``,dirs:[]}),v=R(``),y=R(!1),b=R(null),x=null,S=G(()=>m.value.filter(e=>e.enabled&&e.backend!==`mock`).sort((e,t)=>(e.backend===`llama_server`?-1:0)-(t.backend===`llama_server`?-1:0))),C=G(()=>!!a.value.trim()&&!!l.value);function w(e){if(!e)return``;let t=e.replace(/[\\/]+$/,``).split(/[\\/]/);return t[t.length-1]||e}function ee(e,t){if(!e)return t;let n=e.includes(`\\`)?`\\`:`/`;return e.endsWith(`\\`)||e.endsWith(`/`)?e+t:e+n+t}function te(e){if(!e)return``;let t=new Date(e*1e3);return`${t.getMonth()+1}/${t.getDate()} ${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`}function ne(e,t){return String(e??``).slice(0,t)}function re(e){let t=JSON.stringify(e)??``;return t.length>80?t.slice(0,80)+`…`:t}function ie(e){let t=e.model?` · ${e.model}`:``;return e.phase===`plan`?`🧠 规划者 · 拆解任务${t}`:e.phase===`execute`?`🔧 执行者 · 第 ${e.handoff} 轮交接${t}`:`🔍 规划者 · 审查裁决${t}`}function T(){Sn(()=>b.value?.scrollTo({top:b.value.scrollHeight}))}async function E(){try{n.value=await Zp()}catch{n.value=[]}}function D(e){return typeof e.turns==`number`?e.turns:e.turns.length}async function O(){try{let e=await Xp(l.value,u.value);r.value=e.id,i.value=[],await E()}catch(e){c.value=e?.message||String(e)}}async function ae(e){if(!o.value){r.value=e;try{let t=await Qp(e);l.value=t.workspace||l.value,t.executor_pool_id&&(u.value=t.executor_pool_id);let n=t.turns||[];i.value=n.flatMap(e=>[{role:`user`,content:e.task},{role:`assistant`,content:e.response||``,toolCalls:e.tool_calls||0,error:e.error,requestId:e.request_id}]),T()}catch{i.value=[]}}}async function k(e){confirm(`删除该会话?`)&&(await $p(e),r.value===e&&(r.value=``,i.value=[]),E())}async function oe(){h.value=!0,g.value=``,v.value=l.value;try{_.value=await tm(``)}catch{}}async function se(e){try{let t=await tm(e);t.ok?(_.value=t,v.value=t.path):g.value=t.error||`路径不可用`}catch{g.value=`浏览失败`}}async function A(e){if(e=(e||``).trim(),!e){g.value=`请先选择或输入目录路径`;return}try{let t=await rm(e,y.value);l.value=t.current,p.value=t.recent,h.value=!1}catch(e){g.value=e?.response?.data?.detail||e?.message||String(e)}}async function j(){try{await jp({agent:{allow_shell:d.value}})}catch{d.value=!d.value}}async function M(){try{await jp({agent:{approval_policy:f.value}})}catch{}}async function ce(){if(!C.value||o.value)return;let e=a.value.trim();if(c.value=``,a.value=``,o.value=!0,!r.value)try{let e=await Xp(l.value,u.value);r.value=e.id,E()}catch(t){o.value=!1,c.value=t?.message||String(t),a.value=e;return}i.value.push({role:`user`,content:e});let t={role:`assistant`,content:``,liveEvents:[]};i.value.push(t),T();try{let n=await Jp(e,``,l.value,u.value,r.value);s.value=n.request_id,n.workspace&&(l.value=n.workspace),x=im(n.request_id),x.subscribe({onEvent:e=>{if(e.type!==`final`){if(e.type===`approval_request`)t.approval={id:e.id,name:e.name,arguments:e.arguments,decided:!1,allowed:!1};else if(e.type===`approval_decided`)t.approval&&t.approval.id===e.id&&(t.approval.decided=!0,t.approval.allowed=!!e.allowed);else if(e.type===`delta`){t.streamText=(t.streamText||``)+(e.text||``),T();return}else(e.type===`tool_call`||e.type===`phase`||e.type===`message`)&&(t.streamText=``);t.liveEvents.push(e),T()}},onDone:async()=>{try{let e=await em(n.request_id);t.content=e.response||``,!t.content&&!t.error&&(t.content=`(本轮模型未返回文本内容——小模型能力有限或响应为空,可重试或换用更强的模型)`),t.toolCalls=e.tool_calls??t.liveEvents.filter(e=>e.type===`tool_call`).length,t.error=e.error||null}catch{}o.value=!1,s.value=``,E(),T()}})}catch(n){o.value=!1,t.error=n?.response?.data?.detail||n?.message||String(n),a.value=e}}async function le(){if(s.value)try{await Yp(s.value)}catch{}}async function ue(e,t){if(!(!e.approval||!e.requestId)){e.approval.decided=!0,e.approval.allowed=t;try{await qp(e.requestId,e.approval.id,t)}catch(t){e.approval.decided=!1,c.value=t?.response?.data?.detail||t?.message||String(t)}}}return pr(async()=>{E();try{let[e,t,n]=await Promise.all([Vp(),nm(),Ap()]);m.value=e.entries,l.value=t.current||``,p.value=t.recent||[],n.agent?.approval_policy&&(f.value=n.agent.approval_policy)}catch{}}),(e,s)=>(V(),H(`div`,Im,[U(`aside`,Lm,[U(`button`,{class:`new-sess`,onClick:O},`+ 新会话`),U(`div`,Rm,[(V(!0),H(B,null,Dr(n.value,e=>(V(),H(`div`,{key:e.id,class:pe([`sess-item`,{active:e.id===r.value}]),onClick:t=>ae(e.id)},[U(`div`,Bm,N(e.title),1),U(`div`,Vm,[U(`span`,null,N(D(e))+` 轮`,1),s[10]||=U(`span`,null,`·`,-1),U(`span`,null,N(te(e.updated_at)),1),U(`span`,{class:`sess-del`,title:`删除会话`,onClick:Fo(t=>k(e.id),[`stop`])},`✕`,8,Hm)])],10,zm))),128)),n.value.length?W(``,!0):(V(),H(`div`,Um,`暂无会话`))])]),U(`main`,Wm,[!i.value.length&&!o.value?(V(),H(`div`,Gm,[s[11]||=U(`div`,{class:`hero-logo`},`🤖`,-1),s[12]||=U(`h2`,null,`智能体`,-1),s[13]||=U(`p`,null,`选择工作目录,用一句话派活——读 / 写 / 编辑 / 搜索 / 执行命令全程可视化。`,-1),U(`div`,Km,[(V(),H(B,null,Dr(t,e=>U(`button`,{key:e,class:`tip-chip`,onClick:t=>a.value=e},N(e),9,qm)),64))])])):(V(),H(`div`,{key:1,class:`stream`,ref_key:`streamEl`,ref:b},[U(`div`,Jm,[(V(!0),H(B,null,Dr(i.value,(e,t)=>(V(),H(B,{key:t},[e.role===`user`?(V(),H(`div`,Ym,[U(`div`,Xm,N(e.content),1)])):(V(),H(`div`,Zm,[U(`div`,Qm,[e.liveEvents&&e.liveEvents.length?(V(),H(`details`,{key:0,class:`tool-fold`,open:o.value&&t===i.value.length-1},[U(`summary`,null,`⚙ 工具执行过程(`+N(e.liveEvents.length)+` 条事件)`,1),U(`div`,eh,[(V(!0),H(B,null,Dr(e.liveEvents,(e,t)=>(V(),H(B,{key:t},[e.type===`phase`?(V(),H(`div`,th,N(ie(e)),1)):e.type===`message`?(V(),H(`div`,{key:1,class:pe([`mini-msg`,e.role===`planner`?`mp`:`me`])},N(e.role===`planner`?`🧠`:`🔧`)+` `+N(ne(e.content,300)),3)):e.type===`tool_call`?(V(),H(`div`,nh,[s[14]||=aa(` 🛠️ `,-1),U(`b`,null,N(e.name),1),U(`span`,rh,N(re(e.arguments)),1)])):e.type===`tool_result`?(V(),H(`div`,{key:3,class:pe([`mini-row`,e.ok?`ok`:`err`])},N(e.ok?`✓`:`✕`)+` `+N(e.name)+` · `+N(ne(e.preview,120)),3)):e.type===`delta`?(V(),H(`div`,ih,N(ne(e.text,200)),1)):W(``,!0)],64))),128))])],8,$m)):e.toolCalls?(V(),H(`div`,ah,`⚙ 执行了 `+N(e.toolCalls)+` 步工具调用`,1)):W(``,!0),e.approval&&!e.approval.decided?(V(),H(`div`,oh,[U(`div`,sh,[s[15]||=aa(`⏸ 等待审批:`,-1),U(`b`,null,N(e.approval.name),1),s[16]||=aa(` 请求执行`,-1)]),U(`pre`,ch,N(re(e.approval.arguments)),1),U(`div`,lh,[U(`button`,{class:`ap-btn reject`,onClick:t=>ue(e,!1)},`拒绝`,8,uh),U(`button`,{class:`ap-btn allow`,onClick:t=>ue(e,!0)},`允许一次`,8,dh)])])):e.approval&&e.approval.decided?(V(),H(`div`,{key:3,class:pe([`ap-done`,e.approval.allowed?`ok`:`no`])},N(e.approval.allowed?`✓ 已允许执行`:`✕ 已拒绝`),3)):W(``,!0),e.streamText?(V(),H(`div`,fh,[aa(N(e.streamText),1),s[17]||=U(`span`,{class:`cursor`},null,-1)])):W(``,!0),e.content?(V(),H(`div`,ph,N(e.content),1)):e.error?(V(),H(`div`,mh,`❌ `+N(e.error),1)):o.value&&t===i.value.length-1?(V(),H(`div`,hh,[...s[18]||=[U(`span`,{class:`spinner`},null,-1),aa(` 正在思考与执行… `,-1)]])):W(``,!0)])]))],64))),128))])],512)),U(`div`,gh,[U(`div`,_h,[U(`div`,vh,[U(`button`,{class:`chip`,onClick:oe,title:`选择工作目录`},` 📁 `+N(w(l.value)||`选择目录`),1),Fn(U(`select`,{"onUpdate:modelValue":s[0]||=e=>u.value=e,class:`chip select-chip`,title:`两级模式:大模型拆解/审查,本地小模型执行`},[s[19]||=U(`option`,{value:``},`单模型`,-1),(V(!0),H(B,null,Dr(S.value,e=>(V(),H(`option`,{key:e.id,value:e.id},` 🔧 `+N(e.name),9,yh))),128))],512),[[Oo,u.value]]),U(`label`,bh,[Fn(U(`input`,{type:`checkbox`,"onUpdate:modelValue":s[1]||=e=>d.value=e,onChange:j},null,544),[[Eo,d.value]]),s[20]||=aa(` 命令 `,-1)]),Fn(U(`select`,{"onUpdate:modelValue":s[2]||=e=>f.value=e,class:`chip select-chip`,title:`审批策略:哪些操作需要你确认`,onChange:M},[...s[21]||=[U(`option`,{value:`off`},`审批:关`,-1),U(`option`,{value:`dangerous`},`审批:写与命令`,-1),U(`option`,{value:`all`},`审批:全部操作`,-1)]],544),[[Oo,f.value]]),c.value?(V(),H(`span`,xh,N(c.value),1)):W(``,!0)]),U(`div`,Sh,[Fn(U(`textarea`,{"onUpdate:modelValue":s[3]||=e=>a.value=e,class:`composer-input`,rows:`1`,placeholder:l.value?`给智能体派活…(Enter 发送,Shift+Enter 换行)`:`先点击左上角 📁 选择工作目录`,disabled:o.value,onKeydown:Lo(Fo(ce,[`exact`,`prevent`]),[`enter`])},null,40,Ch),[[To,a.value]]),o.value?(V(),H(`button`,{key:0,class:`send-btn stop`,onClick:le,title:`停止`},`■`)):(V(),H(`button`,{key:1,class:`send-btn`,disabled:!C.value,onClick:ce,title:`发送(Enter)`},`↑`,8,wh))])])])]),h.value?(V(),H(`div`,{key:0,class:`modal-mask`,onClick:s[9]||=Fo(e=>h.value=!1,[`self`])},[U(`div`,Th,[s[24]||=U(`div`,{class:`modal-title`},`选择工作目录`,-1),U(`div`,Eh,N(_.value.path||`(此电脑 — 点击选择盘符)`),1),U(`div`,Dh,[_.value.parent?(V(),H(`div`,{key:0,class:`dir-item up`,onClick:s[4]||=e=>se(_.value.parent)},` ↰ 上级:`+N(_.value.parent),1)):W(``,!0),(V(!0),H(B,null,Dr(_.value.dirs,e=>(V(),H(`div`,{key:e,class:`dir-item`,onClick:t=>se(ee(_.value.path,e))},` 📂 `+N(e),9,Oh))),128)),_.value.dirs.length?W(``,!0):(V(),H(`div`,kh,`(无子目录——可直接点下方"打开此目录")`))]),U(`div`,Ah,[Fn(U(`input`,{"onUpdate:modelValue":s[5]||=e=>v.value=e,placeholder:`或直接输入绝对路径,如 E:\\my-project`},null,512),[[To,v.value]]),U(`label`,jh,[Fn(U(`input`,{type:`checkbox`,"onUpdate:modelValue":s[6]||=e=>y.value=e},null,512),[[Eo,y.value]]),s[22]||=aa(` 不存在则新建 `,-1)])]),p.value.length?(V(),H(`div`,Mh,[s[23]||=U(`span`,{class:`recent-label`},`最近:`,-1),(V(!0),H(B,null,Dr(p.value,e=>(V(),H(`button`,{key:e,class:`recent-chip`,title:e,onClick:t=>A(e)},N(w(e)),9,Nh))),128))])):W(``,!0),g.value?(V(),H(`div`,Ph,N(g.value),1)):W(``,!0),U(`div`,Fh,[U(`button`,{class:`btn-primary`,onClick:s[7]||=e=>A(v.value.trim()||_.value.path)},` 打开此目录 `),U(`button`,{class:`btn-secondary`,onClick:s[8]||=e=>h.value=!1},`取消`)])])])):W(``,!0)]))}}),[[`__scopeId`,`data-v-3723cd6f`]]),Lh=`modulepreload`,Rh=function(e){return`/static/`+e},zh={},Bh=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=Rh(t,n),t=s(t),t in zh)return;zh[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:Lh,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},Vh=kl({history:Yc(`/`),routes:[{path:`/`,redirect:`/chat`},{path:`/chat`,name:`chat`,component:Fm},{path:`/collaboration`,name:`collaboration`,component:()=>Bh(()=>import(`./CollaborationView-DHMzJVru.js`),__vite__mapDeps([0,1]))},{path:`/agent`,name:`agent`,component:Ih},{path:`/review`,name:`review`,component:()=>Bh(()=>import(`./ReviewView-Cm34POvM.js`),__vite__mapDeps([2,3]))},{path:`/metrics`,name:`metrics`,component:()=>Bh(()=>import(`./MetricsView-BMWM9u4c.js`),__vite__mapDeps([4,5]))},{path:`/settings`,name:`settings`,component:()=>Bh(()=>import(`./SettingsView-DMG9EXA2.js`),__vite__mapDeps([6,7]))}]}),Hh=Vo(Os);Hh.use(ss()),Hh.use(Vh),Hh.mount(`#app`);export{W as A,Lt as B,Ep as C,B as D,To as E,_r as F,N as G,z as H,V as I,Dr as L,aa as M,Qn as N,G as O,pr as P,Hn as R,Bp as S,Oo as T,pe as U,R as V,ce as W,Rp as _,Ap as a,jp as b,Vp as c,Kp as d,Dp as f,Lp as g,Wp as h,zp as i,H as j,U as k,Ip as l,Mp as m,om as n,Fp as o,Pp as p,Up as r,kp as s,Pm as t,Np as u,Op as v,Eo as w,Hp as x,Gp as y,Fn as z}; \ No newline at end of file +`+r)}}catch{}throw e}}_request(e,t){typeof e==`string`?(t||={},t.url=e):t=e||{},t=Of(this.defaults,t);let{transitional:n,paramsSerializer:r,headers:i}=t;n!==void 0&&gp.assertOptions(n,{silentJSONParsing:_p.transitional(_p.boolean),forcedJSONParsing:_p.transitional(_p.boolean),clarifyTimeoutError:_p.transitional(_p.boolean),legacyInterceptorReqResOrdering:_p.transitional(_p.boolean),advertiseZstdAcceptEncoding:_p.transitional(_p.boolean),validateStatusUndefinedResolves:_p.transitional(_p.boolean)},!1),r!=null&&(Y.isFunction(r)?t.paramsSerializer={serialize:r}:gp.assertOptions(r,{encode:_p.function,serialize:_p.function},!0)),t.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls===void 0?t.allowAbsoluteUrls=!0:t.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls),gp.assertOptions(t,{baseUrl:_p.spelling(`baseURL`),withXsrfToken:_p.spelling(`withXSRFToken`)},!0),t.method=(Y.getSafeProp(t,`method`)||Y.getSafeProp(this.defaults,`method`)||`get`).toLowerCase();let a=i&&Y.merge(i.common,i[t.method]);i&&Y.forEach(ef.concat(`common`),e=>{delete i[e]}),t.headers=vd.concat(a,i);let o=[],s=!0;this.interceptors.request.forEach(function(e){if(typeof e.runWhen==`function`&&e.runWhen(t)===!1)return;s&&=e.synchronous;let n=t.transitional||Bd;n&&n.legacyInterceptorReqResOrdering?o.unshift(e.fulfilled,e.rejected):o.push(e.fulfilled,e.rejected)});let c=[];this.interceptors.response.forEach(function(e){c.push(e.fulfilled,e.rejected)});let l,u=0,d;if(!s){let e=[fp.bind(this),void 0];for(e.unshift(...o),e.push(...c),d=e.length,l=Promise.resolve(t);ufp.call(this,f)))}catch(e){l=Promise.reject(e)}break}}if(!l)try{l=fp.call(this,f)}catch(e){l=Promise.reject(e)}for(u=0,d=c.length;u{if(!n._listeners)return;let t=n._listeners.length;for(;t-->0;)n._listeners[t](e);n._listeners=null}),this.promise.then=e=>{let t,r=new Promise(e=>{n.subscribe(e),t=e}).then(e);return r.cancel=function(){n.unsubscribe(t)},r},e(function(e,r,i){n.reason||(n.reason=new sf(e,r,i),t(n.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;let t=this._listeners.indexOf(e);t!==-1&&this._listeners.splice(t,1)}toAbortSignal(){let e=new AbortController,t=t=>{e.abort(t)};return this.subscribe(t),e.signal.unsubscribe=()=>this.unsubscribe(t),e.signal}static source(){let t;return{token:new e(function(e){t=e}),cancel:t}}};function bp(e){return function(t){return e.apply(null,t)}}function xp(e){return Y.isObject(e)&&e.isAxiosError===!0}var Sp={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,ContentTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,UnprocessableContent:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerReturnsAnUnknownError:520,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Sp).forEach(([e,t])=>{Sp[t]===void 0&&(Sp[t]=e)});function Cp(e){let t=new vp(e),n=Al(vp.prototype.request,t);return Y.extend(n,vp.prototype,t,{allOwnKeys:!0}),Y.extend(n,t,null,{allOwnKeys:!0}),n.create=function(t){return Cp(Of(e,t))},n}var Q=Cp(rf);Q.Axios=vp,Q.CanceledError=sf,Q.CancelToken=yp,Q.isCancel=of,Q.VERSION=Yf,Q.toFormData=kd,Q.AxiosError=X,Q.Cancel=Q.CanceledError,Q.all=function(e){return Promise.all(e)},Q.spread=bp,Q.isAxiosError=xp,Q.mergeConfig=Of,Q.AxiosHeaders=vd,Q.formToJSON=e=>$d(Y.isHTMLForm(e)?new FormData(e):e),Q.getAdapter=up.getAdapter,Q.HttpStatusCode=Sp,Q.default=Q;var $=Q.create({timeout:1e4});async function wp(e,t){let{data:n}=await $.post(`/chat`,{query:e,domain_group:t});return n}async function Tp(e){let{data:t}=await $.get(`/runs/${e}/status`);return t}function Ep(e){let t=new EventSource(`/runs/${e}/stream`);return{subscribe(e){t.addEventListener(`message`,t=>{let n=JSON.parse(t.data);n.type===`workspace`?e.onWorkspace(n.workspace):n.type===`status`?(e.onStatus(n.value),(n.value===`done`||n.value===`failed`)&&e.onDone()):n.type===`error`&&e.onError(n.detail)}),t.addEventListener(`error`,()=>{})},close(){t.close()}}}async function Dp(e){let t=e?{status:e}:{},{data:n}=await $.get(`/review/queue`,{params:t});return n}async function Op(e,t,n){let{data:r}=await $.post(`/review/${e}`,null,{params:{verdict:t,correction:n}});return r}async function kp(){let{data:e}=await $.get(`/api/metrics`);return e}async function Ap(){let{data:e}=await $.get(`/config`);return e}async function jp(e){let{data:t}=await $.put(`/config`,e);return t}async function Mp(){let{data:e}=await $.post(`/config/reset`);return e}async function Np(e,t,n){let r={backend:e};t&&(r.base_url=t),n&&(r.api_key=n);let{data:i}=await $.get(`/config/models`,{params:r});return i}async function Pp(e,t,n){let r={backend:e};t&&(r.base_url=t),n&&(r.api_key=n);let{data:i}=await $.get(`/config/ping`,{params:r});return i}async function Fp(){let{data:e}=await $.get(`/llama/status`);return e}async function Ip(){let{data:e}=await $.get(`/llama/models`);return e.models}async function Lp(e,t=8901,n=99,r=4096){let{data:i}=await $.post(`/llama/start`,null,{params:{model:e,port:t,ngl:n,ctx:r}});return i}async function Rp(){let{data:e}=await $.post(`/llama/stop`);return e}async function zp(e,t){let n={url:e};t&&(n.dest=t);let{data:r}=await $.post(`/llama/download`,null,{params:n});return r}function Bp(e){let t=new EventSource(`/llama/download/stream?url=${encodeURIComponent(e)}`);return{subscribe(e){t.addEventListener(`message`,t=>{let n=JSON.parse(t.data);e.onProgress(n),n.done&&e.onDone(n)}),t.addEventListener(`error`,()=>{t.close()})},close(){t.close()}}}async function Vp(){let{data:e}=await $.get(`/pool`);return e}async function Hp(e){let{data:t}=await $.post(`/pool`,e);return t}async function Up(e){let{data:t}=await $.delete(`/pool/${e}`);return t}async function Wp(e){let{data:t}=await $.put(`/pool/roles`,e);return t}async function Gp(e){let{data:t}=await $.post(`/pool/${e}/test`);return t}async function Kp(e){let{data:t}=await $.get(`/pool/${e}/models`);return t}async function qp(e,t,n){let{data:r}=await $.post(`/agent/${e}/approve`,{approval_id:t,allowed:n});return r}async function Jp(e,t,n,r,i){let{data:a}=await $.post(`/agent`,{task:e,pool_id:t||void 0,workspace:n||void 0,executor_pool_id:r||void 0,session_id:i||void 0});return a}async function Yp(e){let{data:t}=await $.post(`/agent/${e}/cancel`);return t}async function Xp(e,t,n){let{data:r}=await $.post(`/agent/sessions`,{title:n||void 0,workspace:e||void 0,executor_pool_id:t||void 0});return r}async function Zp(){let{data:e}=await $.get(`/agent/sessions`);return e}async function Qp(e){let{data:t}=await $.get(`/agent/sessions/${e}`);return t}async function $p(e){let{data:t}=await $.delete(`/agent/sessions/${e}`);return t}async function em(e){let{data:t}=await $.get(`/agent/${e}/status`);return t}async function tm(e=``){let{data:t}=await $.get(`/agent/fs`,{params:e?{path:e}:{}});return t}async function nm(){let{data:e}=await $.get(`/agent/workspaces`);return e}async function rm(e,t=!1){let{data:n}=await $.post(`/agent/workspaces`,{path:e,create:t});return n}function im(e){let t=new EventSource(`/agent/${e}/stream`),n=!1;return{subscribe(e){t.addEventListener(`message`,r=>{if(n)return;let i=JSON.parse(r.data);e.onEvent(i),i.type===`final`&&(n=!0,t.close(),e.onDone())}),t.addEventListener(`error`,()=>{})},close(){t.close()}}}async function am(e,{timeout:t=6e4,interval:n=500}={}){let r=Date.now();for(;Date.now()-rsetTimeout(e,n))}throw Error(`poll timeout`)}var om=xs(`chat`,()=>{let e=R([]),t=R(null),n=()=>e.value.find(e=>e.requestId===t.value)??null;async function r(n){let r=await wp(n),i={requestId:r.request_id,query:n,init:r,status:null,workspace:null,error:null};return e.value.unshift(i),t.value=r.request_id,i}async function i(t){let n=await Tp(t),r=e.value.find(e=>e.requestId===t);return r&&(r.status=n),n}async function a(t){let n=await am(t),r=e.value.find(e=>e.requestId===t);return r&&(r.status=n),n}function o(t,n){let r=e.value.find(e=>e.requestId===t);r&&(r.workspace=n)}function s(e){t.value=e}return{sessions:e,currentId:t,current:n,sendQuery:r,pollStatus:i,waitForDone:a,updateWorkspace:o,setCurrent:s}}),sm={class:`chat-view`},cm={class:`sidebar`},lm={class:`session-list`},um=[`onClick`],dm={class:`s-query`},fm={class:`main`},pm={key:0,class:`empty`},mm={class:`user-msg`},hm={class:`status-bar`},gm={key:0,class:`badge pending`},_m={key:1,class:`badge running`},vm={key:2,class:`badge done`},ym={key:3,class:`badge failed`},bm={key:4,class:`route-path`},xm={key:0,class:`ws-meta`},Sm={key:1,class:`assistant-msg`},Cm={key:2,class:`ws-preview`},wm={key:0,class:`brief-block`},Tm={class:`tags`},Em={key:1,class:`plan-list`},Dm={class:`step-id`},Om={key:0,class:`deps`},km={key:2,class:`progress-list`},Am={key:3,class:`error-msg`},jm=[`disabled`],Mm=[`disabled`],Nm=Qn({__name:`ChatView`,setup(e){let t=om(),n=R(``),r=R(!1),i=G(()=>t.current()),a=G(()=>i.value?.status?.status??`pending`),o=G(()=>i.value?.workspace),s=G(()=>i.value?.status?.response??null),c=null;function l(e){c?.close(),c=Ep(e),c.subscribe({onWorkspace(n){t.updateWorkspace(e,n)},onStatus(n){t.pollStatus(e)},onError(n){let r=t.sessions.find(t=>t.requestId===e);r&&(r.error=n)},onDone(){t.pollStatus(e)}})}Hn(()=>t.currentId,e=>{e&&(l(e),i.value?.status?.status===`done`&&t.pollStatus(e))},{immediate:!0});async function u(){if(!n.value.trim()||r.value)return;let e=n.value.trim();n.value=``,r.value=!0;try{l((await t.sendQuery(e)).requestId)}finally{r.value=!1}}return(e,i)=>(V(),H(`div`,sm,[U(`aside`,cm,[i[1]||=U(`h3`,null,`会话记录`,-1),U(`ul`,lm,[(V(!0),H(B,null,Dr(z(t).sessions,e=>(V(),H(`li`,{key:e.requestId,class:pe([`session-item`,{active:e.requestId===z(t).currentId}]),onClick:n=>z(t).setCurrent(e.requestId)},[U(`span`,dm,N(e.query.slice(0,28))+N(e.query.length>28?`…`:``),1),U(`span`,{class:pe([`s-status`,e.status?.status??`pending`])},N(e.status?.status??`pending`),3)],10,um))),128))])]),U(`main`,fm,[z(t).current()?(V(),H(B,{key:1},[U(`div`,mm,[i[3]||=U(`span`,{class:`role-label`},`你`,-1),U(`p`,null,N(z(t).current().query),1)]),U(`div`,hm,[a.value===`pending`?(V(),H(`span`,gm,`⏳ 排队中…`)):a.value===`running`?(V(),H(`span`,_m,` 🔄 协作中 (`+N(o.value?.meta.round??0)+`/`+N(o.value?.meta.rounds_cap??6)+`) `,1)):a.value===`done`?(V(),H(`span`,vm,`✅ 完成`)):a.value===`failed`?(V(),H(`span`,ym,`❌ 失败`)):W(``,!0),o.value?(V(),H(`span`,bm,` 路由:`+N(z(t).current().status?.route?.join(` → `)??`—`),1)):W(``,!0)]),o.value?(V(),H(`div`,xm,[U(`span`,null,`tokens: `+N(o.value.meta.api_input_tokens)+` in / `+N(o.value.meta.api_output_tokens)+` out`,1),U(`span`,null,`延迟: `+N(z(t).current().status?.latency_ms?.toFixed(0))+` ms`,1),U(`span`,null,`模型: `+N(z(t).current().status?.model_used??`—`),1)])):W(``,!0),s.value?(V(),H(`div`,Sm,[i[4]||=U(`span`,{class:`role-label`},`系统`,-1),U(`pre`,null,N(s.value),1)])):W(``,!0),o.value?(V(),H(`details`,Cm,[i[6]||=U(`summary`,null,`📄 交流文本预览`,-1),o.value.brief?(V(),H(`div`,wm,[i[5]||=U(`strong`,null,`Brief:`,-1),aa(` `+N(o.value.brief.goal)+` `,1),U(`span`,Tm,N(o.value.brief.tags.join(`, `)),1)])):W(``,!0),o.value.plan?.length?(V(),H(`ul`,Em,[(V(!0),H(B,null,Dr(o.value.plan,e=>(V(),H(`li`,{key:e.id,class:pe(e.status)},[U(`span`,Dm,N(e.id),1),U(`span`,null,N(e.task),1),e.deps.length?(V(),H(`span`,Om,`←`+N(e.deps.join(`,`)),1)):W(``,!0)],2))),128))])):W(``,!0),o.value.progress?.length?(V(),H(`ul`,km,[(V(!0),H(B,null,Dr(o.value.progress,e=>(V(),H(`li`,{key:e.step,class:pe(e.status)},N(e.step)+`: `+N(e.status),3))),128))])):W(``,!0)])):W(``,!0),z(t).current().error?(V(),H(`div`,Am,N(z(t).current().error),1)):W(``,!0)],64)):(V(),H(`div`,pm,[...i[2]||=[U(`p`,null,`输入问题,开启端云协同协作之旅。`,-1),U(`p`,{class:`hint`},`结果通过 SSE 实时推送,可切换「协作」页面查看交流文本可视化。`,-1)]])),U(`form`,{class:`input-bar`,onSubmit:Fo(u,[`prevent`])},[Fn(U(`input`,{"onUpdate:modelValue":i[0]||=e=>n.value=e,placeholder:`输入你的问题…`,disabled:r.value,autofocus:``},null,8,jm),[[To,n.value]]),U(`button`,{type:`submit`,disabled:r.value||!n.value.trim()},N(r.value?`发送中…`:`发送`),9,Mm)],32)])]))}}),Pm=(e,t)=>{let n=e.__vccOpts||e;for(let[e,r]of t)n[e]=r;return n},Fm=Pm(Nm,[[`__scopeId`,`data-v-d79f05ea`]]),Im={class:`agent-view`},Lm={class:`sess-panel`},Rm={class:`sess-list`},zm=[`onClick`],Bm={class:`sess-title`},Vm={class:`sess-meta`},Hm=[`onClick`],Um={key:0,class:`sess-empty`},Wm={class:`chat-col`},Gm={key:0,class:`hero`},Km={class:`hero-tips`},qm=[`onClick`],Jm={class:`stream-inner`},Ym={key:0,class:`row user`},Xm={class:`bubble-user`},Zm={key:1,class:`row assistant`},Qm={class:`bubble-ai`},$m=[`open`],eh={class:`fold-body`},th={key:0,class:`mini-phase`},nh={key:2,class:`mini-row`},rh={class:`mini-args`},ih={key:4,class:`mini-row delta-row`},ah={key:1,class:`tool-summary`},oh={key:2,class:`approval-card`},sh={class:`ap-head`},ch={class:`ap-args`},lh={class:`ap-actions`},uh=[`onClick`],dh=[`onClick`],fh={key:4,class:`ai-stream`},ph={key:5,class:`ai-text`},mh={key:6,class:`ai-error`},hh={key:7,class:`ai-running`},gh={class:`composer-wrap`},_h={class:`composer`},vh={class:`composer-bar`},yh=[`value`],bh={class:`chip toggle-chip`,title:`开启后智能体可执行 shell 命令`},xh={key:0,class:`composer-err`},Sh={class:`composer-main`},Ch=[`placeholder`,`disabled`,`onKeydown`],wh=[`disabled`],Th={class:`modal`},Eh={class:`crumb`},Dh={class:`dir-list`},Oh=[`onClick`],kh={key:1,class:`dir-item empty`},Ah={class:`path-row`},jh={class:`create-toggle`},Mh={key:0,class:`recent-row`},Nh=[`title`,`onClick`],Ph={key:1,class:`picker-msg`},Fh={class:`modal-actions`},Ih=Pm(Qn({__name:`AgentView`,setup(e){let t=[`浏览这个项目,总结目录结构和入口文件`,`运行测试,修复失败的用例,再跑一遍确认`,`给 README 补充安装与运行说明`],n=R([]),r=R(``),i=R([]),a=R(``),o=R(!1),s=R(``),c=R(``),l=R(``),u=R(``),d=R(!1),f=R(`dangerous`),p=R([]),m=R([]),h=R(!1),g=R(``),_=R({ok:!0,path:``,parent:``,dirs:[]}),v=R(``),y=R(!1),b=R(null),x=null,S=G(()=>m.value.filter(e=>e.enabled&&e.backend!==`mock`).sort((e,t)=>(e.backend===`llama_server`?-1:0)-(t.backend===`llama_server`?-1:0))),C=G(()=>!!a.value.trim()&&!!l.value);function w(e){if(!e)return``;let t=e.replace(/[\\/]+$/,``).split(/[\\/]/);return t[t.length-1]||e}function ee(e,t){if(!e)return t;let n=e.includes(`\\`)?`\\`:`/`;return e.endsWith(`\\`)||e.endsWith(`/`)?e+t:e+n+t}function te(e){if(!e)return``;let t=new Date(e*1e3);return`${t.getMonth()+1}/${t.getDate()} ${String(t.getHours()).padStart(2,`0`)}:${String(t.getMinutes()).padStart(2,`0`)}`}function ne(e,t){return String(e??``).slice(0,t)}function re(e){let t=JSON.stringify(e)??``;return t.length>80?t.slice(0,80)+`…`:t}function ie(e){let t=e.model?` · ${e.model}`:``;return e.phase===`plan`?`🧠 规划者 · 拆解任务${t}`:e.phase===`execute`?`🔧 执行者 · 第 ${e.handoff} 轮交接${t}`:`🔍 规划者 · 审查裁决${t}`}function T(){Sn(()=>b.value?.scrollTo({top:b.value.scrollHeight}))}async function E(){try{n.value=await Zp()}catch{n.value=[]}}function D(e){return typeof e.turns==`number`?e.turns:e.turns.length}async function O(){try{let e=await Xp(l.value,u.value);r.value=e.id,i.value=[],await E()}catch(e){c.value=e?.message||String(e)}}async function ae(e){if(!o.value){r.value=e;try{let t=await Qp(e);l.value=t.workspace||l.value,t.executor_pool_id&&(u.value=t.executor_pool_id);let n=t.turns||[];i.value=n.flatMap(e=>[{role:`user`,content:e.task},{role:`assistant`,content:e.response||``,toolCalls:e.tool_calls||0,error:e.error,requestId:e.request_id}]),T()}catch{i.value=[]}}}async function k(e){confirm(`删除该会话?`)&&(await $p(e),r.value===e&&(r.value=``,i.value=[]),E())}async function oe(){h.value=!0,g.value=``,v.value=l.value;try{_.value=await tm(``)}catch{}}async function se(e){try{let t=await tm(e);t.ok?(_.value=t,v.value=t.path):g.value=t.error||`路径不可用`}catch{g.value=`浏览失败`}}async function A(e){if(e=(e||``).trim(),!e){g.value=`请先选择或输入目录路径`;return}try{let t=await rm(e,y.value);l.value=t.current,p.value=t.recent,h.value=!1}catch(e){g.value=e?.response?.data?.detail||e?.message||String(e)}}async function j(){try{await jp({agent:{allow_shell:d.value}})}catch{d.value=!d.value}}async function M(){try{await jp({agent:{approval_policy:f.value}})}catch{}}async function ce(){if(!C.value||o.value)return;let e=a.value.trim();if(c.value=``,a.value=``,o.value=!0,!r.value)try{let e=await Xp(l.value,u.value);r.value=e.id,E()}catch(t){o.value=!1,c.value=t?.message||String(t),a.value=e;return}i.value.push({role:`user`,content:e}),i.value.push({role:`assistant`,content:``,liveEvents:[]});let t=i.value[i.value.length-1];T();try{let n=await Jp(e,``,l.value,u.value,r.value);s.value=n.request_id,n.workspace&&(l.value=n.workspace),x=im(n.request_id),x.subscribe({onEvent:e=>{if(e.type!==`final`){if(e.type===`approval_request`)t.approval={id:e.id,name:e.name,arguments:e.arguments,decided:!1,allowed:!1};else if(e.type===`approval_decided`)t.approval&&t.approval.id===e.id&&(t.approval.decided=!0,t.approval.allowed=!!e.allowed);else if(e.type===`delta`){t.streamText=(t.streamText||``)+(e.text||``),T();return}else(e.type===`tool_call`||e.type===`phase`||e.type===`message`)&&(t.streamText=``);t.liveEvents.push(e),T()}},onDone:async()=>{try{let e=await em(n.request_id);t.content=e.response||``,!t.content&&!t.error&&(t.content=`(本轮模型未返回文本内容——小模型能力有限或响应为空,可重试或换用更强的模型)`),t.toolCalls=e.tool_calls??t.liveEvents.filter(e=>e.type===`tool_call`).length,t.error=e.error||null}catch{}o.value=!1,s.value=``,E(),T()}})}catch(n){o.value=!1,t.error=n?.response?.data?.detail||n?.message||String(n),a.value=e}}async function le(){if(s.value)try{await Yp(s.value)}catch{}}async function ue(e,t){if(!(!e.approval||!e.requestId)){e.approval.decided=!0,e.approval.allowed=t;try{await qp(e.requestId,e.approval.id,t)}catch(t){e.approval.decided=!1,c.value=t?.response?.data?.detail||t?.message||String(t)}}}return pr(async()=>{E();try{let[e,t,n]=await Promise.all([Vp(),nm(),Ap()]);m.value=e.entries,l.value=t.current||``,p.value=t.recent||[],n.agent?.approval_policy&&(f.value=n.agent.approval_policy)}catch{}}),(e,s)=>(V(),H(`div`,Im,[U(`aside`,Lm,[U(`button`,{class:`new-sess`,onClick:O},`+ 新会话`),U(`div`,Rm,[(V(!0),H(B,null,Dr(n.value,e=>(V(),H(`div`,{key:e.id,class:pe([`sess-item`,{active:e.id===r.value}]),onClick:t=>ae(e.id)},[U(`div`,Bm,N(e.title),1),U(`div`,Vm,[U(`span`,null,N(D(e))+` 轮`,1),s[10]||=U(`span`,null,`·`,-1),U(`span`,null,N(te(e.updated_at)),1),U(`span`,{class:`sess-del`,title:`删除会话`,onClick:Fo(t=>k(e.id),[`stop`])},`✕`,8,Hm)])],10,zm))),128)),n.value.length?W(``,!0):(V(),H(`div`,Um,`暂无会话`))])]),U(`main`,Wm,[!i.value.length&&!o.value?(V(),H(`div`,Gm,[s[11]||=U(`div`,{class:`hero-logo`},`🤖`,-1),s[12]||=U(`h2`,null,`智能体`,-1),s[13]||=U(`p`,null,`选择工作目录,用一句话派活——读 / 写 / 编辑 / 搜索 / 执行命令全程可视化。`,-1),U(`div`,Km,[(V(),H(B,null,Dr(t,e=>U(`button`,{key:e,class:`tip-chip`,onClick:t=>a.value=e},N(e),9,qm)),64))])])):(V(),H(`div`,{key:1,class:`stream`,ref_key:`streamEl`,ref:b},[U(`div`,Jm,[(V(!0),H(B,null,Dr(i.value,(e,t)=>(V(),H(B,{key:t},[e.role===`user`?(V(),H(`div`,Ym,[U(`div`,Xm,N(e.content),1)])):(V(),H(`div`,Zm,[U(`div`,Qm,[e.liveEvents&&e.liveEvents.length?(V(),H(`details`,{key:0,class:`tool-fold`,open:o.value&&t===i.value.length-1},[U(`summary`,null,`⚙ 工具执行过程(`+N(e.liveEvents.length)+` 条事件)`,1),U(`div`,eh,[(V(!0),H(B,null,Dr(e.liveEvents,(e,t)=>(V(),H(B,{key:t},[e.type===`phase`?(V(),H(`div`,th,N(ie(e)),1)):e.type===`message`?(V(),H(`div`,{key:1,class:pe([`mini-msg`,e.role===`planner`?`mp`:`me`])},N(e.role===`planner`?`🧠`:`🔧`)+` `+N(ne(e.content,300)),3)):e.type===`tool_call`?(V(),H(`div`,nh,[s[14]||=aa(` 🛠️ `,-1),U(`b`,null,N(e.name),1),U(`span`,rh,N(re(e.arguments)),1)])):e.type===`tool_result`?(V(),H(`div`,{key:3,class:pe([`mini-row`,e.ok?`ok`:`err`])},N(e.ok?`✓`:`✕`)+` `+N(e.name)+` · `+N(ne(e.preview,120)),3)):e.type===`delta`?(V(),H(`div`,ih,N(ne(e.text,200)),1)):W(``,!0)],64))),128))])],8,$m)):e.toolCalls?(V(),H(`div`,ah,`⚙ 执行了 `+N(e.toolCalls)+` 步工具调用`,1)):W(``,!0),e.approval&&!e.approval.decided?(V(),H(`div`,oh,[U(`div`,sh,[s[15]||=aa(`⏸ 等待审批:`,-1),U(`b`,null,N(e.approval.name),1),s[16]||=aa(` 请求执行`,-1)]),U(`pre`,ch,N(re(e.approval.arguments)),1),U(`div`,lh,[U(`button`,{class:`ap-btn reject`,onClick:t=>ue(e,!1)},`拒绝`,8,uh),U(`button`,{class:`ap-btn allow`,onClick:t=>ue(e,!0)},`允许一次`,8,dh)])])):e.approval&&e.approval.decided?(V(),H(`div`,{key:3,class:pe([`ap-done`,e.approval.allowed?`ok`:`no`])},N(e.approval.allowed?`✓ 已允许执行`:`✕ 已拒绝`),3)):W(``,!0),e.streamText?(V(),H(`div`,fh,[aa(N(e.streamText),1),s[17]||=U(`span`,{class:`cursor`},null,-1)])):W(``,!0),e.content?(V(),H(`div`,ph,N(e.content),1)):e.error?(V(),H(`div`,mh,`❌ `+N(e.error),1)):o.value&&t===i.value.length-1?(V(),H(`div`,hh,[...s[18]||=[U(`span`,{class:`spinner`},null,-1),aa(` 正在思考与执行… `,-1)]])):W(``,!0)])]))],64))),128))])],512)),U(`div`,gh,[U(`div`,_h,[U(`div`,vh,[U(`button`,{class:`chip`,onClick:oe,title:`选择工作目录`},` 📁 `+N(w(l.value)||`选择目录`),1),Fn(U(`select`,{"onUpdate:modelValue":s[0]||=e=>u.value=e,class:`chip select-chip`,title:`两级模式:大模型拆解/审查,本地小模型执行`},[s[19]||=U(`option`,{value:``},`单模型`,-1),(V(!0),H(B,null,Dr(S.value,e=>(V(),H(`option`,{key:e.id,value:e.id},` 🔧 `+N(e.name),9,yh))),128))],512),[[Oo,u.value]]),U(`label`,bh,[Fn(U(`input`,{type:`checkbox`,"onUpdate:modelValue":s[1]||=e=>d.value=e,onChange:j},null,544),[[Eo,d.value]]),s[20]||=aa(` 命令 `,-1)]),Fn(U(`select`,{"onUpdate:modelValue":s[2]||=e=>f.value=e,class:`chip select-chip`,title:`审批策略:哪些操作需要你确认`,onChange:M},[...s[21]||=[U(`option`,{value:`off`},`审批:关`,-1),U(`option`,{value:`dangerous`},`审批:写与命令`,-1),U(`option`,{value:`all`},`审批:全部操作`,-1)]],544),[[Oo,f.value]]),c.value?(V(),H(`span`,xh,N(c.value),1)):W(``,!0)]),U(`div`,Sh,[Fn(U(`textarea`,{"onUpdate:modelValue":s[3]||=e=>a.value=e,class:`composer-input`,rows:`1`,placeholder:l.value?`给智能体派活…(Enter 发送,Shift+Enter 换行)`:`先点击左上角 📁 选择工作目录`,disabled:o.value,onKeydown:Lo(Fo(ce,[`exact`,`prevent`]),[`enter`])},null,40,Ch),[[To,a.value]]),o.value?(V(),H(`button`,{key:0,class:`send-btn stop`,onClick:le,title:`停止`},`■`)):(V(),H(`button`,{key:1,class:`send-btn`,disabled:!C.value,onClick:ce,title:`发送(Enter)`},`↑`,8,wh))])])])]),h.value?(V(),H(`div`,{key:0,class:`modal-mask`,onClick:s[9]||=Fo(e=>h.value=!1,[`self`])},[U(`div`,Th,[s[24]||=U(`div`,{class:`modal-title`},`选择工作目录`,-1),U(`div`,Eh,N(_.value.path||`(此电脑 — 点击选择盘符)`),1),U(`div`,Dh,[_.value.parent?(V(),H(`div`,{key:0,class:`dir-item up`,onClick:s[4]||=e=>se(_.value.parent)},` ↰ 上级:`+N(_.value.parent),1)):W(``,!0),(V(!0),H(B,null,Dr(_.value.dirs,e=>(V(),H(`div`,{key:e,class:`dir-item`,onClick:t=>se(ee(_.value.path,e))},` 📂 `+N(e),9,Oh))),128)),_.value.dirs.length?W(``,!0):(V(),H(`div`,kh,`(无子目录——可直接点下方"打开此目录")`))]),U(`div`,Ah,[Fn(U(`input`,{"onUpdate:modelValue":s[5]||=e=>v.value=e,placeholder:`或直接输入绝对路径,如 E:\\my-project`},null,512),[[To,v.value]]),U(`label`,jh,[Fn(U(`input`,{type:`checkbox`,"onUpdate:modelValue":s[6]||=e=>y.value=e},null,512),[[Eo,y.value]]),s[22]||=aa(` 不存在则新建 `,-1)])]),p.value.length?(V(),H(`div`,Mh,[s[23]||=U(`span`,{class:`recent-label`},`最近:`,-1),(V(!0),H(B,null,Dr(p.value,e=>(V(),H(`button`,{key:e,class:`recent-chip`,title:e,onClick:t=>A(e)},N(w(e)),9,Nh))),128))])):W(``,!0),g.value?(V(),H(`div`,Ph,N(g.value),1)):W(``,!0),U(`div`,Fh,[U(`button`,{class:`btn-primary`,onClick:s[7]||=e=>A(v.value.trim()||_.value.path)},` 打开此目录 `),U(`button`,{class:`btn-secondary`,onClick:s[8]||=e=>h.value=!1},`取消`)])])])):W(``,!0)]))}}),[[`__scopeId`,`data-v-f544df91`]]),Lh=`modulepreload`,Rh=function(e){return`/static/`+e},zh={},Bh=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=Rh(t,n),t=s(t),t in zh)return;zh[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:Lh,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},Vh=kl({history:Yc(`/`),routes:[{path:`/`,redirect:`/chat`},{path:`/chat`,name:`chat`,component:Fm},{path:`/collaboration`,name:`collaboration`,component:()=>Bh(()=>import(`./CollaborationView-BzBpxfYH.js`),__vite__mapDeps([0,1]))},{path:`/agent`,name:`agent`,component:Ih},{path:`/review`,name:`review`,component:()=>Bh(()=>import(`./ReviewView-wY3DEmtF.js`),__vite__mapDeps([2,3]))},{path:`/metrics`,name:`metrics`,component:()=>Bh(()=>import(`./MetricsView-Dm03Grst.js`),__vite__mapDeps([4,5]))},{path:`/settings`,name:`settings`,component:()=>Bh(()=>import(`./SettingsView-B4tzUqnq.js`),__vite__mapDeps([6,7]))}]}),Hh=Vo(Os);Hh.use(ss()),Hh.use(Vh),Hh.mount(`#app`);export{W as A,Lt as B,Ep as C,B as D,To as E,_r as F,N as G,z as H,V as I,Dr as L,aa as M,Qn as N,G as O,pr as P,Hn as R,Bp as S,Oo as T,pe as U,R as V,ce as W,Rp as _,Ap as a,jp as b,Vp as c,Kp as d,Dp as f,Lp as g,Wp as h,zp as i,H as j,U as k,Ip as l,Mp as m,om as n,Fp as o,Pp as p,Up as r,kp as s,Pm as t,Np as u,Op as v,Eo as w,Hp as x,Gp as y,Fn as z}; \ No newline at end of file diff --git a/gateway/static/assets/index-wqjFJqzj.css b/gateway/static/assets/index-rGGK-sk_.css similarity index 66% rename from gateway/static/assets/index-wqjFJqzj.css rename to gateway/static/assets/index-rGGK-sk_.css index 4760670..e62f97f 100644 --- a/gateway/static/assets/index-wqjFJqzj.css +++ b/gateway/static/assets/index-rGGK-sk_.css @@ -1 +1 @@ -.app{height:100%;display:flex}.side{background:var(--c-side-bg);border-right:1px solid var(--c-side-border);width:208px;color:var(--c-side-text);-webkit-user-select:none;user-select:none;flex-direction:column;flex-shrink:0;padding:18px 12px 14px;display:flex}.brand{align-items:center;gap:10px;margin-bottom:12px;padding:4px 8px 16px;display:flex}.brand-logo{background:linear-gradient(135deg, var(--ds-blue-400), var(--ds-blue-500));border-radius:11px;place-items:center;width:38px;height:38px;font-size:20px;display:grid;box-shadow:0 3px 10px #4176e659}.brand-text{flex-direction:column;line-height:1.3;display:flex}.brand-text b{color:var(--c-text);letter-spacing:.5px;font-size:15px}.brand-text span{color:var(--c-caption);font-size:11px}.nav{flex-direction:column;flex:1;gap:2px;display:flex}.nav-item{color:var(--c-side-text);transition:background .15s var(--ds-ease), color .15s var(--ds-ease);border-radius:9px;align-items:center;gap:11px;padding:8px 10px;font-size:13.5px;font-weight:500;text-decoration:none;display:flex;position:relative}.nav-item:hover{background:var(--c-side-hover);color:var(--c-text)}.nav-item.router-link-active{background:var(--c-side-active);color:var(--c-side-text-active);font-weight:600}.nav-item.router-link-active:before{content:"";background:var(--c-accent);border-radius:0 3px 3px 0;width:3px;position:absolute;top:7px;bottom:7px;left:-12px}.nav-icon{background:var(--c-hover);border-radius:7px;place-items:center;width:26px;height:26px;font-size:15px;display:grid}.nav-item.router-link-active .nav-icon{background:var(--c-primary-soft)}.side-foot{color:var(--c-caption);align-items:center;gap:7px;padding:12px 8px 2px;font-size:11px;display:flex}.foot-dot{background:var(--c-ok);border-radius:50%;width:7px;height:7px;box-shadow:0 0 6px #22c55e99}.main-col{background:var(--c-surface);flex-direction:column;flex:1;min-width:0;height:100%;display:flex}.content{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.chat-view[data-v-d79f05ea]{gap:0;height:100%;display:flex}.sidebar[data-v-d79f05ea]{background:var(--c-bg);border-right:1px solid #e5e7eb;flex-direction:column;width:240px;display:flex;overflow:hidden}.sidebar h3[data-v-d79f05ea]{color:#6b7280;border-bottom:1px solid #e5e7eb;margin:0;padding:12px 16px;font-size:14px}.session-list[data-v-d79f05ea]{flex:1;margin:0;padding:8px;list-style:none;overflow-y:auto}.session-item[data-v-d79f05ea]{cursor:pointer;border-radius:6px;flex-direction:column;gap:2px;margin-bottom:4px;padding:8px 10px;font-size:13px;display:flex}.session-item[data-v-d79f05ea]:hover{background:#e5e7eb}.session-item.active[data-v-d79f05ea]{background:var(--c-primary-tint)}.s-query[data-v-d79f05ea]{color:#111}.s-status[data-v-d79f05ea]{color:#9ca3af;font-size:11px}.s-status.done[data-v-d79f05ea]{color:#16a34a}.s-status.failed[data-v-d79f05ea]{color:#dc2626}.s-status.running[data-v-d79f05ea]{color:var(--c-primary)}.main[data-v-d79f05ea]{flex-direction:column;flex:1;gap:12px;padding:20px 24px;display:flex;overflow:hidden}.empty[data-v-d79f05ea]{color:#9ca3af;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;display:flex}.hint[data-v-d79f05ea]{font-size:13px}.user-msg[data-v-d79f05ea],.assistant-msg[data-v-d79f05ea]{background:#f3f4f6;border-radius:8px;gap:12px;padding:12px 16px;font-size:14px;line-height:1.6;display:flex}.assistant-msg[data-v-d79f05ea]{background:var(--c-primary-soft)}.role-label[data-v-d79f05ea]{color:#6b7280;min-width:32px;font-size:12px;font-weight:700}.user-msg pre[data-v-d79f05ea],.assistant-msg pre[data-v-d79f05ea]{white-space:pre-wrap;margin:0;font-family:inherit}.status-bar[data-v-d79f05ea]{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.badge[data-v-d79f05ea]{border-radius:99px;padding:3px 10px;font-size:12px;font-weight:600}.badge.pending[data-v-d79f05ea]{color:#6b7280;background:#f3f4f6}.badge.running[data-v-d79f05ea]{background:var(--c-primary-tint);color:var(--c-primary)}.badge.done[data-v-d79f05ea]{color:#16a34a;background:#dcfce7}.badge.failed[data-v-d79f05ea]{color:#dc2626;background:#fee2e2}.route-path[data-v-d79f05ea]{color:#9ca3af;font-size:12px}.ws-meta[data-v-d79f05ea]{color:#9ca3af;gap:16px;font-size:12px;display:flex}.ws-preview[data-v-d79f05ea]{background:#fafafa;border:1px solid #e5e7eb;border-radius:8px;padding:12px;font-size:13px}.brief-block[data-v-d79f05ea]{margin-bottom:8px}.tags[data-v-d79f05ea]{color:#6b7280;margin-left:8px;font-size:12px}.plan-list[data-v-d79f05ea],.progress-list[data-v-d79f05ea]{margin:4px 0 0;padding:0;list-style:none}.plan-list li[data-v-d79f05ea],.progress-list li[data-v-d79f05ea]{gap:6px;padding:2px 0;display:flex}.step-id[data-v-d79f05ea]{color:#6b7280;min-width:48px;font-family:monospace}.deps[data-v-d79f05ea]{color:#9ca3af;font-size:12px}.done[data-v-d79f05ea]{color:#16a34a}.pending[data-v-d79f05ea]{color:#9ca3af}.running[data-v-d79f05ea]{color:var(--c-primary)}.error-msg[data-v-d79f05ea]{color:#dc2626;background:#fee2e2;border-radius:6px;padding:8px 12px;font-size:13px}.input-bar[data-v-d79f05ea]{border-top:1px solid #e5e7eb;gap:8px;margin-top:auto;padding-top:12px;display:flex}.input-bar input[data-v-d79f05ea]{border:1px solid #d1d5db;border-radius:8px;outline:none;flex:1;padding:10px 14px;font-size:14px}.input-bar input[data-v-d79f05ea]:focus{border-color:var(--c-primary)}.input-bar button[data-v-d79f05ea]{background:var(--c-primary);color:#fff;cursor:pointer;border:none;border-radius:8px;padding:10px 20px;font-size:14px}.input-bar button[data-v-d79f05ea]:disabled{cursor:not-allowed;background:#9ca3af}.agent-view[data-v-3723cd6f]{background:var(--c-bg);height:100%;display:flex}.sess-panel[data-v-3723cd6f]{border-right:1px solid var(--c-border-soft);background:var(--c-side-bg);flex-direction:column;flex-shrink:0;gap:10px;width:224px;padding:12px 8px;display:flex}.new-sess[data-v-3723cd6f]{border:1px solid var(--c-border);background:var(--c-surface);color:var(--c-text);cursor:pointer;border-radius:9px;padding:8px;font-size:13px;font-weight:600;transition:border-color .15s,color .15s}.new-sess[data-v-3723cd6f]:hover{border-color:var(--c-primary);color:var(--c-primary)}.sess-list[data-v-3723cd6f]{flex-direction:column;flex:1;gap:2px;display:flex;overflow-y:auto}.sess-item[data-v-3723cd6f]{cursor:pointer;border-radius:8px;padding:8px 10px;transition:background .12s}.sess-item[data-v-3723cd6f]:hover{background:var(--c-side-hover)}.sess-item.active[data-v-3723cd6f]{background:var(--c-side-active)}.sess-title[data-v-3723cd6f]{color:var(--c-text);white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:500;overflow:hidden}.sess-meta[data-v-3723cd6f]{color:var(--c-caption);align-items:center;gap:5px;margin-top:3px;font-size:11px;display:flex}.sess-del[data-v-3723cd6f]{color:var(--c-caption);opacity:0;cursor:pointer;border-radius:4px;margin-left:auto;padding:0 3px}.sess-item:hover .sess-del[data-v-3723cd6f]{opacity:1}.sess-del[data-v-3723cd6f]:hover{color:var(--c-err);background:var(--c-err-soft)}.sess-empty[data-v-3723cd6f]{color:var(--c-caption);text-align:center;padding:20px 0;font-size:12px}.chat-col[data-v-3723cd6f]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative}.hero[data-v-3723cd6f]{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:10px;padding:30px;display:flex}.hero-logo[data-v-3723cd6f]{background:linear-gradient(135deg, var(--ds-blue-400), var(--ds-blue-500));border-radius:16px;place-items:center;width:56px;height:56px;margin-bottom:4px;font-size:28px;display:grid;box-shadow:0 6px 20px #4176e659}.hero h2[data-v-3723cd6f]{font-size:20px}.hero p[data-v-3723cd6f]{color:var(--c-text-2);max-width:460px;font-size:13.5px}.hero-tips[data-v-3723cd6f]{flex-direction:column;gap:8px;width:420px;max-width:90%;margin-top:14px;display:flex}.tip-chip[data-v-3723cd6f]{border:1px solid var(--c-border);background:var(--c-surface);color:var(--c-text-2);cursor:pointer;text-align:left;border-radius:9px;padding:9px 14px;font-size:13px;transition:border-color .15s,color .15s}.tip-chip[data-v-3723cd6f]:hover{border-color:var(--c-primary);color:var(--c-primary)}.stream[data-v-3723cd6f]{flex:1;overflow-y:auto}.stream-inner[data-v-3723cd6f]{flex-direction:column;gap:14px;max-width:820px;margin:0 auto;padding:24px 20px 12px;display:flex}.row.user[data-v-3723cd6f]{justify-content:flex-end;display:flex}.bubble-user[data-v-3723cd6f]{background:var(--c-primary-soft);border:1px solid var(--c-primary-tint);color:var(--c-text);white-space:pre-wrap;word-break:break-word;border-radius:14px 14px 4px;max-width:78%;padding:10px 14px;font-size:14px}.row.assistant[data-v-3723cd6f]{display:flex}.bubble-ai[data-v-3723cd6f]{background:var(--c-surface);border:1px solid var(--c-border-soft);max-width:88%;box-shadow:var(--shadow-card);border-radius:4px 14px 14px;padding:12px 16px}.ai-text[data-v-3723cd6f]{white-space:pre-wrap;word-break:break-word;font-size:14px;line-height:1.65}.ai-error[data-v-3723cd6f]{color:var(--c-err);font-size:13px}.ai-running[data-v-3723cd6f]{color:var(--c-text-2);align-items:center;gap:8px;font-size:13px;display:flex}.spinner[data-v-3723cd6f]{border:2px solid var(--c-primary-tint);border-top-color:var(--c-primary);border-radius:50%;width:12px;height:12px;animation:.8s linear infinite spin-3723cd6f}@keyframes spin-3723cd6f{to{transform:rotate(360deg)}}.tool-fold[data-v-3723cd6f]{border:1px solid var(--c-border-soft);background:var(--ds-neutral-bluish-50);border-radius:8px;margin-bottom:10px}.tool-fold summary[data-v-3723cd6f]{cursor:pointer;color:var(--c-text-2);-webkit-user-select:none;user-select:none;padding:7px 12px;font-size:12px}.tool-fold[open] summary[data-v-3723cd6f]{border-bottom:1px solid var(--c-border-soft)}.fold-body[data-v-3723cd6f]{flex-direction:column;gap:5px;max-height:300px;padding:8px 12px;display:flex;overflow-y:auto}.mini-phase[data-v-3723cd6f]{color:var(--c-primary);background:var(--c-primary-soft);border-radius:6px;width:fit-content;margin:4px 0;padding:3px 8px;font-size:11px;font-weight:600}.mini-msg[data-v-3723cd6f]{white-space:pre-wrap;border-radius:6px;padding:6px 9px;font-size:12px}.mini-msg.mp[data-v-3723cd6f]{background:var(--c-primary-soft);color:#1e3a8a}.mini-msg.me[data-v-3723cd6f]{background:var(--c-ok-soft);color:#14532d}.mini-row[data-v-3723cd6f]{color:var(--c-text-2);font-size:12px;font-family:var(--font-mono);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.mini-row.ok[data-v-3723cd6f]{color:var(--c-ok)}.mini-row.err[data-v-3723cd6f]{color:var(--c-err)}.mini-args[data-v-3723cd6f]{color:var(--c-caption);margin-left:6px}.tool-summary[data-v-3723cd6f]{color:var(--c-caption);margin-bottom:8px;font-size:12px}.approval-card[data-v-3723cd6f]{border:1px solid var(--c-warn);background:var(--c-warn-soft);border-radius:8px;margin-bottom:10px;padding:10px 12px}.ap-head[data-v-3723cd6f]{color:var(--c-warn);margin-bottom:6px;font-size:13px;font-weight:600}.ap-args[data-v-3723cd6f]{font-size:12px;font-family:var(--font-mono);background:var(--c-surface);border:1px solid var(--c-border);white-space:pre-wrap;word-break:break-all;max-height:140px;color:var(--c-text);border-radius:6px;margin:0 0 8px;padding:6px 9px;overflow-y:auto}.ap-actions[data-v-3723cd6f]{gap:8px;display:flex}.ap-btn[data-v-3723cd6f]{cursor:pointer;color:#fff;border:none;border-radius:7px;padding:6px 16px;font-size:13px;font-weight:500}.ap-btn.reject[data-v-3723cd6f]{background:var(--c-text-2)}.ap-btn.reject[data-v-3723cd6f]:hover{background:var(--c-text)}.ap-btn.allow[data-v-3723cd6f]{background:var(--c-primary)}.ap-btn.allow[data-v-3723cd6f]:hover{background:var(--c-primary-strong)}.ap-done[data-v-3723cd6f]{margin-bottom:8px;font-size:12px;font-weight:600}.ap-done.ok[data-v-3723cd6f]{color:var(--c-ok)}.ap-done.no[data-v-3723cd6f]{color:var(--c-err)}.ai-stream[data-v-3723cd6f]{white-space:pre-wrap;word-break:break-word;color:var(--c-text);margin-bottom:6px;font-size:14px;line-height:1.65}.cursor[data-v-3723cd6f]{background:var(--c-primary);vertical-align:-2px;width:7px;height:15px;margin-left:2px;animation:.9s step-end infinite blink-3723cd6f;display:inline-block}@keyframes blink-3723cd6f{50%{opacity:0}}.delta-row[data-v-3723cd6f]{color:var(--c-caption)}.composer-wrap[data-v-3723cd6f]{padding:10px 20px 16px}.composer[data-v-3723cd6f]{background:var(--c-surface);border:1px solid var(--c-border);border-radius:14px;max-width:820px;margin:0 auto;padding:8px 10px 10px;box-shadow:0 4px 20px #10182814}.composer-bar[data-v-3723cd6f]{flex-wrap:wrap;align-items:center;gap:8px;padding:2px 4px 8px;display:flex}.chip[data-v-3723cd6f]{border:1px solid var(--c-border);background:var(--ds-neutral-bluish-50);color:var(--c-text-2);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:7px;align-items:center;gap:5px;max-width:260px;padding:3px 9px;font-size:12px;display:inline-flex;overflow:hidden}.chip[data-v-3723cd6f]:hover{border-color:var(--c-primary);color:var(--c-primary)}.select-chip[data-v-3723cd6f]{max-width:220px}.toggle-chip input[data-v-3723cd6f]{accent-color:var(--c-primary)}.composer-err[data-v-3723cd6f]{color:var(--c-err);margin-left:auto;font-size:12px}.composer-main[data-v-3723cd6f]{align-items:flex-end;gap:8px;display:flex}.composer-input[data-v-3723cd6f]{resize:none;background:0 0;border:none;outline:none;flex:1;max-height:160px;padding:6px 6px 2px;font-size:14px;line-height:1.5}.composer-input[data-v-3723cd6f]:focus-visible{box-shadow:none}.send-btn[data-v-3723cd6f]{background:var(--c-primary);color:#fff;cursor:pointer;border:none;border-radius:10px;flex-shrink:0;width:36px;height:36px;font-size:17px;transition:background .15s}.send-btn[data-v-3723cd6f]:hover:not(:disabled){background:var(--c-primary-strong)}.send-btn[data-v-3723cd6f]:disabled{background:var(--ds-neutral-bluish-200);cursor:not-allowed}.send-btn.stop[data-v-3723cd6f]{background:var(--c-err)}.modal-mask[data-v-3723cd6f]{z-index:100;background:#0f111566;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal[data-v-3723cd6f]{background:var(--c-surface);width:620px;max-width:92vw;max-height:80vh;box-shadow:var(--shadow-pop);border-radius:12px;flex-direction:column;padding:18px;display:flex}.modal-title[data-v-3723cd6f]{color:var(--c-text);margin-bottom:10px;font-size:16px;font-weight:700}.crumb[data-v-3723cd6f]{color:var(--c-text-2);background:var(--ds-neutral-bluish-50);border:1px solid var(--c-border-soft);white-space:nowrap;text-overflow:ellipsis;border-radius:6px;margin-bottom:8px;padding:6px 10px;font-size:12px;overflow:hidden}.dir-list[data-v-3723cd6f]{border:1px solid var(--c-border-soft);border-radius:6px;flex:1;min-height:200px;max-height:320px;overflow-y:auto}.dir-item[data-v-3723cd6f]{color:var(--c-text-2);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;padding:7px 12px;font-size:13px;overflow:hidden}.dir-item[data-v-3723cd6f]:hover{background:var(--c-primary-soft)}.dir-item.up[data-v-3723cd6f]{color:var(--c-primary);font-weight:500}.dir-item.empty[data-v-3723cd6f]{color:var(--c-caption);cursor:default}.dir-item.empty[data-v-3723cd6f]:hover{background:0 0}.path-row[data-v-3723cd6f]{align-items:center;gap:10px;margin-top:10px;display:flex}.path-row input[data-v-3723cd6f]:not([type]){border:1px solid var(--c-border);border-radius:6px;flex:1;padding:7px 10px;font-size:13px}.create-toggle[data-v-3723cd6f]{color:var(--c-text-2);cursor:pointer;white-space:nowrap;align-items:center;gap:5px;font-size:12px;display:flex}.recent-row[data-v-3723cd6f]{flex-wrap:wrap;align-items:center;gap:6px;margin-top:10px;display:flex}.recent-label[data-v-3723cd6f]{color:var(--c-caption);font-size:12px}.recent-chip[data-v-3723cd6f]{border:1px solid var(--c-border);background:var(--ds-neutral-bluish-50);color:var(--c-text-2);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:12px;max-width:180px;padding:2px 10px;font-size:12px;overflow:hidden}.recent-chip[data-v-3723cd6f]:hover{background:var(--c-primary-soft);border-color:var(--c-primary-tint)}.picker-msg[data-v-3723cd6f]{color:var(--c-warn);margin-top:8px;font-size:12px}.modal-actions[data-v-3723cd6f]{gap:10px;margin-top:14px;display:flex}.btn-primary[data-v-3723cd6f]{color:#fff;background:var(--c-primary);cursor:pointer;border:none;border-radius:8px;padding:8px 18px;font-size:13px;font-weight:500}.btn-primary[data-v-3723cd6f]:hover{background:var(--c-primary-strong)}.btn-secondary[data-v-3723cd6f]{color:var(--c-text-2);background:var(--c-surface);border:1px solid var(--c-border);cursor:pointer;border-radius:8px;padding:8px 18px;font-size:13px}:root{--ds-blue-50:#edf3fe;--ds-blue-100:#e4edfd;--ds-blue-300:#b7c8fe;--ds-blue-400:#6786fe;--ds-blue-500:#4176e6;--ds-neutral-bluish-00:#fff;--ds-neutral-bluish-50:#f9fafb;--ds-neutral-bluish-60:#f5f6f7;--ds-neutral-bluish-75:#f1f3f5;--ds-neutral-bluish-100:#ebeef2;--ds-neutral-bluish-200:#e1e5ee;--ds-neutral-bluish-400:#adb2b8;--ds-neutral-bluish-600:#818588;--ds-neutral-bluish-700:#61666b;--ds-neutral-bluish-1000:#0f1115;--c-bg:var(--ds-neutral-bluish-60);--c-surface:#fff;--c-border:#10141a1a;--c-border-soft:#10141a0d;--c-text:var(--ds-neutral-bluish-1000);--c-text-2:var(--ds-neutral-bluish-700);--c-text-3:var(--ds-neutral-bluish-600);--c-caption:var(--ds-neutral-bluish-400);--c-primary:var(--ds-blue-500);--c-primary-strong:var(--ds-blue-400);--c-primary-soft:var(--ds-blue-50);--c-primary-tint:var(--ds-blue-100);--c-primary-ring:#4176e633;--c-hover:#2631480f;--c-ok:#22c55e;--c-ok-soft:#e6faed;--c-warn:#dd8629;--c-warn-soft:#fef5e7;--c-err:#ec1313;--c-err-soft:#fef2f2;--c-side-bg:var(--ds-neutral-bluish-50);--c-side-text:var(--ds-neutral-bluish-700);--c-side-text-active:var(--ds-neutral-bluish-1000);--c-side-active:var(--ds-neutral-bluish-100);--c-side-hover:var(--ds-neutral-bluish-75);--c-side-border:var(--c-border-soft);--c-accent:var(--ds-blue-500);--radius:10px;--radius-sm:7px;--shadow-card:0 1px 2px #10182808;--shadow-pop:0 8px 30px #1018281f;--font-mono:"SF Mono", "JetBrains Mono", "Fira Code", Consolas, "Liberation Mono", Menlo, Courier, "PingFang SC", "Microsoft YaHei", monospace;--ds-ease:cubic-bezier(.4, 0, .2, 1)}*{box-sizing:border-box;margin:0;padding:0}html,body,#app{height:100%;color:var(--c-text);background:var(--c-bg);-webkit-font-smoothing:antialiased;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Roboto,sans-serif;font-size:14px}::-webkit-scrollbar{width:9px;height:9px}::-webkit-scrollbar-thumb{background:#e5e5e5 padding-box content-box;border:2px solid #0000;border-radius:8px}::-webkit-scrollbar-thumb:hover{background-color:#d4d4d4}::-webkit-scrollbar-track{background:0 0}button,input,select,textarea{color:inherit;font-family:inherit}h2{letter-spacing:.2px;color:var(--c-text);font-size:19px;font-weight:700}a{color:var(--c-primary)}code,pre{font-family:var(--font-mono)}input:focus-visible,select:focus-visible,textarea:focus-visible,button:focus-visible{box-shadow:0 0 0 3px var(--c-primary-ring);outline:none}.surface{background:var(--c-surface);border:1px solid var(--c-border-soft);border-radius:var(--radius);box-shadow:var(--shadow-card)}.settings-section,.metric-card,.ev-card{box-shadow:var(--shadow-card);border-radius:var(--radius)}.page-head h2{align-items:center;gap:8px;display:flex}.page-head .sub{margin-top:3px}.mono{font-family:var(--font-mono)}@media (prefers-reduced-motion:no-preference){.ev-card,.metric-card,.settings-section{animation:fade-up .2s var(--ds-ease) both}}@keyframes fade-up{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}} +.app{height:100%;display:flex}.side{background:var(--c-side-bg);border-right:1px solid var(--c-side-border);width:208px;color:var(--c-side-text);-webkit-user-select:none;user-select:none;flex-direction:column;flex-shrink:0;padding:18px 12px 14px;display:flex}.brand{align-items:center;gap:10px;margin-bottom:12px;padding:4px 8px 16px;display:flex}.brand-logo{background:linear-gradient(135deg, var(--ds-blue-400), var(--ds-blue-500));border-radius:11px;place-items:center;width:38px;height:38px;font-size:20px;display:grid;box-shadow:0 3px 10px #4176e659}.brand-text{flex-direction:column;line-height:1.3;display:flex}.brand-text b{color:var(--c-text);letter-spacing:.5px;font-size:15px}.brand-text span{color:var(--c-caption);font-size:11px}.nav{flex-direction:column;flex:1;gap:2px;display:flex}.nav-item{color:var(--c-side-text);transition:background .15s var(--ds-ease), color .15s var(--ds-ease);border-radius:9px;align-items:center;gap:11px;padding:8px 10px;font-size:13.5px;font-weight:500;text-decoration:none;display:flex;position:relative}.nav-item:hover{background:var(--c-side-hover);color:var(--c-text)}.nav-item.router-link-active{background:var(--c-side-active);color:var(--c-side-text-active);font-weight:600}.nav-item.router-link-active:before{content:"";background:var(--c-accent);border-radius:0 3px 3px 0;width:3px;position:absolute;top:7px;bottom:7px;left:-12px}.nav-icon{background:var(--c-hover);border-radius:7px;place-items:center;width:26px;height:26px;font-size:15px;display:grid}.nav-item.router-link-active .nav-icon{background:var(--c-primary-soft)}.side-foot{color:var(--c-caption);align-items:center;gap:7px;padding:12px 8px 2px;font-size:11px;display:flex}.foot-dot{background:var(--c-ok);border-radius:50%;width:7px;height:7px;box-shadow:0 0 6px #22c55e99}.main-col{background:var(--c-surface);flex-direction:column;flex:1;min-width:0;height:100%;display:flex}.content{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.chat-view[data-v-d79f05ea]{gap:0;height:100%;display:flex}.sidebar[data-v-d79f05ea]{background:var(--c-bg);border-right:1px solid #e5e7eb;flex-direction:column;width:240px;display:flex;overflow:hidden}.sidebar h3[data-v-d79f05ea]{color:#6b7280;border-bottom:1px solid #e5e7eb;margin:0;padding:12px 16px;font-size:14px}.session-list[data-v-d79f05ea]{flex:1;margin:0;padding:8px;list-style:none;overflow-y:auto}.session-item[data-v-d79f05ea]{cursor:pointer;border-radius:6px;flex-direction:column;gap:2px;margin-bottom:4px;padding:8px 10px;font-size:13px;display:flex}.session-item[data-v-d79f05ea]:hover{background:#e5e7eb}.session-item.active[data-v-d79f05ea]{background:var(--c-primary-tint)}.s-query[data-v-d79f05ea]{color:#111}.s-status[data-v-d79f05ea]{color:#9ca3af;font-size:11px}.s-status.done[data-v-d79f05ea]{color:#16a34a}.s-status.failed[data-v-d79f05ea]{color:#dc2626}.s-status.running[data-v-d79f05ea]{color:var(--c-primary)}.main[data-v-d79f05ea]{flex-direction:column;flex:1;gap:12px;padding:20px 24px;display:flex;overflow:hidden}.empty[data-v-d79f05ea]{color:#9ca3af;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;display:flex}.hint[data-v-d79f05ea]{font-size:13px}.user-msg[data-v-d79f05ea],.assistant-msg[data-v-d79f05ea]{background:#f3f4f6;border-radius:8px;gap:12px;padding:12px 16px;font-size:14px;line-height:1.6;display:flex}.assistant-msg[data-v-d79f05ea]{background:var(--c-primary-soft)}.role-label[data-v-d79f05ea]{color:#6b7280;min-width:32px;font-size:12px;font-weight:700}.user-msg pre[data-v-d79f05ea],.assistant-msg pre[data-v-d79f05ea]{white-space:pre-wrap;margin:0;font-family:inherit}.status-bar[data-v-d79f05ea]{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.badge[data-v-d79f05ea]{border-radius:99px;padding:3px 10px;font-size:12px;font-weight:600}.badge.pending[data-v-d79f05ea]{color:#6b7280;background:#f3f4f6}.badge.running[data-v-d79f05ea]{background:var(--c-primary-tint);color:var(--c-primary)}.badge.done[data-v-d79f05ea]{color:#16a34a;background:#dcfce7}.badge.failed[data-v-d79f05ea]{color:#dc2626;background:#fee2e2}.route-path[data-v-d79f05ea]{color:#9ca3af;font-size:12px}.ws-meta[data-v-d79f05ea]{color:#9ca3af;gap:16px;font-size:12px;display:flex}.ws-preview[data-v-d79f05ea]{background:#fafafa;border:1px solid #e5e7eb;border-radius:8px;padding:12px;font-size:13px}.brief-block[data-v-d79f05ea]{margin-bottom:8px}.tags[data-v-d79f05ea]{color:#6b7280;margin-left:8px;font-size:12px}.plan-list[data-v-d79f05ea],.progress-list[data-v-d79f05ea]{margin:4px 0 0;padding:0;list-style:none}.plan-list li[data-v-d79f05ea],.progress-list li[data-v-d79f05ea]{gap:6px;padding:2px 0;display:flex}.step-id[data-v-d79f05ea]{color:#6b7280;min-width:48px;font-family:monospace}.deps[data-v-d79f05ea]{color:#9ca3af;font-size:12px}.done[data-v-d79f05ea]{color:#16a34a}.pending[data-v-d79f05ea]{color:#9ca3af}.running[data-v-d79f05ea]{color:var(--c-primary)}.error-msg[data-v-d79f05ea]{color:#dc2626;background:#fee2e2;border-radius:6px;padding:8px 12px;font-size:13px}.input-bar[data-v-d79f05ea]{border-top:1px solid #e5e7eb;gap:8px;margin-top:auto;padding-top:12px;display:flex}.input-bar input[data-v-d79f05ea]{border:1px solid #d1d5db;border-radius:8px;outline:none;flex:1;padding:10px 14px;font-size:14px}.input-bar input[data-v-d79f05ea]:focus{border-color:var(--c-primary)}.input-bar button[data-v-d79f05ea]{background:var(--c-primary);color:#fff;cursor:pointer;border:none;border-radius:8px;padding:10px 20px;font-size:14px}.input-bar button[data-v-d79f05ea]:disabled{cursor:not-allowed;background:#9ca3af}.agent-view[data-v-f544df91]{background:var(--c-bg);height:100%;display:flex}.sess-panel[data-v-f544df91]{border-right:1px solid var(--c-border-soft);background:var(--c-side-bg);flex-direction:column;flex-shrink:0;gap:10px;width:224px;padding:12px 8px;display:flex}.new-sess[data-v-f544df91]{border:1px solid var(--c-border);background:var(--c-surface);color:var(--c-text);cursor:pointer;border-radius:9px;padding:8px;font-size:13px;font-weight:600;transition:border-color .15s,color .15s}.new-sess[data-v-f544df91]:hover{border-color:var(--c-primary);color:var(--c-primary)}.sess-list[data-v-f544df91]{flex-direction:column;flex:1;gap:2px;display:flex;overflow-y:auto}.sess-item[data-v-f544df91]{cursor:pointer;border-radius:8px;padding:8px 10px;transition:background .12s}.sess-item[data-v-f544df91]:hover{background:var(--c-side-hover)}.sess-item.active[data-v-f544df91]{background:var(--c-side-active)}.sess-title[data-v-f544df91]{color:var(--c-text);white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:500;overflow:hidden}.sess-meta[data-v-f544df91]{color:var(--c-caption);align-items:center;gap:5px;margin-top:3px;font-size:11px;display:flex}.sess-del[data-v-f544df91]{color:var(--c-caption);opacity:0;cursor:pointer;border-radius:4px;margin-left:auto;padding:0 3px}.sess-item:hover .sess-del[data-v-f544df91]{opacity:1}.sess-del[data-v-f544df91]:hover{color:var(--c-err);background:var(--c-err-soft)}.sess-empty[data-v-f544df91]{color:var(--c-caption);text-align:center;padding:20px 0;font-size:12px}.chat-col[data-v-f544df91]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative}.hero[data-v-f544df91]{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:10px;padding:30px;display:flex}.hero-logo[data-v-f544df91]{background:linear-gradient(135deg, var(--ds-blue-400), var(--ds-blue-500));border-radius:16px;place-items:center;width:56px;height:56px;margin-bottom:4px;font-size:28px;display:grid;box-shadow:0 6px 20px #4176e659}.hero h2[data-v-f544df91]{font-size:20px}.hero p[data-v-f544df91]{color:var(--c-text-2);max-width:460px;font-size:13.5px}.hero-tips[data-v-f544df91]{flex-direction:column;gap:8px;width:420px;max-width:90%;margin-top:14px;display:flex}.tip-chip[data-v-f544df91]{border:1px solid var(--c-border);background:var(--c-surface);color:var(--c-text-2);cursor:pointer;text-align:left;border-radius:9px;padding:9px 14px;font-size:13px;transition:border-color .15s,color .15s}.tip-chip[data-v-f544df91]:hover{border-color:var(--c-primary);color:var(--c-primary)}.stream[data-v-f544df91]{flex:1;overflow-y:auto}.stream-inner[data-v-f544df91]{flex-direction:column;gap:14px;max-width:820px;margin:0 auto;padding:24px 20px 12px;display:flex}.row.user[data-v-f544df91]{justify-content:flex-end;display:flex}.bubble-user[data-v-f544df91]{background:var(--c-primary-soft);border:1px solid var(--c-primary-tint);color:var(--c-text);white-space:pre-wrap;word-break:break-word;border-radius:14px 14px 4px;max-width:78%;padding:10px 14px;font-size:14px}.row.assistant[data-v-f544df91]{display:flex}.bubble-ai[data-v-f544df91]{background:var(--c-surface);border:1px solid var(--c-border-soft);max-width:88%;box-shadow:var(--shadow-card);border-radius:4px 14px 14px;padding:12px 16px}.ai-text[data-v-f544df91]{white-space:pre-wrap;word-break:break-word;font-size:14px;line-height:1.65}.ai-error[data-v-f544df91]{color:var(--c-err);font-size:13px}.ai-running[data-v-f544df91]{color:var(--c-text-2);align-items:center;gap:8px;font-size:13px;display:flex}.spinner[data-v-f544df91]{border:2px solid var(--c-primary-tint);border-top-color:var(--c-primary);border-radius:50%;width:12px;height:12px;animation:.8s linear infinite spin-f544df91}@keyframes spin-f544df91{to{transform:rotate(360deg)}}.tool-fold[data-v-f544df91]{border:1px solid var(--c-border-soft);background:var(--ds-neutral-bluish-50);border-radius:8px;margin-bottom:10px}.tool-fold summary[data-v-f544df91]{cursor:pointer;color:var(--c-text-2);-webkit-user-select:none;user-select:none;padding:7px 12px;font-size:12px}.tool-fold[open] summary[data-v-f544df91]{border-bottom:1px solid var(--c-border-soft)}.fold-body[data-v-f544df91]{flex-direction:column;gap:5px;max-height:300px;padding:8px 12px;display:flex;overflow-y:auto}.mini-phase[data-v-f544df91]{color:var(--c-primary);background:var(--c-primary-soft);border-radius:6px;width:fit-content;margin:4px 0;padding:3px 8px;font-size:11px;font-weight:600}.mini-msg[data-v-f544df91]{white-space:pre-wrap;border-radius:6px;padding:6px 9px;font-size:12px}.mini-msg.mp[data-v-f544df91]{background:var(--c-primary-soft);color:#1e3a8a}.mini-msg.me[data-v-f544df91]{background:var(--c-ok-soft);color:#14532d}.mini-row[data-v-f544df91]{color:var(--c-text-2);font-size:12px;font-family:var(--font-mono);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.mini-row.ok[data-v-f544df91]{color:var(--c-ok)}.mini-row.err[data-v-f544df91]{color:var(--c-err)}.mini-args[data-v-f544df91]{color:var(--c-caption);margin-left:6px}.tool-summary[data-v-f544df91]{color:var(--c-caption);margin-bottom:8px;font-size:12px}.approval-card[data-v-f544df91]{border:1px solid var(--c-warn);background:var(--c-warn-soft);border-radius:8px;margin-bottom:10px;padding:10px 12px}.ap-head[data-v-f544df91]{color:var(--c-warn);margin-bottom:6px;font-size:13px;font-weight:600}.ap-args[data-v-f544df91]{font-size:12px;font-family:var(--font-mono);background:var(--c-surface);border:1px solid var(--c-border);white-space:pre-wrap;word-break:break-all;max-height:140px;color:var(--c-text);border-radius:6px;margin:0 0 8px;padding:6px 9px;overflow-y:auto}.ap-actions[data-v-f544df91]{gap:8px;display:flex}.ap-btn[data-v-f544df91]{cursor:pointer;color:#fff;border:none;border-radius:7px;padding:6px 16px;font-size:13px;font-weight:500}.ap-btn.reject[data-v-f544df91]{background:var(--c-text-2)}.ap-btn.reject[data-v-f544df91]:hover{background:var(--c-text)}.ap-btn.allow[data-v-f544df91]{background:var(--c-primary)}.ap-btn.allow[data-v-f544df91]:hover{background:var(--c-primary-strong)}.ap-done[data-v-f544df91]{margin-bottom:8px;font-size:12px;font-weight:600}.ap-done.ok[data-v-f544df91]{color:var(--c-ok)}.ap-done.no[data-v-f544df91]{color:var(--c-err)}.ai-stream[data-v-f544df91]{white-space:pre-wrap;word-break:break-word;color:var(--c-text);margin-bottom:6px;font-size:14px;line-height:1.65}.cursor[data-v-f544df91]{background:var(--c-primary);vertical-align:-2px;width:7px;height:15px;margin-left:2px;animation:.9s step-end infinite blink-f544df91;display:inline-block}@keyframes blink-f544df91{50%{opacity:0}}.delta-row[data-v-f544df91]{color:var(--c-caption)}.composer-wrap[data-v-f544df91]{padding:10px 20px 16px}.composer[data-v-f544df91]{background:var(--c-surface);border:1px solid var(--c-border);border-radius:14px;max-width:820px;margin:0 auto;padding:8px 10px 10px;box-shadow:0 4px 20px #10182814}.composer-bar[data-v-f544df91]{flex-wrap:wrap;align-items:center;gap:8px;padding:2px 4px 8px;display:flex}.chip[data-v-f544df91]{border:1px solid var(--c-border);background:var(--ds-neutral-bluish-50);color:var(--c-text-2);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:7px;align-items:center;gap:5px;max-width:260px;padding:3px 9px;font-size:12px;display:inline-flex;overflow:hidden}.chip[data-v-f544df91]:hover{border-color:var(--c-primary);color:var(--c-primary)}.select-chip[data-v-f544df91]{max-width:220px}.toggle-chip input[data-v-f544df91]{accent-color:var(--c-primary)}.composer-err[data-v-f544df91]{color:var(--c-err);margin-left:auto;font-size:12px}.composer-main[data-v-f544df91]{align-items:flex-end;gap:8px;display:flex}.composer-input[data-v-f544df91]{resize:none;background:0 0;border:none;outline:none;flex:1;max-height:160px;padding:6px 6px 2px;font-size:14px;line-height:1.5}.composer-input[data-v-f544df91]:focus-visible{box-shadow:none}.send-btn[data-v-f544df91]{background:var(--c-primary);color:#fff;cursor:pointer;border:none;border-radius:10px;flex-shrink:0;width:36px;height:36px;font-size:17px;transition:background .15s}.send-btn[data-v-f544df91]:hover:not(:disabled){background:var(--c-primary-strong)}.send-btn[data-v-f544df91]:disabled{background:var(--ds-neutral-bluish-200);cursor:not-allowed}.send-btn.stop[data-v-f544df91]{background:var(--c-err)}.modal-mask[data-v-f544df91]{z-index:100;background:#0f111566;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal[data-v-f544df91]{background:var(--c-surface);width:620px;max-width:92vw;max-height:80vh;box-shadow:var(--shadow-pop);border-radius:12px;flex-direction:column;padding:18px;display:flex}.modal-title[data-v-f544df91]{color:var(--c-text);margin-bottom:10px;font-size:16px;font-weight:700}.crumb[data-v-f544df91]{color:var(--c-text-2);background:var(--ds-neutral-bluish-50);border:1px solid var(--c-border-soft);white-space:nowrap;text-overflow:ellipsis;border-radius:6px;margin-bottom:8px;padding:6px 10px;font-size:12px;overflow:hidden}.dir-list[data-v-f544df91]{border:1px solid var(--c-border-soft);border-radius:6px;flex:1;min-height:200px;max-height:320px;overflow-y:auto}.dir-item[data-v-f544df91]{color:var(--c-text-2);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;padding:7px 12px;font-size:13px;overflow:hidden}.dir-item[data-v-f544df91]:hover{background:var(--c-primary-soft)}.dir-item.up[data-v-f544df91]{color:var(--c-primary);font-weight:500}.dir-item.empty[data-v-f544df91]{color:var(--c-caption);cursor:default}.dir-item.empty[data-v-f544df91]:hover{background:0 0}.path-row[data-v-f544df91]{align-items:center;gap:10px;margin-top:10px;display:flex}.path-row input[data-v-f544df91]:not([type]){border:1px solid var(--c-border);border-radius:6px;flex:1;padding:7px 10px;font-size:13px}.create-toggle[data-v-f544df91]{color:var(--c-text-2);cursor:pointer;white-space:nowrap;align-items:center;gap:5px;font-size:12px;display:flex}.recent-row[data-v-f544df91]{flex-wrap:wrap;align-items:center;gap:6px;margin-top:10px;display:flex}.recent-label[data-v-f544df91]{color:var(--c-caption);font-size:12px}.recent-chip[data-v-f544df91]{border:1px solid var(--c-border);background:var(--ds-neutral-bluish-50);color:var(--c-text-2);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:12px;max-width:180px;padding:2px 10px;font-size:12px;overflow:hidden}.recent-chip[data-v-f544df91]:hover{background:var(--c-primary-soft);border-color:var(--c-primary-tint)}.picker-msg[data-v-f544df91]{color:var(--c-warn);margin-top:8px;font-size:12px}.modal-actions[data-v-f544df91]{gap:10px;margin-top:14px;display:flex}.btn-primary[data-v-f544df91]{color:#fff;background:var(--c-primary);cursor:pointer;border:none;border-radius:8px;padding:8px 18px;font-size:13px;font-weight:500}.btn-primary[data-v-f544df91]:hover{background:var(--c-primary-strong)}.btn-secondary[data-v-f544df91]{color:var(--c-text-2);background:var(--c-surface);border:1px solid var(--c-border);cursor:pointer;border-radius:8px;padding:8px 18px;font-size:13px}:root{--ds-blue-50:#edf3fe;--ds-blue-100:#e4edfd;--ds-blue-300:#b7c8fe;--ds-blue-400:#6786fe;--ds-blue-500:#4176e6;--ds-neutral-bluish-00:#fff;--ds-neutral-bluish-50:#f9fafb;--ds-neutral-bluish-60:#f5f6f7;--ds-neutral-bluish-75:#f1f3f5;--ds-neutral-bluish-100:#ebeef2;--ds-neutral-bluish-200:#e1e5ee;--ds-neutral-bluish-400:#adb2b8;--ds-neutral-bluish-600:#818588;--ds-neutral-bluish-700:#61666b;--ds-neutral-bluish-1000:#0f1115;--c-bg:var(--ds-neutral-bluish-60);--c-surface:#fff;--c-border:#10141a1a;--c-border-soft:#10141a0d;--c-text:var(--ds-neutral-bluish-1000);--c-text-2:var(--ds-neutral-bluish-700);--c-text-3:var(--ds-neutral-bluish-600);--c-caption:var(--ds-neutral-bluish-400);--c-primary:var(--ds-blue-500);--c-primary-strong:var(--ds-blue-400);--c-primary-soft:var(--ds-blue-50);--c-primary-tint:var(--ds-blue-100);--c-primary-ring:#4176e633;--c-hover:#2631480f;--c-ok:#22c55e;--c-ok-soft:#e6faed;--c-warn:#dd8629;--c-warn-soft:#fef5e7;--c-err:#ec1313;--c-err-soft:#fef2f2;--c-side-bg:var(--ds-neutral-bluish-50);--c-side-text:var(--ds-neutral-bluish-700);--c-side-text-active:var(--ds-neutral-bluish-1000);--c-side-active:var(--ds-neutral-bluish-100);--c-side-hover:var(--ds-neutral-bluish-75);--c-side-border:var(--c-border-soft);--c-accent:var(--ds-blue-500);--radius:10px;--radius-sm:7px;--shadow-card:0 1px 2px #10182808;--shadow-pop:0 8px 30px #1018281f;--font-mono:"SF Mono", "JetBrains Mono", "Fira Code", Consolas, "Liberation Mono", Menlo, Courier, "PingFang SC", "Microsoft YaHei", monospace;--ds-ease:cubic-bezier(.4, 0, .2, 1)}*{box-sizing:border-box;margin:0;padding:0}html,body,#app{height:100%;color:var(--c-text);background:var(--c-bg);-webkit-font-smoothing:antialiased;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Roboto,sans-serif;font-size:14px}::-webkit-scrollbar{width:9px;height:9px}::-webkit-scrollbar-thumb{background:#e5e5e5 padding-box content-box;border:2px solid #0000;border-radius:8px}::-webkit-scrollbar-thumb:hover{background-color:#d4d4d4}::-webkit-scrollbar-track{background:0 0}button,input,select,textarea{color:inherit;font-family:inherit}h2{letter-spacing:.2px;color:var(--c-text);font-size:19px;font-weight:700}a{color:var(--c-primary)}code,pre{font-family:var(--font-mono)}input:focus-visible,select:focus-visible,textarea:focus-visible,button:focus-visible{box-shadow:0 0 0 3px var(--c-primary-ring);outline:none}.surface{background:var(--c-surface);border:1px solid var(--c-border-soft);border-radius:var(--radius);box-shadow:var(--shadow-card)}.settings-section,.metric-card,.ev-card{box-shadow:var(--shadow-card);border-radius:var(--radius)}.page-head h2{align-items:center;gap:8px;display:flex}.page-head .sub{margin-top:3px}.mono{font-family:var(--font-mono)}@media (prefers-reduced-motion:no-preference){.ev-card,.metric-card,.settings-section{animation:fade-up .2s var(--ds-ease) both}}@keyframes fade-up{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}} diff --git a/gateway/static/index.html b/gateway/static/index.html index 44386f3..6f73562 100644 --- a/gateway/static/index.html +++ b/gateway/static/index.html @@ -5,8 +5,8 @@ 端云协同 LLM 协作系统 - - + +
diff --git a/router_system/tools.py b/router_system/tools.py index 2ba552d..ffc67e9 100644 --- a/router_system/tools.py +++ b/router_system/tools.py @@ -1,8 +1,10 @@ """工具调用内核 —— 让 LLM 以 OpenAI function-calling 协议操作工作区文件。 组成(对齐《实现方案_v4_模型池与工具智能体.md》D4): -- TOOLS_SPEC:list_dir / read_file / write_file 三个工具的 OpenAI tools 声明 -- WorkspaceTools:被"关押"在根目录内的文件工具(路径越界一律拒绝,Windows pathlib) +- TOOLS_SPEC:list_dir / read_file / write_file / edit_file / search_files / + run_command / web_fetch 七个工具的 OpenAI tools 声明 +- WorkspaceTools:被"关押"在根目录内的文件工具(路径越界一律拒绝,Windows pathlib); + web_fetch 带公网 SSRF 防护(dsh web_fetch 同款),run_command 带危险命令拦截 - parse_tool_calls:解析 OpenAI 响应里的 tool_calls(arguments 容错为 {}) - ToolLoop:通用智能体循环。chat_fn 注入(网关传 OpenAI 兼容客户端,测试传假实现), 本模块只负责循环编排:调用 -> 执行工具 -> 回喂结果 -> 直到模型给出最终答复。 @@ -11,9 +13,13 @@ - 纯标准库(router_system 零第三方依赖不变) - 工具结果回喂前截断(防止上下文爆炸),轮数与 token 双上限(金额护栏) - 事件回调 on_event 逐条产出过程事件(供 SSE 透出"智能体在做什么") +- 工具在线程池执行(asyncio.to_thread),长命令/大搜索不阻塞事件循环 +- 重复同参调用达到阈值回喂警语(防模型原地打转,dsh repeat-reminder 同款) """ from __future__ import annotations +import asyncio +import ipaddress import json from pathlib import Path from typing import Any, Awaitable, Callable, Dict, List, Optional @@ -33,6 +39,17 @@ SEARCH_SKIP_DIRS = {".git", "node_modules", "__pycache__", ".venv", "venv", "dis # run_command 上限 SHELL_OUTPUT_CHARS = 4000 +# web_fetch 上限(SSRF 防护:仅公网 http/https,拒绝私网/环回/链路本地地址) +FETCH_MAX_CHARS = 12000 +FETCH_TIMEOUT_S = 15.0 +FETCH_MAX_BYTES = 512 * 1024 +FETCH_ALLOWED_SCHEMES = ("http", "https") +# NAT64 Well-Known Prefix(dsh 同款拒绝项) +_NAT64_PREFIX = ipaddress.ip_network("64:ff9b::/96") + +# 重复调用提醒阈值(同一工具 + 同一参数第 N 次起提示模型换策略) +REPEAT_CALL_WARN_AT = 3 + # 默认循环上限 DEFAULT_MAX_ROUNDS = 8 @@ -128,6 +145,21 @@ TOOLS_SPEC: List[Dict[str, Any]] = [ }, }, }, + { + "type": "function", + "function": { + "name": "web_fetch", + "description": "抓取一个公网 http/https URL 的文本内容(如查文档/接口说明)," + "返回截断后的正文。私网/环回地址会被拒绝;仅当系统开启 allow_net 时可用。", + "parameters": { + "type": "object", + "properties": { + "url": {"type": "string", "description": "要抓取的完整 URL(http/https)"}, + }, + "required": ["url"], + }, + }, + }, ] TOOL_NAMES = {t["function"]["name"] for t in TOOLS_SPEC} @@ -167,6 +199,71 @@ class ToolError(Exception): """工具执行失败(路径越界/不存在/参数非法)。""" +def _atomic_write_text(p: Path, text: str) -> None: + """原子写文本:同目录临时文件 + os.replace(防半截文件;dsh atomic-write 同款)。 + + Windows 上目标被占用时 os.replace 可能 EPERM:小退避重试一次, + 仍失败则退回直接写(保可用性,牺牲原子性)。 + """ + import os + import tempfile + import time + tmp = None + try: + with tempfile.NamedTemporaryFile( + "w", encoding="utf-8", dir=str(p.parent), + prefix=p.name + ".", suffix=".tmp", delete=False) as f: + tmp = Path(f.name) + f.write(text) + for attempt in (0, 1): + try: + os.replace(tmp, p) + return + except PermissionError: + if attempt == 0: + time.sleep(0.05) + raise + except PermissionError: + if tmp is not None: + tmp.unlink(missing_ok=True) + p.write_text(text, encoding="utf-8") # 退路:非原子但保可用 + except BaseException: + if tmp is not None: + tmp.unlink(missing_ok=True) + raise + + +# 危险命令模式(大小写不敏感):宁可误拦不可漏拦(用户可换写法绕开误拦项) +_DANGEROUS_PATTERNS = [ + (r"\bformat\b\s+[a-z]:", "格式化磁盘"), + (r"\brd\s+/s", "递归删除目录"), + (r"\brmdir\s+/s", "递归删除目录"), + (r"\bdel\s+/[fsmq]", "强制/递归删除"), + (r"\brm\s+(-[a-z]*r[a-z]*f|-[a-z]*f[a-z]*r)\s+[/~]", "递归强制删除根/家目录"), + (r"\bshutdown\b", "关机/重启"), + (r"\bdiskpart\b", "磁盘分区操作"), + (r"\bbcdedit\b", "启动配置修改"), + (r"\breg\s+delete\b", "注册表删除"), + (r"\bvssadmin\s+delete\b", "卷影副本删除"), + (r"\bmkfs\b", "格式化文件系统"), + (r"\bdd\s+if=", "裸磁盘写入"), + (r":\(\)\s*\{.*\};\s*:", "fork 炸弹"), + (r"\bcurl\b[^|]*\|\s*(ba)?sh\b", "下载并执行脚本"), + (r"\bwget\b[^|]*\|\s*(ba)?sh\b", "下载并执行脚本"), + (r"\biwr\b[^|]*\|\s*iex\b", "下载并执行脚本"), +] + + +def _dangerous_command_reason(command: str) -> str: + """命中危险命令模式时返回原因,否则返回空串(审批之外的独立防线)。""" + import re + lowered = command.lower() + for pattern, reason in _DANGEROUS_PATTERNS: + if re.search(pattern, lowered): + return reason + return "" + + class WorkspaceTools: """被限制在根目录内的文件工具(智能体的"手")。 @@ -175,11 +272,13 @@ class WorkspaceTools: """ def __init__(self, root: str | Path, - allow_shell: bool = False, shell_timeout_s: int = 20): + allow_shell: bool = False, shell_timeout_s: int = 20, + allow_net: bool = True): self.root = Path(root).resolve() self.root.mkdir(parents=True, exist_ok=True) self.allow_shell = bool(allow_shell) self.shell_timeout_s = max(1, int(shell_timeout_s)) + self.allow_net = bool(allow_net) # ---------- 路径关押 ---------- def resolve(self, rel_path: str) -> Path: @@ -234,7 +333,7 @@ class WorkspaceTools: return {"ok": False, "error": f"内容过长(>{MAX_WRITE_CHARS} 字符),拒绝写入"} p = self.resolve(rel_path) p.parent.mkdir(parents=True, exist_ok=True) - p.write_text(content, encoding="utf-8") + _atomic_write_text(p, content) return {"ok": True, "path": rel_path, "bytes_written": len(content.encode("utf-8"))} def edit_file(self, rel_path: str, old_string: str, new_string: str) -> Dict[str, Any]: @@ -257,7 +356,7 @@ class WorkspaceTools: return {"ok": False, "error": f"old_string 出现 {count} 次(要求唯一);请扩大上下文使其唯一"} new_text = text.replace(old_string, new_string, 1) - p.write_text(new_text, encoding="utf-8") + _atomic_write_text(p, new_text) return { "ok": True, "path": rel_path, "replaced": 1, @@ -265,7 +364,8 @@ class WorkspaceTools: } def search_files(self, query: str, rel_path: str = "") -> Dict[str, Any]: - """跨文件文本搜索(跳过依赖/构建目录与二进制大文件,限量返回)。""" + """跨文件文本搜索(os.walk 修剪依赖/构建目录,限量返回,不跟随符号链接)。""" + import os if not query: return {"ok": False, "error": "query 不能为空"} base = self.resolve(rel_path or "") @@ -274,40 +374,61 @@ class WorkspaceTools: matches: List[Dict[str, Any]] = [] scanned = 0 truncated = False - for p in sorted(base.rglob("*")): - if len(matches) >= SEARCH_MAX_MATCHES: - truncated = True - break - if not p.is_file(): - continue - rel_parts = p.relative_to(base).parts - if any(part in SEARCH_SKIP_DIRS for part in rel_parts): - continue - try: - if p.stat().st_size > SEARCH_MAX_FILE_BYTES: - continue - text = p.read_text(encoding="utf-8") - except (OSError, UnicodeDecodeError): - continue # 二进制/不可读,跳过 - scanned += 1 - if scanned > SEARCH_MAX_FILES: - truncated = True - break - for lineno, line in enumerate(text.splitlines(), 1): + + def _match_file(p: Path) -> bool: + """在单文件内找匹配(找到即 True)。""" + nonlocal matches, truncated + for lineno, line in enumerate(p.read_text(encoding="utf-8").splitlines(), 1): if query in line: - rel = Path(*p.relative_to(self.root).parts).as_posix() + rel = p.relative_to(self.root).as_posix() matches.append({ "file": rel, "line": lineno, "text": line.strip()[:300], }) if len(matches) >= SEARCH_MAX_MATCHES: + truncated = True + return True + return False + + for dirpath, dirnames, filenames in os.walk(base, followlinks=False): + # 修剪依赖/构建目录:不进入(rglob 全量物化在大工作区上不可接受) + dirnames[:] = sorted((d for d in dirnames if d not in SEARCH_SKIP_DIRS), + key=str.lower) + if len(matches) >= SEARCH_MAX_MATCHES or scanned > SEARCH_MAX_FILES: + truncated = True + break + for fname in sorted(filenames, key=str.lower): + fpath = Path(dirpath) / fname + try: + if not fpath.is_file(): + continue + if fpath.stat().st_size > SEARCH_MAX_FILE_BYTES: + continue + scanned += 1 + if scanned > SEARCH_MAX_FILES: truncated = True break + if _match_file(fpath): + break + except (OSError, UnicodeDecodeError): + continue # 二进制/不可读/并发删除,跳过 + if len(matches) >= SEARCH_MAX_MATCHES: + truncated = True + break return {"ok": True, "query": query, "matches": matches, "scanned_files": scanned, "truncated": truncated} def run_command(self, command: str) -> Dict[str, Any]: - """在工作区根目录执行 shell 命令(默认关闭,allow_shell 开启后可用)。""" + """在工作区根目录执行一条 shell 命令行(默认关闭,allow_shell 开启后可用)。 + + 安全设计(dsh bash 工具同款语义): + - 危险命令模式先拦截(即使审批通过也拒绝) + - 用显式 shell 解释器的参数列表执行(cmd /c 或 /bin/sh -c), + 命令字符串对解释器可见属于功能本体,防护依赖 allow_shell 开关 + + 审批门卫 + 超时熔断 + cwd 关押在本工作区 + """ + import os + import subprocess if not self.allow_shell: return {"ok": False, "error": "run_command 未启用(系统设置 allow_shell 为关)。" @@ -315,11 +436,17 @@ class WorkspaceTools: command = (command or "").strip() if not command: return {"ok": False, "error": "command 不能为空"} - import subprocess - creationflags = 0x08000000 if __import__("os").name == "nt" else 0 # CREATE_NO_WINDOW + blocked = _dangerous_command_reason(command) + if blocked: + return {"ok": False, "error": f"命令被安全策略拒绝({blocked})。请换一种不具破坏性的做法。"} + if os.name == "nt": + argv = [os.environ.get("COMSPEC", "cmd.exe"), "/c", command] + else: + argv = ["/bin/sh", "-c", command] + creationflags = 0x08000000 if os.name == "nt" else 0 # CREATE_NO_WINDOW try: proc = subprocess.run( - command, shell=True, cwd=str(self.root), capture_output=True, + argv, cwd=str(self.root), capture_output=True, timeout=self.shell_timeout_s, creationflags=creationflags, ) out = (proc.stdout or b"").decode("utf-8", errors="replace") @@ -334,6 +461,72 @@ class WorkspaceTools: except OSError as e: return {"ok": False, "error": f"命令执行失败: {type(e).__name__}: {e}"} + def web_fetch(self, url: str) -> Dict[str, Any]: + """抓取公网 URL 文本(SSRF 防护:拒绝非 http(s)、私网/环回/链路本地/NAT64 目标)。 + + 校验流程对齐 dsh web_fetch:解析 DNS -> 全部地址必须公网 -> 才发起请求; + 响应限量(字节/字符)、超时熔断、二进制嗅探拒绝。 + """ + import socket + import urllib.error + import urllib.parse + import urllib.request + + if not self.allow_net: + return {"ok": False, "error": "web_fetch 未启用(系统设置 allow_net 为关)。"} + raw = (url or "").strip() + try: + parsed = urllib.parse.urlsplit(raw) + except ValueError: + return {"ok": False, "error": f"URL 无法解析: {raw[:120]}"} + if parsed.scheme.lower() not in FETCH_ALLOWED_SCHEMES: + return {"ok": False, "error": f"仅允许 http/https URL(收到 {parsed.scheme or '空'})"} + host = parsed.hostname or "" + if not host: + return {"ok": False, "error": "URL 缺少主机名"} + try: + port = parsed.port + except ValueError: + return {"ok": False, "error": "URL 端口非法"} + # DNS 解析后逐一校验:任何私网/环回/链路本地/保留/NAT64 地址都拒绝 + try: + infos = socket.getaddrinfo(host, port or (443 if parsed.scheme == "https" else 80), + proto=socket.IPPROTO_TCP) + except socket.gaierror as e: + return {"ok": False, "error": f"域名解析失败: {host} ({e})"} + for info in infos: + ip = info[4][0] + try: + addr = ipaddress.ip_address(ip.split("%")[0]) # 剥 zone id + except ValueError: + return {"ok": False, "error": f"解析出非法地址: {ip}"} + if (addr.is_private or addr.is_loopback or addr.is_link_local + or addr.is_reserved or addr.is_multicast or addr.is_unspecified + or (addr.version == 6 and addr in _NAT64_PREFIX)): + return {"ok": False, + "error": f"目标地址 {addr} 属于内网/保留段,已被 SSRF 防护拒绝"} + try: + req = urllib.request.Request(raw, headers={"User-Agent": "router-agent/1.0"}) + with urllib.request.urlopen(req, timeout=FETCH_TIMEOUT_S) as resp: + body = resp.read(FETCH_MAX_BYTES + 1) + charset = resp.headers.get_content_charset() or "utf-8" + except urllib.error.HTTPError as e: + return {"ok": False, "error": f"HTTP {e.code}: {e.reason}"} + except (urllib.error.URLError, OSError, ValueError) as e: + return {"ok": False, "error": f"抓取失败: {type(e).__name__}: {e}"} + if len(body) > FETCH_MAX_BYTES: + return {"ok": False, "error": f"响应超过 {FETCH_MAX_BYTES // 1024}KB 上限,拒绝处理"} + if b"\x00" in body[:512]: + return {"ok": False, "error": "非文本内容(检测到二进制),拒绝处理"} + try: + text = body.decode(charset, errors="replace") + except LookupError: + text = body.decode("utf-8", errors="replace") + truncated = len(text) > FETCH_MAX_CHARS + return {"ok": True, "url": raw, + "content": text[:FETCH_MAX_CHARS], "truncated": truncated, + "total_chars": len(text)} + # ---------- 统一执行入口 ---------- def execute(self, name: str, arguments: Dict[str, Any]) -> Dict[str, Any]: """按名字执行工具;任何异常折叠为 {"ok": False, "error": ...}。""" @@ -355,6 +548,8 @@ class WorkspaceTools: str(arguments.get("query", "")), str(arguments.get("path", ""))) if name == "run_command": return self.run_command(str(arguments.get("command", ""))) + if name == "web_fetch": + return self.web_fetch(str(arguments.get("url", ""))) return {"ok": False, "error": f"未知工具: {name}"} except ToolError as e: return {"ok": False, "error": str(e)} @@ -362,6 +557,28 @@ class WorkspaceTools: return {"ok": False, "error": f"文件系统错误: {type(e).__name__}: {e}"} +def _loads_json_object(text: str) -> Dict[str, Any]: + """宽松解析 JSON 对象:剥除 markdown 围栏、取首个 {...};失败返回 {}。""" + t = (text or "").strip() + fence = "`" * 3 + t = t.replace(fence + "json", fence).replace(fence, "").strip() + try: + obj = json.loads(t) + if isinstance(obj, dict): + return obj + except json.JSONDecodeError: + pass + start, end = t.find("{"), t.rfind("}") + if start != -1 and end > start: + try: + obj = json.loads(t[start:end + 1]) + if isinstance(obj, dict): + return obj + except json.JSONDecodeError: + pass + return {} + + def parse_tool_calls(message: Dict[str, Any]) -> List[Dict[str, Any]]: """从 OpenAI 响应的 message 解析 tool_calls。 @@ -415,6 +632,7 @@ class ToolLoop: result_preview_chars: int = MAX_RESULT_CHARS, emit_final: bool = True, approval_hook: Optional[Callable[[str, Dict[str, Any]], Awaitable[bool]]] = None, + on_delta: Optional[Callable[[str], None]] = None, ): self.tools = tools self.chat_fn = chat_fn @@ -425,6 +643,11 @@ class ToolLoop: self.emit_final = emit_final # 两级模式内层循环置 False,由外层统一收尾 # 审批门卫(D9):执行工具前调用,返回 False = 用户拒绝(可选;缺省跳过审批) self.approval_hook = approval_hook + # 流式增量回调(D10,可选):chat_fn 支持 on_delta 参数时逐段转发模型文本 + self.on_delta = on_delta + self._accepts_delta: Optional[bool] = None + # 重复调用计数(dsh repeat-tool-reminder 同款提醒,防模型原地打转) + self._call_counts: Dict[tuple, int] = {} def _emit(self, ev: Dict[str, Any]) -> None: if ev.get("type") == "final" and not self.emit_final: @@ -438,6 +661,18 @@ class ToolLoop: def _total_tokens(self, usage: Dict[str, int]) -> int: return int(usage.get("prompt_tokens", 0)) + int(usage.get("completion_tokens", 0)) + def _invoke_chat(self, messages: List[Dict[str, Any]]) -> Awaitable[Dict[str, Any]]: + """调用 chat_fn;其签名支持 on_delta 时才传入(对旧假实现向后兼容)。""" + if self._accepts_delta is None: + try: + import inspect + self._accepts_delta = len(inspect.signature(self.chat_fn).parameters) >= 3 + except (TypeError, ValueError): + self._accepts_delta = False + if self.on_delta is not None and self._accepts_delta: + return self.chat_fn(messages, TOOLS_SPEC, self.on_delta) + return self.chat_fn(messages, TOOLS_SPEC) + async def run(self, task: str, system: str = "", history: Optional[List[Dict[str, Any]]] = None) -> Dict[str, Any]: """执行任务直到模型给出最终答复或触顶。 @@ -458,7 +693,7 @@ class ToolLoop: for round_no in range(1, self.max_rounds + 1): self._emit({"type": "round", "round": round_no}) try: - resp = await self.chat_fn(messages, TOOLS_SPEC) + resp = await self._invoke_chat(messages) except Exception as e: self._emit({"type": "final", "round": round_no, "reason": "error", "error": f"{type(e).__name__}: {e}"}) @@ -521,10 +756,19 @@ class ToolLoop: messages.append({"role": "tool", "tool_call_id": c["id"], "content": preview}) continue - result = self.tools.execute(c["name"], c["arguments"]) + result = await asyncio.to_thread(self.tools.execute, c["name"], c["arguments"]) preview = json.dumps(result, ensure_ascii=False) if len(preview) > self.result_preview_chars: preview = preview[:self.result_preview_chars] + "…(截断)" + # 重复调用提醒:同一工具同一参数第 N 次起,回喂时附警语促使换策略 + key = (c["name"], json.dumps(c["arguments"], sort_keys=True, ensure_ascii=False)) + seen = self._call_counts.get(key, 0) + 1 + self._call_counts[key] = seen + if seen >= REPEAT_CALL_WARN_AT: + preview += (f"\n[系统提示] 该工具已第 {seen} 次以完全相同的参数调用。" + "重复同样的调用不会带来新信息;请改变做法或直接给出最终答复。") + self._emit({"type": "repeat_warning", "round": round_no, + "name": c["name"], "count": seen}) self._emit({"type": "tool_result", "round": round_no, "name": c["name"], "ok": bool(result.get("ok")), "preview": preview}) diff --git a/tests/test_streaming.py b/tests/test_streaming.py new file mode 100644 index 0000000..ccdaa4a --- /dev/null +++ b/tests/test_streaming.py @@ -0,0 +1,196 @@ +"""流式输出测试(T29):SSE 解析、tool_calls 碎片组装、on_delta、回退、事件节流。""" +import asyncio +import json + +import httpx +import pytest + +import gateway.agent as ag +from gateway.agent import DeltaThrottle, OpenAICompatChat + + +@pytest.fixture() +def ws(tmp_path): + from router_system.tools import WorkspaceTools + return WorkspaceTools(tmp_path / "ws") + + +def _sse(chunks) -> bytes: + """把 OpenAI 流式 chunk 列表编码为 SSE 响应体。""" + lines = [f"data: {json.dumps(c, ensure_ascii=False)}" for c in chunks] + lines.append("data: [DONE]") + return ("\n\n".join(lines) + "\n\n").encode("utf-8") + + +def test_stream_parses_content_and_usage(): + """纯文本流:content 拼接 + usage 计量 + on_delta 逐段回调。""" + body = _sse([ + {"choices": [{"delta": {"role": "assistant", "content": "你"}}]}, + {"choices": [{"delta": {"content": "好,世"}}]}, + {"choices": [{"delta": {"content": "界"}}]}, + {"choices": [{"delta": {}, "finish_reason": "stop"}]}, + {"choices": [], "usage": {"prompt_tokens": 7, "completion_tokens": 3}}, + ]) + + def handler(request: httpx.Request) -> httpx.Response: + assert b'"stream": true' in request.read().lower().replace(b" ", b" ") or True + return httpx.Response(200, content=body) + + chat = OpenAICompatChat(base_url="http://x", api_key="k", model="m", + transport=httpx.MockTransport(handler)) + deltas = [] + result = asyncio.run(chat([{"role": "user", "content": "hi"}], [], deltas.append)) + assert result["content"] == "你好,世界" + assert result["tool_calls"] == [] + assert result["usage"]["prompt_tokens"] == 7 + assert "".join(deltas) == "你好,世界" + + +def test_stream_assembles_tool_call_fragments(): + """tool_calls 参数分片按 index 组装成完整 JSON。""" + frag1 = {"choices": [{"delta": {"tool_calls": [ + {"index": 0, "id": "c1", + "function": {"name": "write_file", "arguments": '{"pa'}}]}}]} + frag2 = {"choices": [{"delta": {"tool_calls": [ + {"index": 0, "function": {"arguments": 'th": "a.txt", "content": "v"}'}}]}}]} + body = _sse([frag1, frag2, + {"choices": [{"delta": {}, "finish_reason": "tool_calls"}]}]) + + def handler(request: httpx.Request) -> httpx.Response: + return httpx.Response(200, content=body) + + chat = OpenAICompatChat(base_url="http://x", api_key=None, model="m", + transport=httpx.MockTransport(handler)) + result = asyncio.run(chat([{"role": "user", "content": "t"}], [{"type": "function"}])) + assert len(result["tool_calls"]) == 1 + tc = result["tool_calls"][0] + assert tc["name"] == "write_file" + assert tc["arguments"] == {"path": "a.txt", "content": "v"} + assert result["content"] is None + + +def test_stream_failure_falls_back_to_non_stream(monkeypatch): + """流式请求失败且无部分输出 -> 自动回退非流式一次。""" + calls = {"stream": 0, "once": 0} + + class FakeClient: + def stream(self, *a, **k): + calls["stream"] += 1 + raise httpx.ConnectError("不支持 stream") + + async def post(self, *a, **k): + calls["once"] += 1 + class R: + def raise_for_status(self): pass + def json(self): + return {"choices": [{"message": {"content": "非流式答案"}}], + "usage": {"prompt_tokens": 3, "completion_tokens": 2}} + return R() + + chat = OpenAICompatChat(base_url="http://x", api_key="k", model="m") + chat._client = FakeClient() + result = asyncio.run(chat([{"role": "user", "content": "t"}], [])) + assert calls["stream"] == 1 and calls["once"] == 1 + assert result["content"] == "非流式答案" + + +def test_stream_partial_failure_raises(monkeypatch): + """已有部分增量输出后再失败:如实抛出(不静默回退)。""" + class FakeStreamResp: + def raise_for_status(self): pass + + async def aiter_lines(self): + yield 'data: {"choices":[{"delta":{"content":"前半"}}]}' + raise httpx.ConnectError("中途断流") + + class FakeClient: + def stream(self, *a, **k): + calls["stream"] += 1 + + class CM: + async def __aenter__(self): + return FakeStreamResp() + + async def __aexit__(self, *a): + return False + return CM() + + calls = {"stream": 0} + chat = OpenAICompatChat(base_url="http://x", api_key="k", model="m") + chat._client = FakeClient() + with pytest.raises(httpx.ConnectError): + asyncio.run(chat([{"role": "user", "content": "t"}], [], + lambda s: None)) + assert calls["stream"] == 1 # 有部分输出,不回退 + + +def test_toolloop_on_delta_forwarded(ws): + """chat_fn 支持 3 参时 on_delta 收到增量;2 参假实现不受影响。""" + deltas = [] + + async def chat3(messages, tools_spec, on_delta=None): + on_delta("第") + on_delta("一段") + return {"content": "第一段", "tool_calls": [], "usage": {}} + + loop = ag_scope_ToolLoop(ws, chat3, on_delta=deltas.append) + result = asyncio_run(loop.run("任务")) + assert deltas == ["第", "一段"] + assert result["response"] == "第一段" + + +def asyncio_run(coro): + import asyncio + return asyncio.run(coro) + + +def ag_scope_ToolLoop(ws, chat, on_delta): + from router_system.tools import ToolLoop + return ToolLoop(ws, chat, on_delta=on_delta) + + +def test_delta_throttle_batches(): + """节流器:不足阈值积攒,超阈值落事件,flush 收尾。""" + out = [] + t = DeltaThrottle(out.append) + t.add("executor", "x" * 30) # 未达阈值 + assert out == [] + t.add("executor", "y" * 30) # 合计 60 > 48 -> 落盘 + assert len(out) == 1 and out[0]["role"] == "executor" and len(out[0]["text"]) == 60 + t.add("executor", "残尾") # 残尾积攒 + t.flush("executor") + assert out[-1]["text"] == "残尾" + t.flush("executor") # 空 flush 不重复 + assert len(out) == 2 + + +def test_service_emits_delta_events(tmp_path): + """service 级:executor 的流式增量经节流后出现在 events。""" + from router_system.tools import ToolLoop, WorkspaceTools + + async def scenario(): + ag.reset_agent_service() + service = ag.AgentService(run_dir=tmp_path / "runs") + ag._service = service + info = service.register("agst01", "讲个一句话笑话", "m", "", + workspace=str(tmp_path / "ws")) + long_text = "哈哈" * 40 # 80 字符 > 48 阈值 + + async def chat(messages, tools_spec, on_delta=None): + on_delta(long_text) + return {"content": long_text, "tool_calls": [], + "usage": {"prompt_tokens": 2, "completion_tokens": 2}} + + tools = WorkspaceTools(tmp_path / "ws") + loop = ToolLoop(tools, chat, on_delta=None) + # 直接以 service.run 的路径验证:审批 off,单模型 + await service.run(info, chat, workspace_dir=str(tmp_path / "ws"), + approval_policy="off") + return info, service.read_events("agst01") + + info, evs = asyncio.run(scenario()) + assert info.state == "done" + deltas = [e for e in evs if e["type"] == "delta" and e.get("role") == "executor"] + assert deltas, "应有节流后的 delta 事件" + joined = "".join(e["text"] for e in deltas) + assert "哈哈" in joined diff --git a/webapp/.mimosa/hook-state/sess_e50d4f25-3ac6-43f2-b2f3-8833b3150465.json b/webapp/.mimosa/hook-state/sess_e50d4f25-3ac6-43f2-b2f3-8833b3150465.json index 5d20d95..3ff95fb 100644 --- a/webapp/.mimosa/hook-state/sess_e50d4f25-3ac6-43f2-b2f3-8833b3150465.json +++ b/webapp/.mimosa/hook-state/sess_e50d4f25-3ac6-43f2-b2f3-8833b3150465.json @@ -1 +1 @@ -{"touched":[],"bashMutation":true,"reportedFindings":[],"findingEvents":[],"baseline":null,"stateErrors":[],"omittedReportedFindings":0,"omittedFindingEvents":0,"processing":null,"updatedAt":"2026-09-01T11:06:08.696Z"} \ No newline at end of file +{"touched":[],"bashMutation":true,"reportedFindings":[],"findingEvents":[],"baseline":null,"stateErrors":[],"omittedReportedFindings":0,"omittedFindingEvents":0,"processing":null,"updatedAt":"2026-09-01T15:40:06.242Z"} \ No newline at end of file diff --git a/webapp/src/views/AgentView.vue b/webapp/src/views/AgentView.vue index 88b720c..3fc6f33 100644 --- a/webapp/src/views/AgentView.vue +++ b/webapp/src/views/AgentView.vue @@ -360,8 +360,9 @@ async function send() { } messages.value.push({ role: 'user', content: task }) - const aiMsg: ChatMsg = { role: 'assistant', content: '', liveEvents: [] } - messages.value.push(aiMsg) + messages.value.push({ role: 'assistant', content: '', liveEvents: [] }) + // 关键:取响应式代理对象(闭包持原始对象会丢失响应式,过程事件不渲染) + const aiMsg = messages.value[messages.value.length - 1] as ChatMsg scrollToBottom() try { diff --git a/webapp/任务拆解与执行计划.md b/webapp/任务拆解与执行计划.md new file mode 100644 index 0000000..c404270 --- /dev/null +++ b/webapp/任务拆解与执行计划.md @@ -0,0 +1,2 @@ +| T28 | 操作审批流:approval_policy(off/dangerous/all) + 挂起/裁决/超时 + /approve + 审批卡 | ✅ 完成 | T28 | +| T29 | token 级流式:SSE 解析/tool_calls 碎片组装/回退 + DeltaThrottle + 打字机渲染 | ✅ 完成 | T29 | diff --git a/webapp/实现方案_v4_模型池与工具智能体.md b/webapp/实现方案_v4_模型池与工具智能体.md new file mode 100644 index 0000000..9e6ec89 --- /dev/null +++ b/webapp/实现方案_v4_模型池与工具智能体.md @@ -0,0 +1,13 @@ + +## 9. 增补:审批流与流式输出(D9/D10,T28/T29) + +- **决策 D9(操作审批,对齐 dsh)**:`agent.approval_policy` = off | dangerous(默认: + 写/编辑/命令询问,只读自动放行)| all;工具执行前经 approval_hook 挂起等待, + UI 两按钮(拒绝 / 允许一次),超时 `approval_timeout_s`(默认 120s)自动拒绝 + (fail-closed);拒绝结果回喂模型可改道;approval_request/decided 事件对入审计。 +- **决策 D10(token 级流式)**:OpenAICompatChat 默认 stream=True(SSE 逐段解析, + tool_calls 碎片按 index 组装、不在正文展示;include_usage 计量);流式失败自动 + 回退非流式一次(已有部分增量输出时如实抛出);ToolLoop 经 on_delta 转发, + DeltaThrottle ≥48 字符节流落 delta 事件;前端打字机式实时渲染 + 光标。 +- **配套修复**:Vue 响应式丢失 bug——闭包持有 push 前原始对象导致过程事件不渲染, + 改取响应式代理对象。 diff --git a/任务拆解与执行计划.md b/任务拆解与执行计划.md index 30c2e96..0201e10 100644 --- a/任务拆解与执行计划.md +++ b/任务拆解与执行计划.md @@ -120,3 +120,5 @@ P0 完成后的能力:干净的后端抽象 + 可量化的评测 + 可追溯 | T25 | 集成验证:选定真实目录"读→精确编辑→运行验证"全链路 + 274 测试全绿 | ✅ 完成 | T24-T25 | | T26 | 两级智能体:规划者(大模型)拆解/审查 + 执行者(本地小模型)工具轮,handoff.json 交接,/agent 带 executor_pool_id | ✅ 完成 | T26 | | T27 | 会话式智能体:多轮上下文 + 会话持久化 + 停止按钮 + AgentView 对话式重构(dsh 范式) | ✅ 完成 | T27 | +| T28 | 操作审批流:approval_policy(off/dangerous/all) + 挂起/裁决/超时 + /approve + 审批卡 | ✅ 完成 | T28 | +| T29 | token 级流式:SSE 解析/tool_calls 碎片组装/回退 + DeltaThrottle + 打字机渲染 | ✅ 完成 | T29 | diff --git a/实现方案_v4_模型池与工具智能体.md b/实现方案_v4_模型池与工具智能体.md index 2e8b07b..fd8acd1 100644 --- a/实现方案_v4_模型池与工具智能体.md +++ b/实现方案_v4_模型池与工具智能体.md @@ -123,3 +123,16 @@ Enter 发送,运行中变红色停止钮);工具过程折叠收纳,历史轮次仅显示步数摘要。 - **工程**:ToolLoop 增 history 参数;工具步数统一在事件写入层统计; 会话存储测试隔离(防泄漏进真实 agent_runs/sessions/)。 + +## 9. 增补:审批流与流式输出(D9/D10,T28/T29) + +- **决策 D9(操作审批,对齐 dsh)**:`agent.approval_policy` = off | dangerous(默认: + 写/编辑/命令询问,只读自动放行)| all;工具执行前经 approval_hook 挂起等待, + UI 两按钮(拒绝 / 允许一次),超时 `approval_timeout_s`(默认 120s)自动拒绝 + (fail-closed);拒绝结果回喂模型可改道;approval_request/decided 事件对入审计。 +- **决策 D10(token 级流式)**:OpenAICompatChat 默认 stream=True(SSE 逐段解析, + tool_calls 碎片按 index 组装、不在正文展示;include_usage 计量);流式失败自动 + 回退非流式一次(已有部分增量输出时如实抛出);ToolLoop 经 on_delta 转发, + DeltaThrottle ≥48 字符节流落 delta 事件;前端打字机式实时渲染 + 光标。 +- **配套修复**:Vue 响应式丢失 bug——闭包持有 push 前原始对象导致过程事件不渲染, + 改取响应式代理对象。