"""Cursor SDK 调用(daily 包专用)。""" from __future__ import annotations import os from cursor_sdk import Agent, AgentOptions, Client, CursorAgentError, LocalAgentOptions from daily.config import env, env_int from daily.cursor_bridge import cursor_cwd, warm_cursor_bridge _sdk_client: Client | None = None _sdk_client_key: tuple[str, str, float] | None = None def cursor_timeout_seconds() -> float: """Cursor bridge unary/stream 超时(秒);与 bot 共用 CURSOR_TIMEOUT。""" return float(env_int("CURSOR_TIMEOUT", 600)) def _cursor_sdk_client() -> Client: """带自定义超时的 bridge Client(SDK 默认 unary 仅 60s,复杂 Agent 任务易超时)。""" global _sdk_client, _sdk_client_key warm_cursor_bridge() url = os.environ.get("CURSOR_SDK_BRIDGE_URL", "") token = os.environ.get("CURSOR_SDK_BRIDGE_TOKEN", "") timeout = cursor_timeout_seconds() key = (url, token, timeout) if _sdk_client is not None and _sdk_client_key == key: return _sdk_client if _sdk_client is not None: _sdk_client.close() _sdk_client = Client( base_url=url, auth_token=token, unary_timeout=timeout, stream_timeout=timeout, allow_api_key_env_fallback=False, ) _sdk_client_key = key return _sdk_client def cursor_chat(system: str, user: str) -> str: api_key = (env("CURSOR_API_KEY") or "").strip() if not api_key: return "" client = _cursor_sdk_client() cwd = cursor_cwd() model = env("CURSOR_MODEL") or "composer-2.5" prompt = f"{system}\n\n{user}" try: result = Agent.prompt( prompt, AgentOptions( api_key=api_key, model=model, local=LocalAgentOptions(cwd=cwd), ), client=client, ) except CursorAgentError as exc: raise RuntimeError(f"LLM 调用失败:{exc.message}") from exc if result.status == "error": raise RuntimeError(f"LLM 调用失败:{result.result or '未知错误'}") return (result.result or "").strip()