@yachiyo-5i/xlyra-agent 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-5AIZKDJO.js → chunk-KKPK4RMM.js} +57 -20
- package/dist/chunk-KKPK4RMM.js.map +1 -0
- package/dist/cli.cjs +56 -19
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +56 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-5AIZKDJO.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/llm/models.ts","../src/llm/errors.ts","../src/llm/credential.ts","../src/llm/http-error.ts","../src/llm/sse.ts","../src/llm/stream-assembler.ts","../src/llm/protocols/messages.ts","../src/llm/protocols/responses.ts","../src/llm/router.ts","../src/llm/validate.ts","../src/agent/events.ts","../src/agent/prompts.ts","../src/agent/retained-context.ts","../src/agent/compaction.ts","../src/agent/sessions.ts","../src/agent/runner.ts","../src/tools/types.ts","../src/agent/escalation.ts","../src/tools/index.ts","../src/tools/apply-patch.ts","../src/tools/workdir.ts","../src/tools/create.ts","../src/tools/edit.ts","../src/tools/exec-command.ts","../src/tools/process-manager.ts","../src/tools/list.ts","../src/tools/load-skill.ts","../src/context/skills.ts","../src/tools/read.ts","../src/tools/search.ts","../src/tools/write.ts","../src/tools/write-stdin.ts","../src/server/index.ts","../src/server/config.ts","../src/server/config-routes.ts","../src/server/run-registry.ts","../src/server/recorder.ts","../src/server/routes.ts","../src/context/agents-md.ts","../src/context/index.ts","../src/server/session-index.ts"],"sourcesContent":["/**\n * xlyra-agent 公共出口。\n *\n * 分层:llm/(怎么调模型)→ agent/(一次任务怎么跑)→ server/(HTTP 服务)。\n * 库用法只 import 本文件即可拿到全部公共 API。\n */\nexport * from \"./llm/index.js\";\nexport * from \"./agent/index.js\";\nexport * from \"./tools/index.js\";\nexport {\n createAgentServer,\n serveFromConfig,\n createAgentRoutes,\n loadConfig,\n saveConfig,\n upsertEndpoint,\n removeEndpoint,\n configExists,\n defaultConfigPath,\n HttpError,\n RunRegistry,\n SessionIndex,\n AgentRunRecorder,\n type AppConfig,\n type ServerConfig,\n type AgentServiceConfig,\n type StoredAgentEvent,\n} from \"./server/index.js\";\n\nexport * from \"./context/index.js\";\n","/**\n * 内部规范模型 —— 协议无关的对话数据表达。\n *\n * 分层定位:llm/protocols/ 下的两个适配器(OpenAI Responses / Anthropic\n * Messages)负责把各自 wire 格式翻译成这里的模型;agent 层(runner/压缩/\n * 工具)永远只面对本文件定义的结构,不感知任何协议细节。\n *\n * 设计要点:\n * - ToolCall 始终保留 raw_arguments 原文(字符串),parse 发生在使用方——\n * 流式分片期间参数是不完整 JSON,只有归并完成后才可能解析成功;\n * - ChatMessage 带 thinking / thinking_signature:Anthropic 多轮工具往返\n * 要求带签名的 thinking block 原样回喂(评审定案透传),无签名的旧消息\n * 回喂时整块省略(API 允许);\n * - tool 角色的 is_error:Anthropic tool_result block 需要显式标注失败。\n */\nimport { z } from \"zod\";\n\nexport const toolCallSchema = z.object({\n id: z.string(),\n name: z.string(),\n /** 参数 JSON 原文(流式归并后的完整串;可能不是合法 JSON,由校验阶段兜底) */\n raw_arguments: z.string(),\n});\nexport type ToolCall = z.infer<typeof toolCallSchema>;\n\nexport const chatMessageSchema = z.object({\n role: z.enum([\"system\", \"user\", \"assistant\", \"tool\"]),\n content: z.string().default(\"\"),\n tool_calls: z.array(toolCallSchema).optional(),\n tool_call_id: z.string().optional(),\n name: z.string().optional(),\n is_error: z.boolean().optional(),\n thinking: z.string().optional(),\n thinking_signature: z.string().optional(),\n});\nexport type ChatMessage = z.infer<typeof chatMessageSchema>;\n\n/** 消息正文文本(当前为纯文本管线,直接返回 content;保留函数形态便于将来多模态扩展) */\nexport function messageText(message: ChatMessage): string {\n return message.content ?? \"\";\n}\n\nexport const tokenUsageSchema = z.object({\n prompt_tokens: z.number().default(0),\n completion_tokens: z.number().default(0),\n total_tokens: z.number().default(0),\n cache_read_tokens: z.number().default(0),\n});\nexport type TokenUsage = z.infer<typeof tokenUsageSchema>;\n\nexport function emptyUsage(): TokenUsage {\n return { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, cache_read_tokens: 0 };\n}\n\nexport function addUsage(total: TokenUsage, step: TokenUsage): TokenUsage {\n return {\n prompt_tokens: total.prompt_tokens + step.prompt_tokens,\n completion_tokens: total.completion_tokens + step.completion_tokens,\n total_tokens: total.total_tokens + step.total_tokens,\n cache_read_tokens: total.cache_read_tokens + step.cache_read_tokens,\n };\n}\n\nexport const modelSettingsSchema = z.object({\n temperature: z.number().optional(),\n max_tokens: z.number().optional(),\n /** 思考强度:映射到 Anthropic thinking budget / OpenAI reasoning effort。\n * max/ultra 是网关侧的更高档位别名,协议层统一归一为 xhigh */\n reasoning_effort: z.enum([\"low\", \"medium\", \"high\", \"xhigh\", \"max\", \"ultra\"]).optional(),\n});\nexport type ModelSettings = z.infer<typeof modelSettingsSchema>;\n\nexport type ReasoningEffort = NonNullable<ModelSettings[\"reasoning_effort\"]>;\n\n/** 归一化思考强度:max/ultra 一律按 xhigh 处理 */\nexport function normalizeEffort(effort: ReasoningEffort): \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n return effort === \"max\" || effort === \"ultra\" ? \"xhigh\" : effort;\n}\n\n/** 暴露给模型的工具声明(parameters 为 JSON Schema object) */\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n}\n\n/** 一次模型调用的定稿响应(done 事件的载荷) */\nexport interface ChatResponse {\n content: string;\n thinking: string | null;\n thinking_signature: string | null;\n tool_calls: ToolCall[];\n usage: TokenUsage;\n finish_reason: string | null;\n model: string;\n provider: string;\n}\n\n/** 定稿响应 → 入对话历史的 assistant 消息(思考链与签名随消息保存,供历史回喂) */\nexport function responseToMessage(response: ChatResponse): ChatMessage {\n const message: ChatMessage = { role: \"assistant\", content: response.content };\n if (response.tool_calls.length > 0) message.tool_calls = response.tool_calls;\n if (response.thinking) message.thinking = response.thinking;\n if (response.thinking_signature) message.thinking_signature = response.thinking_signature;\n return message;\n}\n","/**\n * LLM 层错误:路由解析失败(没配端点/模型不存在)等**调用前**错误抛出;\n * 调用中的流错误一律走 StreamEvent error 事件,不抛异常。\n */\nexport class LlmError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LlmError\";\n }\n}\n","/**\n * 统一凭证解析:direct 与 remote-xlyra 都经此得到「凭证类型 + HTTP header」,\n * 协议实现不自行判断配置字段,也不把所有凭证当作同一种认证方式。\n *\n * 认证规则(docs 第 6 章定稿):\n * - direct + openai-responses → Authorization: Bearer <api_key>\n * - direct + anthropic-messages → x-api-key: <api_key>\n * - remote-xlyra(两种协议) → Authorization: Bearer <temporary-token>\n *\n * 纪律:token/api_key 只存在于 ResolvedCredential.headerValue 与 provider 内部,\n * 不得写入日志、事件、transcript 或错误信息。\n */\nimport { LlmError } from \"./errors.js\";\nimport type { AgentRunContext, EndpointConfig } from \"./router.js\";\n\nexport interface ResolvedCredential {\n kind: \"api-key\" | \"temporary-bearer\";\n headerName: \"authorization\" | \"x-api-key\";\n headerValue: string;\n}\n\nexport interface CredentialProvider {\n getCredential(): Promise<ResolvedCredential>;\n}\n\n/** 静态凭证:direct api_key 或 remote-xlyra 固定 token,一经构造不变 */\nexport class StaticCredentialProvider implements CredentialProvider {\n constructor(private readonly credential: ResolvedCredential) {}\n\n getCredential(): Promise<ResolvedCredential> {\n return Promise.resolve(this.credential);\n }\n}\n\n/**\n * xlyra-callback 凭证 provider:首次缺 token 走 callback 初始签发;之后按\n * expires_at 提前主动续期(持旧 token 调 /credential/renew 换新 token)。\n * token 只保存在进程内存。\n *\n * 续期纪律(docs §8 定稿):\n * - 续期由 runner 主动发起,绝不由 LLM 入口的 401 触发——401 只表示凭证\n * 已被吊销或 run 已结束,此时不得换票,应终止当前 run;\n * - renew 是持票认证:请求携带当前 token 做 Bearer,过期/被顶替的凭证\n * 无法换新;\n * - token 按 runId 隔离存储,并发 run 各自持有独立 token,互不作废\n * (xLyra 按 run_id 校验,串 run 用 token 会 401);\n * - 并发首次取 token / 续期各自合并为一次 in-flight 请求,避免重复签发。\n */\n\n/** 主动续期阈值:剩余 TTL 低于该值时,下次取凭证先换票 */\nconst DEFAULT_RENEW_THRESHOLD_MS = 5 * 60_000;\n/** 响应缺少合法 expires_at 时的保守兜底有效期 */\nconst FALLBACK_TOKEN_TTL_MS = 15 * 60_000;\nconst INITIAL_ISSUE_ATTEMPTS = 6;\nconst INITIAL_ISSUE_RETRY_DELAY_MS = 500;\n\ninterface CachedCredential {\n credential: ResolvedCredential;\n /** epoch 毫秒 */\n expiresAt: number;\n}\n\nexport class XlyraCallbackCredentialProvider implements CredentialProvider {\n private context: AgentRunContext | null = null;\n /** runId → 当前有效 token 及其过期时刻 */\n private readonly tokensByRun = new Map<string, CachedCredential>();\n /** runId → 进行中的签发/续期(并发去重) */\n private readonly inflight = new Map<string, Promise<CachedCredential | null>>();\n private readonly fetchImpl: typeof fetch;\n private readonly renewThresholdMs: number;\n private readonly sleep: (ms: number) => Promise<void>;\n private readonly now: () => number;\n\n constructor(\n private readonly url: string,\n opts?: {\n fetchImpl?: typeof fetch;\n renewThresholdMs?: number;\n sleep?: (ms: number) => Promise<void>;\n now?: () => number;\n },\n ) {\n this.fetchImpl = opts?.fetchImpl ?? fetch;\n this.renewThresholdMs = opts?.renewThresholdMs ?? DEFAULT_RENEW_THRESHOLD_MS;\n this.sleep = opts?.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n this.now = opts?.now ?? Date.now;\n }\n\n /** 更新当前 run 上下文。token 按 runId 隔离,切换 run 不影响其他 run 的 token */\n setRunContext(context: AgentRunContext): void {\n this.context = context;\n }\n\n async getCredential(): Promise<ResolvedCredential> {\n return this.getCredentialFor(this.requireContext().runId);\n }\n\n /**\n * 按 run 取凭证(并发安全):chatStream 在请求开始时调用一次并全程使用\n * 返回值——并发 run 各自的 token 互不干扰(setRunContext 只影响下一次\n * 请求开始时的解析)。缓存 token 临近过期时先主动续期再返回。\n */\n async getCredentialFor(runId: string): Promise<ResolvedCredential> {\n const cached = this.tokensByRun.get(runId);\n if (cached) {\n const remaining = cached.expiresAt - this.now();\n if (remaining > this.renewThresholdMs) return cached.credential;\n const renewed = await this.renewCredentialFor(runId);\n if (renewed) return renewed;\n if (remaining > 0) return cached.credential; // 续期失败但旧 token 仍有效:沿用\n throw new LlmError(\"xLyra LLM 调用凭证不可用:token 已过期且续期失败\");\n }\n const issued = await this.issueInitial(runId);\n if (!issued) {\n throw new LlmError(\"xLyra LLM 调用凭证不可用:run 已结束或 callback 未签发 token\");\n }\n return issued;\n }\n\n /**\n * 401 重试专用:仅当本地凭证自 used 之后已被轮换(主动续期换上了新\n * token)时返回新凭证,否则返回 null——401 本身不触发换票。\n */\n rotatedCredentialFor(runId: string, used: ResolvedCredential): ResolvedCredential | null {\n const cached = this.tokensByRun.get(runId);\n if (!cached || cached.credential === used) return null;\n return cached.credential;\n }\n\n /**\n * 持票续期(并发去重):携带当前 token 调 renew 端点换新 token。\n * 返回 null:无缓存、上下文已换 run、renew 被拒(token 失效/run 结束)\n * 或网络失败——调用方按语义自行决定是否沿用旧 token 或终止 run。\n */\n renewCredentialFor(runId: string): Promise<ResolvedCredential | null> {\n const context = this.requireContext();\n if (context.runId !== runId) return Promise.resolve(null); // 上下文已换 run,拒签\n const cached = this.tokensByRun.get(runId);\n if (!cached) return Promise.resolve(null);\n return this.dedup(runId, () => this.doRenew(context, cached));\n }\n\n /** 首次签发(并发去重):run 还没有 token 时调 credential callback */\n private issueInitial(runId: string): Promise<ResolvedCredential | null> {\n const context = this.requireContext();\n if (context.runId !== runId) return Promise.resolve(null);\n return this.dedup(runId, () => this.doIssueInitial(context));\n }\n\n private dedup(runId: string, task: () => Promise<CachedCredential | null>): Promise<ResolvedCredential | null> {\n const pending = this.inflight.get(runId);\n if (pending) return pending.then((cached) => cached?.credential ?? null);\n const promise = task().finally(() => {\n this.inflight.delete(runId);\n });\n this.inflight.set(runId, promise);\n return promise.then((cached) => cached?.credential ?? null);\n }\n\n private requireContext(): AgentRunContext {\n if (!this.context) {\n throw new LlmError(\"xLyra LLM 凭证缺少 run 上下文(agent_instance_id/session_id/run_id)\");\n }\n return this.context;\n }\n\n private async doIssueInitial(context: AgentRunContext): Promise<CachedCredential | null> {\n for (let attempt = 0; attempt < INITIAL_ISSUE_ATTEMPTS; attempt += 1) {\n if (attempt > 0) await this.sleep(INITIAL_ISSUE_RETRY_DELAY_MS);\n let res: Response;\n try {\n res = await this.fetchImpl(this.url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n agent_instance_id: context.agentInstanceId,\n session_id: context.sessionId,\n run_id: context.runId,\n model: context.model,\n reason: \"initial\",\n }),\n });\n } catch {\n continue;\n }\n const cached = await this.storeFromResponse(context.runId, res);\n if (cached) return cached;\n }\n return null;\n }\n\n private async doRenew(context: AgentRunContext, cached: CachedCredential): Promise<CachedCredential | null> {\n let res: Response;\n try {\n res = await this.fetchImpl(`${this.url}/renew`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n // 持票认证:token 只出现在 Authorization header,不进日志与错误\n authorization: cached.credential.headerValue,\n },\n });\n } catch {\n return null;\n }\n return this.storeFromResponse(context.runId, res);\n }\n\n private async storeFromResponse(runId: string, res: Response): Promise<CachedCredential | null> {\n if (!res.ok) return null;\n let payload: { active?: unknown; token?: unknown; expires_at?: unknown };\n try {\n payload = (await res.json()) as typeof payload;\n } catch {\n return null;\n }\n if (payload.active !== true || typeof payload.token !== \"string\" || !payload.token) {\n return null;\n }\n const parsedExpiry = typeof payload.expires_at === \"string\" ? Date.parse(payload.expires_at) : Number.NaN;\n const cached: CachedCredential = {\n credential: {\n kind: \"temporary-bearer\",\n headerName: \"authorization\",\n headerValue: `Bearer ${payload.token}`,\n },\n expiresAt: Number.isNaN(parsedExpiry) ? this.now() + FALLBACK_TOKEN_TTL_MS : parsedExpiry,\n };\n this.tokensByRun.set(runId, cached);\n // 只保留最近若干个 run 的 token(长时间运行进程的内存卫生)\n if (this.tokensByRun.size > 64) {\n const oldest = this.tokensByRun.keys().next().value;\n if (oldest !== undefined) this.tokensByRun.delete(oldest);\n }\n return cached;\n }\n}\n\n/** 按 endpoint 配置构造凭证 provider;配置非法在启动期就已被 schema 拦截,这里兜底 */\nexport function resolveCredentialProvider(endpoint: EndpointConfig): CredentialProvider {\n if (endpoint.mode === \"remote-xlyra\") {\n if (endpoint.credential?.type === \"xlyra-callback\") {\n return new XlyraCallbackCredentialProvider(endpoint.credential.url);\n }\n const token = endpoint.credential?.token;\n if (!token) throw new LlmError(`端点 ${endpoint.name} 未配置临时 LLM 凭证`);\n return new StaticCredentialProvider({\n kind: \"temporary-bearer\",\n headerName: \"authorization\",\n headerValue: `Bearer ${token}`,\n });\n }\n\n if (!endpoint.api_key) {\n throw new LlmError(`端点 ${endpoint.name} 未配置 api_key`);\n }\n\n return new StaticCredentialProvider(\n endpoint.protocol === \"anthropic-messages\"\n ? { kind: \"api-key\", headerName: \"x-api-key\", headerValue: endpoint.api_key }\n : {\n kind: \"api-key\",\n headerName: \"authorization\",\n headerValue: `Bearer ${endpoint.api_key}`,\n },\n );\n}\n\n/** 判断 provider 是否支持 callback 轮换(协议层 401 重试用) */\nexport function isRefreshable(provider: CredentialProvider): provider is XlyraCallbackCredentialProvider {\n return provider instanceof XlyraCallbackCredentialProvider;\n}\n","/**\n * 上游 HTTP 错误的脱敏摘要(docs §8.3/§12.1):\n * - 不回传完整响应体:只提取常见 JSON 形态里的 message 字段,截断到 200 字符;\n * - 已知秘密(token/api_key 等)若出现在消息里,一律替换为 ***;\n * - 非 JSON 响应体只回状态文本,不回原文。\n */\nimport type { ResolvedCredential } from \"./credential.js\";\n\nexport async function httpErrorSummary(res: Response, secrets: string[] = []): Promise<string> {\n const raw = await res.text().catch(() => \"\");\n let msg = \"\";\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n const j = parsed as { error?: { message?: unknown }; message?: unknown };\n const candidate = j.error?.message ?? j.message;\n if (typeof candidate === \"string\") msg = candidate;\n }\n } catch {\n // 非 JSON:不回传响应体原文\n }\n msg = msg.slice(0, 200);\n for (const secret of secrets) {\n if (secret) msg = msg.split(secret).join(\"***\");\n }\n return `请求失败(HTTP ${res.status}):${msg || res.statusText}`;\n}\n\n/**\n * 从凭证推导脱敏秘密集合:同时覆盖完整 headerValue(\"Bearer xxx\")与\n * 裸 token(上游错误消息通常不带 Bearer 前缀)。\n */\nexport function credentialSecrets(cred: ResolvedCredential): string[] {\n const bare = cred.headerValue.startsWith(\"Bearer \")\n ? cred.headerValue.slice(\"Bearer \".length)\n : cred.headerValue;\n return bare === cred.headerValue ? [cred.headerValue] : [cred.headerValue, bare];\n}\n","/**\n * 极简 SSE 解析器 —— 两套协议适配器共用。\n *\n * 覆盖 SSE 规范的常用子集:`event:` / 多行 `data:` 拼接 / `: comment`\n * 心跳行 / \\r\\n 与 \\n 换行 / OpenAI 的 `data: [DONE]` 哨兵。\n * 不依赖任何第三方库;输入是 fetch 响应的 body 流。\n */\n\nexport interface SseEvent {\n /** event 字段值;缺省为空串(OpenAI 系协议通常不写 event,靠 data 里的 type) */\n event: string;\n /** 多行 data 已按规范以 \\n 拼接 */\n data: string;\n}\n\nexport async function* parseSse(body: ReadableStream<Uint8Array>): AsyncGenerator<SseEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventName = \"\";\n let dataLines: string[] = [];\n\n const flush = (): SseEvent | null => {\n if (dataLines.length === 0) {\n eventName = \"\";\n return null;\n }\n const evt: SseEvent = { event: eventName, data: dataLines.join(\"\\n\") };\n eventName = \"\";\n dataLines = [];\n return evt;\n };\n\n const handleLine = function* (line: string): Generator<SseEvent> {\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1);\n if (line === \"\") {\n const evt = flush();\n if (evt) yield evt;\n return;\n }\n if (line.startsWith(\":\")) return; // 心跳/注释行\n const colon = line.indexOf(\":\");\n const field = colon === -1 ? line : line.slice(0, colon);\n // 规范:冒号后的一个前导空格要剥掉\n let value = colon === -1 ? \"\" : line.slice(colon + 1);\n if (value.startsWith(\" \")) value = value.slice(1);\n if (field === \"event\") eventName = value;\n else if (field === \"data\") dataLines.push(value);\n // id:/retry: 等字段当前协议均不需要,忽略\n };\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) !== -1) {\n const line = buffer.slice(0, nl);\n buffer = buffer.slice(nl + 1);\n yield* handleLine(line);\n }\n }\n // 流末尾可能残留未以空行收尾的事件\n if (buffer.length > 0) yield* handleLine(buffer);\n const tail = flush();\n if (tail) yield tail;\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * 流式 tool_call 归并器 —— 两个协议适配器共用。\n *\n * 两套协议的参数都是逐片增量(Responses 的 function_call_arguments.delta /\n * Anthropic 的 input_json_delta),适配器以各自的归并键(item_id / block\n * index)调用本类累积,end 时得到 raw_arguments 全量。\n *\n * 刻意不在增量阶段做 partial parse(避免 O(n²) 重复解析);end 时的\n * JSON.parse 失败也不报错——raw_arguments 保留原文,由 runner 的参数\n * 校验阶段统一报错回喂模型。\n */\nimport type { ToolCall } from \"./models.js\";\n\ninterface BufferEntry {\n id: string;\n name: string;\n raw: string;\n}\n\nexport class ToolCallBuffer {\n private readonly buffers = new Map<string, BufferEntry>();\n\n /** 名称确定的第一刻登记;返回仅含 id/name 的 ToolCall(供 toolcall_start 事件) */\n start(key: string, id: string, name: string): ToolCall {\n this.buffers.set(key, { id, name, raw: \"\" });\n return { id, name, raw_arguments: \"\" };\n }\n\n /** 追加参数分片;返回当前快照(供 toolcall_delta 事件携带归属信息) */\n append(key: string, delta: string): ToolCall | null {\n const entry = this.buffers.get(key);\n if (!entry) return null;\n entry.raw += delta;\n return { id: entry.id, name: entry.name, raw_arguments: entry.raw };\n }\n\n /** 结束归并;fullRaw 提供时以全量为准(Responses 的 .done 事件自带全量串) */\n finish(key: string, fullRaw?: string): ToolCall | null {\n const entry = this.buffers.get(key);\n if (!entry) return null;\n this.buffers.delete(key);\n return { id: entry.id, name: entry.name, raw_arguments: fullRaw ?? entry.raw };\n }\n\n /** 流异常终止时丢弃全部未完成归并 */\n clear(): void {\n this.buffers.clear();\n }\n\n get pendingCount(): number {\n return this.buffers.size;\n }\n}\n","/**\n * Anthropic Messages API 适配器。\n *\n * 按官方文档实现(https://docs.claude.com/en/api/messages-streaming):\n * - 请求:POST {base_url}/v1/messages,system 是顶层字段;assistant 的\n * tool_calls → tool_use content blocks;tool 结果并入 user 消息的\n * tool_result blocks;max_tokens 必填;\n * - 流式:content_block 状态机按 block index 归并;input_json_delta\n * 累积到 content_block_stop 才 parse(避免每片 partial parse 的 O(n²));\n * signature_delta 必须采集——评审定案 thinking 签名透传进历史,\n * 多轮工具往返要求带签名的 thinking block 原样回喂。\n *\n * 实现纪律(来自公开 issue 的已知坑):\n * - delta 类型与当前 block 类型不符 → 按流损坏处理,error 事件收尾,不猜;\n * - tool_result 必须与此前 assistant 的 tool_use 严格配对(runner 保证),\n * 否则 API 400。\n */\nimport { LlmError } from \"../errors.js\";\nimport { httpErrorSummary, credentialSecrets } from \"../http-error.js\";\nimport {\n isRefreshable,\n StaticCredentialProvider,\n type CredentialProvider,\n type ResolvedCredential,\n} from \"../credential.js\";\nimport { normalizeEffort, type ChatMessage, type ChatResponse, type ToolDefinition } from \"../models.js\";\nimport type { ChatRequest, LlmProtocol, StreamEvent } from \"../protocol.js\";\nimport type { AgentRunContext } from \"../router.js\";\nimport { parseSse } from \"../sse.js\";\nimport { ToolCallBuffer } from \"../stream-assembler.js\";\n\nexport interface MessagesEndpointOptions {\n baseUrl: string;\n /**\n * 统一凭证来源(推荐)。apiKey 是 direct 模式的简写,\n * 等价于 x-api-key: <apiKey> 的静态凭证。\n */\n credential?: CredentialProvider;\n apiKey?: string;\n providerName?: string;\n /** anthropic-version 头;默认官方当前版本 */\n apiVersion?: string;\n /** 测试注入用;默认全局 fetch */\n fetchImpl?: typeof fetch;\n}\n\ntype Json = Record<string, unknown>;\n\nconst DEFAULT_MAX_TOKENS = 8192;\n\n/** reasoning_effort → thinking budget(官方建议 budget ≥ 1024 且 < max_tokens) */\nconst THINKING_BUDGET = { low: 2048, medium: 8192, high: 24576, xhigh: 49152 } as const;\n\n/** 内部消息 → Anthropic messages 数组 + 顶层 system */\nexport function toAnthropicMessages(messages: ChatMessage[]): {\n system: string | undefined;\n messages: Json[];\n} {\n const systemParts: string[] = [];\n const out: Json[] = [];\n\n const flushToolResults = (pending: Json[]): void => {\n if (pending.length > 0) {\n // 连续的 tool 结果合并进同一条 user 消息(多个 tool_result block)\n out.push({ role: \"user\", content: pending.splice(0, pending.length) });\n }\n };\n\n const pendingToolResults: Json[] = [];\n for (const m of messages) {\n if (m.role === \"system\") {\n if (m.content) systemParts.push(m.content);\n continue;\n }\n if (m.role === \"tool\") {\n const block: Json = {\n type: \"tool_result\",\n tool_use_id: m.tool_call_id ?? \"\",\n content: m.content,\n };\n if (m.is_error) block.is_error = true;\n pendingToolResults.push(block);\n continue;\n }\n flushToolResults(pendingToolResults);\n if (m.role === \"user\") {\n out.push({ role: \"user\", content: m.content });\n continue;\n }\n // assistant:thinking(有签名才回喂)→ text → tool_use blocks\n const blocks: Json[] = [];\n if (m.thinking && m.thinking_signature) {\n blocks.push({ type: \"thinking\", thinking: m.thinking, signature: m.thinking_signature });\n }\n if (m.content) blocks.push({ type: \"text\", text: m.content });\n for (const tc of m.tool_calls ?? []) {\n blocks.push({ type: \"tool_use\", id: tc.id, name: tc.name, input: parseArgs(tc.raw_arguments) });\n }\n out.push({ role: \"assistant\", content: blocks.length ? blocks : [{ type: \"text\", text: \"\" }] });\n }\n flushToolResults(pendingToolResults);\n return { system: systemParts.length ? systemParts.join(\"\\n\\n\") : undefined, messages: out };\n}\n\nfunction parseArgs(raw: string): Json {\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as Json) : {};\n } catch {\n return {}; // 参数原文非法时给空对象:模型会在工具结果里收到校验错误并自行修正\n }\n}\n\nfunction toAnthropicTools(tools: ToolDefinition[]): Json[] {\n return tools.map((t) => ({ name: t.name, description: t.description, input_schema: t.parameters }));\n}\n\ntype BlockKind = \"text\" | \"thinking\" | \"tool_use\";\n\nexport class AnthropicMessagesProtocol implements LlmProtocol {\n readonly name = \"anthropic-messages\";\n private readonly baseUrl: string;\n private readonly credential: CredentialProvider;\n private readonly provider: string;\n private readonly apiVersion: string;\n private readonly fetchImpl: typeof fetch;\n private runContext: AgentRunContext | null = null;\n\n constructor(opts: MessagesEndpointOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n if (opts.credential) {\n this.credential = opts.credential;\n } else if (opts.apiKey) {\n this.credential = new StaticCredentialProvider({\n kind: \"api-key\",\n headerName: \"x-api-key\",\n headerValue: opts.apiKey,\n });\n } else {\n throw new LlmError(\"AnthropicMessagesProtocol 缺少凭证(credential 或 apiKey)\");\n }\n this.provider = opts.providerName ?? \"anthropic\";\n this.apiVersion = opts.apiVersion ?? \"2023-06-01\";\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n /** 更新 run 上下文:仅 xlyra-callback 凭证消费;静态凭证为 no-op */\n setRunContext(context: AgentRunContext): void {\n this.runContext = context;\n if (isRefreshable(this.credential)) this.credential.setRunContext(context);\n }\n\n /**\n * 请求开始时解析本次 run 的凭证:xlyra-callback 按 runId 定向取\n * (并发 run 各自独立),静态凭证直接返回。\n */\n private resolveRequestCredential(): Promise<ResolvedCredential> {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.getCredentialFor(this.runContext.runId);\n }\n return this.credential.getCredential();\n }\n\n /** 401 后仅当本地凭证已被主动续期轮换时返回新 token;401 本身不触发换票 */\n private rotatedRequestCredential(used: ResolvedCredential): ResolvedCredential | null {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.rotatedCredentialFor(this.runContext.runId, used);\n }\n return null;\n }\n\n async *chatStream(req: ChatRequest): AsyncIterable<StreamEvent> {\n const { system, messages } = toAnthropicMessages(req.messages);\n const maxTokens = req.settings.max_tokens ?? DEFAULT_MAX_TOKENS;\n const body: Json = { model: req.model, max_tokens: maxTokens, messages, stream: true };\n if (system) body.system = system;\n if (req.tools?.length) body.tools = toAnthropicTools(req.tools);\n if (req.settings.temperature !== undefined) body.temperature = req.settings.temperature;\n if (req.settings.reasoning_effort) {\n const budget = Math.min(THINKING_BUDGET[normalizeEffort(req.settings.reasoning_effort)], maxTokens - 1);\n if (budget >= 1024) body.thinking = { type: \"enabled\", budget_tokens: budget };\n }\n\n let cred;\n try {\n cred = await this.resolveRequestCredential();\n } catch (err) {\n // 凭证获取失败(如 callback 未签发):原文上抛语义,不归类为网络错误\n yield { type: \"error\", error: errMsg(err) };\n return;\n }\n\n const doFetch = (c: ResolvedCredential): Promise<Response> =>\n this.fetchImpl(`${this.baseUrl}/v1/messages`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n [c.headerName]: c.headerValue,\n \"anthropic-version\": this.apiVersion,\n },\n body: JSON.stringify(body),\n signal: req.signal ?? null,\n });\n\n let res: Response;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return; // 取消:静默结束,终态事件由编排层负责\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n\n // 401 有限重试(docs §8.2):仅当请求在途期间凭证已被主动续期轮换\n // (本地已有新 token)时用新 token 重试一次;401 本身不触发换票——\n // 无新 token 说明凭证被吊销或 run 已结束,直接终止当前 run\n if (res.status === 401 && isRefreshable(this.credential)) {\n await res.body?.cancel().catch(() => {}); // 释放连接再重试\n const rotated = this.rotatedRequestCredential(cred);\n if (!rotated) {\n yield {\n type: \"error\",\n error: \"xLyra LLM 调用凭证已被拒绝(token 已吊销或 run 已结束)(HTTP 401)\",\n };\n return;\n }\n cred = rotated;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n }\n\n if (!res.ok || !res.body) {\n yield { type: \"error\", error: await httpErrorSummary(res, credentialSecrets(cred)) };\n return;\n }\n\n // content_block 状态机:index → 当前 block 类别\n const blockKinds = new Map<number, BlockKind>();\n const calls = new ToolCallBuffer();\n const finishedCalls: import(\"../models.js\").ToolCall[] = [];\n let text = \"\";\n let thinking = \"\";\n let thinkingSignature: string | null = null;\n let stopReason: string | null = null;\n const usage = { input: 0, output: 0, cacheRead: 0 };\n let model = \"\";\n let sawTerminal = false;\n\n try {\n for await (const sse of parseSse(res.body)) {\n const evt = safeParse(sse.data);\n if (!evt) continue;\n const type = String(evt.type ?? \"\");\n\n if (type === \"message_start\") {\n const msg = (evt.message as Json) ?? {};\n model = String(msg.model ?? \"\");\n const u = (msg.usage as Json) ?? {};\n usage.input = Number(u.input_tokens ?? 0);\n usage.cacheRead = Number(u.cache_read_input_tokens ?? 0);\n } else if (type === \"content_block_start\") {\n const index = Number(evt.index ?? 0);\n const block = (evt.content_block as Json) ?? {};\n const kind = String(block.type ?? \"\") as BlockKind;\n blockKinds.set(index, kind);\n if (kind === \"tool_use\") {\n const tc = calls.start(String(index), String(block.id ?? \"\"), String(block.name ?? \"\"));\n yield { type: \"toolcall_start\", tool_call: tc };\n }\n } else if (type === \"content_block_delta\") {\n const index = Number(evt.index ?? 0);\n const delta = (evt.delta as Json) ?? {};\n const kind = blockKinds.get(index);\n const deltaType = String(delta.type ?? \"\");\n if (deltaType === \"text_delta\" && kind === \"text\") {\n const d = String(delta.text ?? \"\");\n text += d;\n yield { type: \"text_delta\", delta: d };\n } else if (deltaType === \"thinking_delta\" && kind === \"thinking\") {\n const d = String(delta.thinking ?? \"\");\n thinking += d;\n yield { type: \"thinking_delta\", delta: d };\n } else if (deltaType === \"signature_delta\" && kind === \"thinking\") {\n thinkingSignature = String(delta.signature ?? \"\") || thinkingSignature;\n } else if (deltaType === \"input_json_delta\" && kind === \"tool_use\") {\n const d = String(delta.partial_json ?? \"\");\n const tc = calls.append(String(index), d);\n if (tc) yield { type: \"toolcall_delta\", tool_call: tc, delta: d };\n } else if (deltaType) {\n // delta 类型与 block 类型不符 → 流损坏,不猜\n yield { type: \"error\", error: `流损坏:block ${index}(${kind})收到 ${deltaType}` };\n return;\n }\n } else if (type === \"content_block_stop\") {\n const index = Number(evt.index ?? 0);\n if (blockKinds.get(index) === \"tool_use\") {\n const tc = calls.finish(String(index));\n if (tc) {\n finishedCalls.push(tc);\n yield { type: \"toolcall_end\", tool_call: tc };\n }\n }\n blockKinds.delete(index);\n } else if (type === \"message_delta\") {\n stopReason = String((evt.delta as Json)?.stop_reason ?? \"\") || stopReason;\n usage.output = Number((evt.usage as Json)?.output_tokens ?? usage.output);\n } else if (type === \"message_stop\") {\n sawTerminal = true;\n yield {\n type: \"done\",\n response: {\n content: text,\n thinking: thinking || null,\n thinking_signature: thinkingSignature,\n tool_calls: finishedCalls,\n usage: {\n prompt_tokens: usage.input,\n completion_tokens: usage.output,\n total_tokens: usage.input + usage.output,\n cache_read_tokens: usage.cacheRead,\n },\n finish_reason: stopReason,\n model,\n provider: this.provider,\n },\n };\n return;\n } else if (type === \"error\") {\n const err = (evt.error as Json)?.message;\n yield { type: \"error\", error: `模型调用失败:${String(err ?? \"原因未知\")}` };\n return;\n }\n // ping 等其他事件忽略\n }\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `流读取失败:${errMsg(err)}` };\n return;\n }\n if (!sawTerminal) yield { type: \"error\", error: \"模型流异常终止,未返回结果\" };\n }\n}\n\nfunction safeParse(data: string): Json | null {\n try {\n return JSON.parse(data) as Json;\n } catch {\n return null;\n }\n}\n\nfunction errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","/**\n * OpenAI Responses API 适配器。\n *\n * 按官方文档实现(https://platform.openai.com/docs/api-reference/responses-streaming):\n * - 请求:POST {base_url}/responses,system → instructions,历史 → input items\n * (message / function_call / function_call_output),stream: true;\n * - 流式:tool_call 以 output_item.added(function_call) 确定 id/name,\n * function_call_arguments.delta 逐片累积、.done 给全量;\n * response.completed / failed / incomplete 为终态。\n *\n * 终态怪癖处理(继承 MovieClaw 兼容层经验):\n * - response.incomplete:已累积出完整 tool_calls 时按 done 处理(让循环继续),\n * 否则报 error;\n * - 流中途断开(无终态事件)→ error,不静默。\n */\nimport { LlmError } from \"../errors.js\";\nimport { httpErrorSummary, credentialSecrets } from \"../http-error.js\";\nimport {\n isRefreshable,\n StaticCredentialProvider,\n type CredentialProvider,\n type ResolvedCredential,\n} from \"../credential.js\";\nimport { normalizeEffort, type ChatMessage, type ChatResponse, type ToolDefinition } from \"../models.js\";\nimport { emptyUsage } from \"../models.js\";\nimport type { ChatRequest, LlmProtocol, StreamEvent } from \"../protocol.js\";\nimport type { AgentRunContext } from \"../router.js\";\nimport { parseSse } from \"../sse.js\";\nimport { ToolCallBuffer } from \"../stream-assembler.js\";\n\nexport interface ResponsesEndpointOptions {\n baseUrl: string;\n /**\n * 统一凭证来源(推荐)。apiKey 是 direct 模式的简写,\n * 等价于 Authorization: Bearer <apiKey> 的静态凭证。\n */\n credential?: CredentialProvider;\n apiKey?: string;\n /** 展示与日志用的端点名 */\n providerName?: string;\n /** 测试注入用;默认全局 fetch */\n fetchImpl?: typeof fetch;\n}\n\ntype Json = Record<string, unknown>;\n\n/** 内部消息 → Responses input items(一条内部消息可能展开成多个 item) */\nexport function toResponsesInput(messages: ChatMessage[]): {\n instructions: string | undefined;\n input: Json[];\n} {\n const instructions: string[] = [];\n const input: Json[] = [];\n for (const m of messages) {\n if (m.role === \"system\") {\n if (m.content) instructions.push(m.content);\n continue;\n }\n if (m.role === \"user\") {\n input.push({ type: \"message\", role: \"user\", content: [{ type: \"input_text\", text: m.content }] });\n continue;\n }\n if (m.role === \"assistant\") {\n if (m.content) {\n input.push({ type: \"message\", role: \"assistant\", content: [{ type: \"output_text\", text: m.content }] });\n }\n for (const tc of m.tool_calls ?? []) {\n input.push({ type: \"function_call\", call_id: tc.id, name: tc.name, arguments: tc.raw_arguments });\n }\n continue;\n }\n // tool 结果 → function_call_output\n input.push({ type: \"function_call_output\", call_id: m.tool_call_id ?? \"\", output: m.content });\n }\n return { instructions: instructions.length ? instructions.join(\"\\n\\n\") : undefined, input };\n}\n\nfunction toResponsesTools(tools: ToolDefinition[]): Json[] {\n return tools.map((t) => ({\n type: \"function\",\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n }));\n}\n\n/** 从 response.completed 的完整响应体提取定稿 ChatResponse */\nfunction responseFromCompleted(response: Json, provider: string): ChatResponse {\n let content = \"\";\n let thinking = \"\";\n const toolCalls: ChatResponse[\"tool_calls\"] = [];\n for (const item of (response.output as Json[] | undefined) ?? []) {\n if (item.type === \"message\") {\n for (const part of (item.content as Json[] | undefined) ?? []) {\n if (part.type === \"output_text\" && typeof part.text === \"string\") content += part.text;\n }\n } else if (item.type === \"reasoning\") {\n for (const part of (item.summary as Json[] | undefined) ?? []) {\n if (part.type === \"summary_text\" && typeof part.text === \"string\") {\n thinking += (thinking ? \"\\n\" : \"\") + part.text;\n }\n }\n } else if (item.type === \"function_call\") {\n toolCalls.push({\n id: String(item.call_id ?? item.id ?? \"\"),\n name: String(item.name ?? \"\"),\n raw_arguments: String(item.arguments ?? \"\"),\n });\n }\n }\n const usage = (response.usage as Json | undefined) ?? {};\n const cached = (usage.input_tokens_details as Json | undefined)?.cached_tokens;\n return {\n content,\n thinking: thinking || null,\n thinking_signature: null, // Responses 的思考摘要无签名概念\n tool_calls: toolCalls,\n usage: {\n prompt_tokens: Number(usage.input_tokens ?? 0),\n completion_tokens: Number(usage.output_tokens ?? 0),\n total_tokens: Number(usage.total_tokens ?? 0),\n cache_read_tokens: Number(cached ?? 0),\n },\n finish_reason: (response.status as string | undefined) ?? \"completed\",\n model: String(response.model ?? \"\"),\n provider,\n };\n}\n\nexport class OpenAIResponsesProtocol implements LlmProtocol {\n readonly name = \"openai-responses\";\n private readonly baseUrl: string;\n private readonly credential: CredentialProvider;\n private readonly provider: string;\n private readonly fetchImpl: typeof fetch;\n private runContext: AgentRunContext | null = null;\n\n constructor(opts: ResponsesEndpointOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n if (opts.credential) {\n this.credential = opts.credential;\n } else if (opts.apiKey) {\n this.credential = new StaticCredentialProvider({\n kind: \"api-key\",\n headerName: \"authorization\",\n headerValue: `Bearer ${opts.apiKey}`,\n });\n } else {\n throw new LlmError(\"OpenAIResponsesProtocol 缺少凭证(credential 或 apiKey)\");\n }\n this.provider = opts.providerName ?? \"openai\";\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n /** 更新 run 上下文:仅 xlyra-callback 凭证消费;静态凭证为 no-op */\n setRunContext(context: AgentRunContext): void {\n this.runContext = context;\n if (isRefreshable(this.credential)) this.credential.setRunContext(context);\n }\n\n /**\n * 请求开始时解析本次 run 的凭证:xlyra-callback 按 runId 定向取\n * (并发 run 各自独立),静态凭证直接返回。\n */\n private resolveRequestCredential(): Promise<ResolvedCredential> {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.getCredentialFor(this.runContext.runId);\n }\n return this.credential.getCredential();\n }\n\n /** 401 后仅当本地凭证已被主动续期轮换时返回新 token;401 本身不触发换票 */\n private rotatedRequestCredential(used: ResolvedCredential): ResolvedCredential | null {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.rotatedCredentialFor(this.runContext.runId, used);\n }\n return null;\n }\n\n async *chatStream(req: ChatRequest): AsyncIterable<StreamEvent> {\n const { instructions, input } = toResponsesInput(req.messages);\n const body: Json = { model: req.model, input, stream: true };\n if (instructions) body.instructions = instructions;\n if (req.tools?.length) body.tools = toResponsesTools(req.tools);\n if (req.settings.max_tokens) body.max_output_tokens = req.settings.max_tokens;\n if (req.settings.temperature !== undefined) body.temperature = req.settings.temperature;\n if (req.settings.reasoning_effort) {\n body.reasoning = { effort: normalizeEffort(req.settings.reasoning_effort), summary: \"auto\" };\n body.include = [\"reasoning.encrypted_content\"];\n }\n\n let cred;\n try {\n cred = await this.resolveRequestCredential();\n } catch (err) {\n // 凭证获取失败(如 callback 未签发):原文上抛语义,不归类为网络错误\n yield { type: \"error\", error: errMsg(err) };\n return;\n }\n\n const doFetch = (c: ResolvedCredential): Promise<Response> =>\n this.fetchImpl(`${this.baseUrl}/responses`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n [c.headerName]: c.headerValue,\n },\n body: JSON.stringify(body),\n signal: req.signal ?? null,\n });\n\n let res: Response;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return; // 取消:静默结束,终态事件由编排层负责\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n\n // 401 有限重试(docs §8.2):仅当请求在途期间凭证已被主动续期轮换\n // (本地已有新 token)时用新 token 重试一次;401 本身不触发换票——\n // 无新 token 说明凭证被吊销或 run 已结束,直接终止当前 run\n if (res.status === 401 && isRefreshable(this.credential)) {\n await res.body?.cancel().catch(() => {}); // 释放连接再重试\n const rotated = this.rotatedRequestCredential(cred);\n if (!rotated) {\n yield {\n type: \"error\",\n error: \"xLyra LLM 调用凭证已被拒绝(token 已吊销或 run 已结束)(HTTP 401)\",\n };\n return;\n }\n cred = rotated;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n }\n\n if (!res.ok || !res.body) {\n yield { type: \"error\", error: await httpErrorSummary(res, credentialSecrets(cred)) };\n return;\n }\n\n const calls = new ToolCallBuffer();\n // item_id → call_id:delta 事件只带 item_id,事件里的 ToolCall.id 用 call_id\n // (function_call_output 回喂以 call_id 关联)\n const callIdByItem = new Map<string, string>();\n let streamedText = \"\";\n let streamedThinking = \"\";\n let doneCalls: ChatResponse[\"tool_calls\"] = [];\n\n try {\n for await (const sse of parseSse(res.body)) {\n if (sse.data === \"[DONE]\") break;\n const evt = safeParse(sse.data);\n if (!evt) continue;\n const type = String(evt.type ?? \"\");\n\n if (type === \"response.output_item.added\") {\n const item = evt.item as Json | undefined;\n if (item?.type === \"function_call\") {\n const itemId = String(item.id ?? \"\");\n const callId = String(item.call_id ?? itemId);\n callIdByItem.set(itemId, callId);\n const tc = calls.start(itemId, callId, String(item.name ?? \"\"));\n yield { type: \"toolcall_start\", tool_call: tc };\n }\n } else if (type === \"response.function_call_arguments.delta\") {\n const itemId = String(evt.item_id ?? \"\");\n const tc = calls.append(itemId, String(evt.delta ?? \"\"));\n if (tc) yield { type: \"toolcall_delta\", tool_call: tc, delta: String(evt.delta ?? \"\") };\n } else if (type === \"response.function_call_arguments.done\") {\n const itemId = String(evt.item_id ?? \"\");\n const tc = calls.finish(itemId, String(evt.arguments ?? \"\"));\n if (tc) {\n doneCalls.push(tc);\n yield { type: \"toolcall_end\", tool_call: tc };\n }\n } else if (type === \"response.output_item.done\") {\n // 兜底:arguments.done 缺失时,function_call item 完结也带全量 arguments\n const item = evt.item as Json | undefined;\n const itemId = String(item?.id ?? \"\");\n if (item?.type === \"function_call\" && itemId && callIdByItem.has(itemId)) {\n const tc = calls.finish(itemId, String(item.arguments ?? \"\"));\n if (tc) {\n doneCalls.push(tc);\n yield { type: \"toolcall_end\", tool_call: tc };\n }\n }\n } else if (type === \"response.output_text.delta\") {\n const delta = String(evt.delta ?? \"\");\n streamedText += delta;\n yield { type: \"text_delta\", delta };\n } else if (type === \"response.reasoning_summary_text.delta\") {\n const delta = String(evt.delta ?? \"\");\n streamedThinking += delta;\n yield { type: \"thinking_delta\", delta };\n } else if (type === \"response.completed\") {\n const response = responseFromCompleted((evt.response as Json) ?? {}, this.provider);\n // 部分网关(含 xLyra 代理链)的 completed 事件只带元数据不带完整 output:\n // 正文/思考/工具调用回落到流式累积值,否则定稿消息会空 content 落盘\n yield {\n type: \"done\",\n response: {\n ...response,\n content: response.content || streamedText,\n thinking: response.thinking ?? (streamedThinking || null),\n tool_calls: response.tool_calls.length > 0 ? response.tool_calls : doneCalls,\n },\n };\n return;\n } else if (type === \"response.incomplete\") {\n // 已累积出完整 tool_calls → 按 done 处理让循环继续;否则报错\n if (doneCalls.length > 0) {\n const response = responseFromCompleted((evt.response as Json) ?? {}, this.provider);\n yield {\n type: \"done\",\n response: {\n ...response,\n content: response.content || streamedText,\n thinking: response.thinking ?? (streamedThinking || null),\n tool_calls: doneCalls,\n },\n };\n } else {\n const detail = ((evt.response as Json)?.incomplete_details as Json)?.reason;\n yield { type: \"error\", error: `响应不完整${detail ? `(${String(detail)})` : \"\"},请重试` };\n }\n return;\n } else if (type === \"response.failed\") {\n const err = ((evt.response as Json)?.error as Json)?.message;\n yield { type: \"error\", error: `模型调用失败:${String(err ?? \"原因未知\")}` };\n return;\n } else if (type === \"error\") {\n yield { type: \"error\", error: `模型调用失败:${String(evt.message ?? \"原因未知\")}` };\n return;\n }\n // 其余事件(created / in_progress / output_text.done / ping 等)忽略\n }\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `流读取失败:${errMsg(err)}` };\n return;\n }\n // 流结束但没有任何终态事件——视为异常断流\n yield { type: \"error\", error: \"模型流异常终止,未返回结果\" };\n }\n}\n\nfunction safeParse(data: string): Json | null {\n try {\n return JSON.parse(data) as Json;\n } catch {\n return null;\n }\n}\n\nfunction errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nexport { LlmError };\n","/**\n * 端点配置与模型解析 —— 刻意简化的路由层(不做多供应商目录体系)。\n *\n * 模型引用写法:\n * - \"端点名/模型id\":显式指定端点(如 \"anthropic/claude-sonnet-4-5\");\n * - 裸 \"模型id\":在全部端点中查找,唯一命中即用,多命中报错;\n * - 空串:第一个端点的 default_model。\n *\n * context_window 优先取端点配置;未配置时回落内置常识表;都未命中返回\n * undefined——自动压缩随之停用(宁放行到供应商报错,不瞎猜预算)。\n */\nimport { LlmError } from \"./errors.js\";\nimport { resolveCredentialProvider } from \"./credential.js\";\nimport type { LlmProtocol } from \"./protocol.js\";\nimport { AnthropicMessagesProtocol } from \"./protocols/messages.js\";\nimport { OpenAIResponsesProtocol } from \"./protocols/responses.js\";\n\n/**\n * 端点凭证模式:\n * - direct:原有 base_url + api_key 直连 provider;\n * - remote-xlyra:调用 xLyra 内部 LLM 网关,使用临时凭证。\n * 配置输入可省略 mode,schema 解析后自动补为 \"direct\"(见 server/config.ts)。\n */\nexport type EndpointMode = \"direct\" | \"remote-xlyra\";\n\n/** 固定临时 token(Bearer) */\nexport interface TemporaryBearerCredential {\n type: \"temporary-bearer\";\n token: string;\n}\n\n/** xLyra credential callback:按需签发/轮换短期 token(见 docs 第 8、9 章) */\nexport interface XlyraCallbackCredential {\n type: \"xlyra-callback\";\n url: string;\n}\n\nexport type EndpointCredential = TemporaryBearerCredential | XlyraCallbackCredential;\n\nexport interface EndpointConfig {\n name: string;\n protocol: \"openai-responses\" | \"anthropic-messages\";\n mode: EndpointMode;\n base_url: string;\n api_key?: string;\n credential?: EndpointCredential;\n /** 可用模型表:key 为模型 id;context_window 可选 */\n models?: Record<string, { context_window?: number }>;\n default_model?: string;\n}\n\n/**\n * 一次 Agent run 的标识上下文:credential callback 所需。\n * sessionId/runId 由 agent 自身生成(事实源在 agent),agentInstanceId 由\n * 部署方/runner 在启动 run 时注入;只携带标识 ID,不携带会话内容。\n */\nexport interface AgentRunContext {\n agentInstanceId: string;\n sessionId: string;\n runId: string;\n model?: string;\n}\n\nexport interface ResolvedModel {\n endpoint: EndpointConfig;\n protocol: LlmProtocol;\n /** 端点内的模型 id(已剥离端点前缀) */\n modelId: string;\n contextWindow: number | undefined;\n}\n\n/** 内置 context window 常识表(前缀匹配,先到先得;保守取值,可被配置覆盖) */\nconst BUILTIN_CONTEXT_WINDOWS: Array<[prefix: string, window: number]> = [\n [\"claude-\", 200_000],\n [\"gpt-4o\", 128_000],\n [\"gpt-4.1\", 1_047_576],\n [\"gpt-5\", 400_000],\n [\"o1\", 200_000],\n [\"o3\", 200_000],\n [\"o4\", 200_000],\n];\n\nexport function builtinContextWindow(modelId: string): number | undefined {\n for (const [prefix, win] of BUILTIN_CONTEXT_WINDOWS) {\n if (modelId.startsWith(prefix)) return win;\n }\n return undefined;\n}\n\nexport class EndpointResolver {\n private readonly endpoints: EndpointConfig[];\n private readonly protocols = new Map<string, LlmProtocol>();\n\n constructor(endpoints: EndpointConfig[]) {\n if (endpoints.length === 0) throw new LlmError(\"未配置任何模型端点\");\n this.endpoints = endpoints;\n }\n\n resolve(model: string): ResolvedModel {\n let endpoint: EndpointConfig | undefined;\n let modelId: string;\n\n if (!model) {\n // 构造函数已保证 endpoints 非空\n endpoint = this.endpoints[0]!;\n modelId = endpoint.default_model ?? \"\";\n if (!modelId) throw new LlmError(`端点 ${endpoint.name} 未配置默认模型`);\n } else if (model.includes(\"/\")) {\n const [name, ...rest] = model.split(\"/\");\n endpoint = this.endpoints.find((e) => e.name === name);\n if (endpoint) {\n modelId = rest.join(\"/\");\n } else {\n modelId = model;\n const hits = this.endpoints.filter((e) => e.models && model in e.models);\n if (hits.length > 1) {\n throw new LlmError(`模型 ${model} 在多个端点中均有配置,请用「端点名/模型id」显式指定`);\n }\n endpoint = hits[0] ?? this.endpoints[0]!;\n }\n } else {\n modelId = model;\n const hits = this.endpoints.filter((e) => e.models && model in e.models);\n if (hits.length > 1) {\n throw new LlmError(`模型 ${model} 在多个端点中均有配置,请用「端点名/模型id」显式指定`);\n }\n // 裸模型 id 且无端点声明:回落到第一个端点(兼容官方端点的自由模型名)\n endpoint = hits[0] ?? this.endpoints[0]!;\n }\n\n return {\n endpoint,\n protocol: this.protocolFor(endpoint),\n modelId,\n contextWindow: endpoint.models?.[modelId]?.context_window ?? builtinContextWindow(modelId),\n };\n }\n\n private protocolFor(endpoint: EndpointConfig): LlmProtocol {\n let protocol = this.protocols.get(endpoint.name);\n if (!protocol) {\n const opts = {\n baseUrl: endpoint.base_url,\n credential: resolveCredentialProvider(endpoint),\n providerName: endpoint.name,\n };\n protocol =\n endpoint.protocol === \"anthropic-messages\"\n ? new AnthropicMessagesProtocol(opts)\n : new OpenAIResponsesProtocol(opts);\n this.protocols.set(endpoint.name, protocol);\n }\n return protocol;\n }\n}\n","/**\n * 工具参数校验 —— 调用前对 raw_arguments 做 JSON Schema 校验。\n *\n * 覆盖我们工具声明用到的 JSON Schema 子集(object / properties / required /\n * string / number / integer / boolean / array / enum / default),不引 ajv:\n * 我们的 schema 全部来自自家工具的 Zod 定义,结构可控。将来支持外部工具\n * 声明时,可在此替换为完整 JSON Schema 校验器,接口不变。\n *\n * 校验失败返回中文错误文本(喂回模型自行修正),不抛异常。\n */\nimport type { ToolDefinition } from \"./models.js\";\nimport type { ToolCall } from \"./models.js\";\n\nexport interface ValidatedArgs {\n args: Record<string, unknown> | null;\n error: string | null;\n}\n\nexport function validateToolCall(\n definitions: ToolDefinition[],\n call: ToolCall,\n): ValidatedArgs {\n const def = definitions.find((d) => d.name === call.name);\n if (!def) {\n return { args: null, error: `工具不存在:${call.name};可用工具:${definitions.map((d) => d.name).join(\"、\")}` };\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(call.raw_arguments || \"{}\");\n } catch {\n return {\n args: null,\n error: `工具 ${call.name} 的参数不是合法 JSON,请修正后重试。原文:${call.raw_arguments.slice(0, 200)}`,\n };\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { args: null, error: `工具 ${call.name} 的参数必须是 JSON object` };\n }\n const err = validateAgainstSchema(parsed as Record<string, unknown>, def.parameters);\n if (err) return { args: null, error: `工具 ${call.name} 参数校验失败:${err}` };\n return { args: parsed as Record<string, unknown>, error: null };\n}\n\nfunction validateAgainstSchema(\n args: Record<string, unknown>,\n schema: Record<string, unknown>,\n): string | null {\n // required 语义修正:Zod 的 .default() 字段会被 z.toJSONSchema 同时列入\n // required 与 properties[x].default——带默认值的参数模型省略是合法的,\n // 官方 API 也不要求它出现。这里以「required 且无 default」为真正必填。\n const properties = (schema.properties as Record<string, Record<string, unknown>> | undefined) ?? {};\n const required = ((schema.required as string[] | undefined) ?? []).filter(\n (key) => properties[key]?.default === undefined,\n );\n for (const key of required) {\n if (!(key in args) || args[key] === undefined || args[key] === null) {\n return `缺少必填参数 ${key}`;\n }\n }\n for (const [key, value] of Object.entries(args)) {\n const prop = properties[key];\n if (!prop) continue; // additionalProperties 放行\n const expected = prop.type as string | undefined;\n if (value === undefined || !expected) continue;\n const ok =\n (expected === \"string\" && typeof value === \"string\") ||\n (expected === \"number\" && typeof value === \"number\") ||\n (expected === \"integer\" && typeof value === \"number\" && Number.isInteger(value)) ||\n (expected === \"boolean\" && typeof value === \"boolean\") ||\n (expected === \"array\" && Array.isArray(value)) ||\n (expected === \"object\" && typeof value === \"object\" && !Array.isArray(value));\n if (!ok) return `参数 ${key} 类型应为 ${expected}`;\n const enumValues = prop.enum as unknown[] | undefined;\n if (enumValues && !enumValues.includes(value)) {\n return `参数 ${key} 取值须为 ${enumValues.join(\" / \")}`;\n }\n }\n return null;\n}\n","/**\n * Agent 执行过程的事件协议 —— 前后端之间的「执行进度语言」。\n *\n * 设计原则(移植自 MovieClaw,对齐 pi 的 agent 事件思路):\n * 1. 事件类型面向「渲染语义」而非模型协议:调用方拿到事件就知道往哪个区域\n * 画什么,不需要理解底层 LLM 流的细节;\n * 2. 增量事件(*_delta)负责打字机效果,结束事件(agent_done)带完整结果,\n * 断线重连/中途加入也能靠终态恢复;\n * 3. 工具调用三段式:名称确定即发 tool_call_start,参数逐片发 tool_call_delta,\n * 参数完整后发 tool_call——调用方从名称确定的一刻起就能展示进度。\n *\n * 事件序列(每一步 = 一次模型调用):\n * agent_start → [ (thinking_delta|text_delta)*\n * → (tool_call_start → tool_call_delta* → tool_call)*\n * → tool_result* ]×N\n * → agent_done | agent_error | agent_cancelled\n * (任意安全点可插 context_compacted)\n */\nimport { z } from \"zod\";\nimport {\n chatMessageSchema,\n modelSettingsSchema,\n tokenUsageSchema,\n toolCallSchema,\n} from \"../llm/models.js\";\n\nexport const agentStartParamsSchema = z.object({\n /** 用户的任务描述(作为本轮 user 消息) */\n input: z.string(),\n /** 是否把 input 追加为新的 user 消息;提权续跑沿用 history 中的原始输入 */\n include_input: z.boolean().default(true),\n /** 多轮历史(可选):追加在 system 之后、本轮 input 之前 */\n history: z.array(chatMessageSchema).default([]),\n /** 模型引用(\"端点名/模型id\" 或裸模型 id);空串 = 第一个端点的默认模型 */\n model: z.string().default(\"\"),\n /** 覆盖默认系统提示词(缺省用 prompts.buildSystemPrompt()) */\n system_prompt: z.string().nullish(),\n settings: modelSettingsSchema.default({}),\n});\nexport type AgentStartParams = z.input<typeof agentStartParamsSchema>;\n\nexport const agentToolResultSchema = z.object({\n tool_call_id: z.string(),\n name: z.string(),\n /** 喂回模型的文本(事件里截断到 2000 字符,完整版进对话上下文) */\n output: z.string(),\n is_error: z.boolean().default(false),\n elapsed_ms: z.number().default(0),\n});\nexport type AgentToolResult = z.infer<typeof agentToolResultSchema>;\n\nexport const agentCompactionSchema = z.object({\n summary: z.string(),\n tokens_before: z.number(),\n tokens_after: z.number(),\n});\nexport type AgentCompaction = z.infer<typeof agentCompactionSchema>;\n\n/** 提权请求(escalation_request 事件载荷):工具访问越界路径时发起,\n * 前端展示并等待用户确认;确认后服务端登记授权并重发消息续跑 */\nexport const agentEscalationSchema = z.object({\n /** 本次提权请求的唯一 id(确认接口的定位参数) */\n escalation_id: z.string(),\n /** 用户/模型给出的原始路径(展示用) */\n requested_path: z.string(),\n /** 沙箱解析后的绝对路径(确认后登记的授权键) */\n resolved_path: z.string(),\n /** 触发提权的工具名(如 list/read) */\n tool_name: z.string(),\n resource_type: z.enum([\"path\", \"command\"]).default(\"path\"),\n requested_command: z.array(z.string()).nullish(),\n /** 当前工作区根(展示给用户看边界在哪) */\n workdir: z.string(),\n});\nexport type AgentEscalation = z.infer<typeof agentEscalationSchema>;\n\nexport const agentDoneSchema = z.object({\n /** 最后一步的产出(loop 的最终答复) */\n text: z.string().nullish(),\n thinking: z.string().nullish(),\n finish_reason: z.string().nullish(),\n /** 全部步骤的累计用量 */\n usage: tokenUsageSchema.default({ prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, cache_read_tokens: 0 }),\n /** 模型调用次数 */\n steps: z.number().default(1),\n model: z.string().default(\"\"),\n provider: z.string().default(\"\"),\n elapsed_ms: z.number().default(0),\n});\nexport type AgentDone = z.infer<typeof agentDoneSchema>;\n\n/** Agent 事件:type 决定哪些字段有值;作为 SSE 载荷时 type 同时用作 SSE 的 event 名 */\nexport const agentEventSchema = z.object({\n type: z.enum([\n \"agent_start\",\n \"thinking_delta\",\n \"text_delta\",\n \"tool_call_start\",\n \"tool_call_delta\",\n \"tool_call\",\n \"tool_result\",\n \"context_compacted\",\n \"escalation_request\",\n \"agent_done\",\n \"agent_error\",\n \"agent_cancelled\",\n ]),\n /** 本次运行的唯一 id,一次 start 产生的所有事件共享同一个值 */\n run_id: z.string(),\n delta: z.string().nullish(),\n tool_call: toolCallSchema.nullish(),\n tool_call_id: z.string().nullish(),\n tool_result: agentToolResultSchema.nullish(),\n compaction: agentCompactionSchema.nullish(),\n /** escalation_request 事件:路径提权请求 */\n escalation: agentEscalationSchema.nullish(),\n /** agent_start:实际路由到的端点名与模型 id */\n provider: z.string().nullish(),\n model: z.string().nullish(),\n /** agent_done 的终态载荷 */\n result: agentDoneSchema.nullish(),\n /** agent_error 的中文错误说明 */\n error: z.string().nullish(),\n /** agent_cancelled 的取消原因:escalation 表示提权协商暂停(等待用户确认),\n * 空/其它值表示用户主动停止或异常中断 */\n reason: z.string().nullish(),\n});\nexport type AgentEvent = z.infer<typeof agentEventSchema>;\n\nexport type AgentEventType = AgentEvent[\"type\"];\n\nexport const TERMINAL_EVENT_TYPES: ReadonlySet<AgentEventType> = new Set([\n \"agent_done\",\n \"agent_error\",\n \"agent_cancelled\",\n]);\n","/**\n * Agent 系统提示词。\n *\n * 设计原则(移植自 MovieClaw,对齐 Claude Code 的提示词架构):\n * - 正文只写通用行为准则(运行方式 / 并行调用 / 工作循环 / 回复风格),\n * 不含任何领域词汇——领域语义由各工具的 description 和运行时环境段承载;\n * - 环境事实(日期等)随时会变,由 buildSystemPrompt 在每次运行时拼接,\n * 绝不写死在正文里。\n */\n\n/** 压缩摘要消息的固定前缀——重建历史时靠它识别「这条 user 消息是压缩摘要」,\n * 再次压缩时旧摘要不会被当成用户原话保留(codex SUMMARY_PREFIX 同款机制) */\nexport const SUMMARY_PREFIX = \"【上下文压缩摘要】此前的对话已被压缩,以下是交接摘要:\";\n\n/** 交接摘要指令(codex SUMMARIZATION_PROMPT 的中文对齐版)。作为一条普通\n * user 消息追加到全量历史末尾发起压缩请求,不是系统提示词。 */\nexport const COMPACT_PROMPT = `\\\n你正在执行一次上下文压缩。请为将要接手这段对话的另一个 LLM 写一份交接摘要。\n\n摘要必须包含:\n- 任务目标与当前进度、已做出的关键决定\n- 用户提出的约束、偏好和重要背景\n- 尚未完成的事项(明确的下一步)\n- 继续工作必须保留的关键数据(路径、ID、编号、查询结果要点等)\n\n保持简洁、结构化,以帮助下一个 LLM 无缝接续工作为唯一目标。只输出摘要正文。\n`;\n\nconst SYSTEM_PROMPT_TEMPLATE = `\\\n你是 {agentName},一个友好的智能助理。{persona}\n\n# 运行方式\n- 你的文字输出以 Markdown 渲染在会话页,工具调用过程用户全程可见。执行中不要旁白「我现在要去做什么」——工具调用本身就是过程展示。\n- 需要事实时永远先调用工具查证,一律以工具返回为准,绝不凭印象臆断。\n- 文件与工作状态都具有时效性;每次用户询问此类信息时,必须在当前轮次重新调用工具查询最新数据,不要相信或复用历史对话中已经获取的结果。\n- 工具报错或被拒绝,不要原样重发:读懂原因,修正参数或换一条路。\n\n# 工具使用规则\n- 工具列表会随当前会话配置动态注入;只能调用列表中实际存在的工具,不要臆造工具名或参数。\n- 先用 search 定位代码或文本,再用 read 查看必要上下文;不要为寻找内容递归读取大量文件。\n- 修改已有文件优先使用 edit;需要同时修改多个文件时使用 apply_patch;只有明确需要整体替换时才使用 write。\n- 修改后如果当前会话提供 exec_command,应运行最相关的格式化、类型检查或测试,并根据结果继续修正。\n- exec_command 使用 argv 数组而不是 shell 字符串;命令会话返回 session_id 时,用 write_stdin 继续读取,不要重复启动同一个命令。\n- exec_command 与 write_stdin 即使需要授权也会出现在工具目录中;调用后若收到提权请求,应等待用户确认,不要声称当前没有命令工具。\n- 任何工具被拒绝、越界或取消时,先理解返回原因;不要通过换写法绕过权限边界。\n\n# 并行工具调用\n需要多项互不依赖的信息时,在同一轮里一次性发起全部调用,而不是一轮一个。独立的检索、查询、状态读取都应合并到同一次回复中——运行时会安全并发执行连续的只读调用并按原顺序返回结果,合并调用避免了每多一轮就把整个对话重新发送一遍的开销。\n只有当后一个调用确实依赖前一个的结果时才分轮串行。拿不准且调用之间相互独立时,一律合并。\n\n# 工作循环\n以「思考 → 行动 → 观察」持续循环,直到任务完成:\n- 每次观察结果后重新评估:推进了就走下一步;没推进就换一种方式再试,而不是原样重试。\n- 坚持到底,不把做了一半的任务交回用户。同一障碍连续两次绕不过去,才停下向用户说明卡点。\n- 允许停下提问的只有两种情况:缺少只有用户能做的决定,或动作超出了本次的明确授权。\n\n# 回复风格\n- 全程中文。最终答复先结论、后关键依据,不复述执行过程。\n- 找不到就说找不到,绝不虚构任何数据。\n- 简短优先:一句能说清的不用三句。\n- 友好、有温度:像一个长期陪伴用户的真人伙伴那样交流,在恰当的时候给用户情绪价值。可以适度使用表情符号,但别泛滥。\n`;\n\nexport interface SystemPromptOptions {\n /** 助理名称,默认 \"xlyra 助理\" */\n agentName?: string;\n /** 一句话人设(拼在首段),默认空 */\n persona?: string;\n /** 运行时环境段(每行一个事实,拼在「# 环境」下) */\n extraEnvironment?: string;\n /** 当前会话实际暴露给模型的工具;由 Runner 动态注入,避免静态提示漂移。 */\n availableTools?: Array<Pick<import(\"../llm/models.js\").ToolDefinition, \"name\" | \"description\">>;\n contextFragments?: string[];\n}\n\nexport function buildAvailableToolsPrompt(\n availableTools: Array<Pick<import(\"../llm/models.js\").ToolDefinition, \"name\" | \"description\">>,\n): string {\n if (availableTools.length === 0) {\n return \"# 当前会话可用工具\\n- 当前会话没有可用工具;不要尝试调用工具。\";\n }\n return [\n \"# 当前会话可用工具\",\n ...availableTools.map((tool) => `- ${tool.name}:${tool.description.replace(/\\s+/g, \" \").trim()}`),\n ].join(\"\\n\");\n}\n\nexport function buildSystemPrompt(opts: SystemPromptOptions = {}): string {\n const body = SYSTEM_PROMPT_TEMPLATE.replace(\"{agentName}\", opts.agentName ?? \"xlyra 助理\").replace(\n \"{persona}\",\n opts.persona ? ` ${opts.persona}` : \"\",\n );\n const lines = [body, \"# 环境\", `- 当前日期:${new Date().toISOString().slice(0, 10)}`];\n if (opts.extraEnvironment) lines.push(opts.extraEnvironment);\n for (const fragment of opts.contextFragments ?? []) {\n if (fragment.trim()) lines.push(fragment);\n }\n lines.push(buildAvailableToolsPrompt(opts.availableTools ?? []));\n return lines.join(\"\\n\");\n}\n","/**\n * 可在上下文压缩后保留的耐久上下文块。\n *\n * 工具可通过 ToolHandlerResult.metadata.retainedContext 声明;同时建议在\n * content 中写入 START/END 标记,以便跨 run 重建历史时仅凭消息正文识别\n * (JSONL 不持久化 metadata)。\n */\nimport type { ChatMessage } from \"../llm/models.js\";\n\nexport const RETAINED_CONTEXT_START = \"【保留上下文开始】\";\nexport const RETAINED_CONTEXT_END = \"【保留上下文结束】\";\n/** 压缩后重新注入的耐久上下文总预算,独立于用户原话预算。 */\nexport const RETAINED_CONTEXT_TOKEN_BUDGET = 20_000;\n\nconst SKILL_CONTEXT_KEY = /^skill:([a-z0-9]+(?:-[a-z0-9]+)*)$/;\n\nexport interface RetainedContextBlock {\n /** 去重键,例如 skill:code-review */\n key: string;\n /** 压缩后重新注入的完整文本(通常已含标记) */\n content: string;\n}\n\nexport function isRetainedContextBlock(value: unknown): value is RetainedContextBlock {\n if (!value || typeof value !== \"object\") return false;\n const block = value as Record<string, unknown>;\n return typeof block.key === \"string\" && block.key.length > 0\n && typeof block.content === \"string\" && block.content.length > 0;\n}\n\nfunction isSkillRetainedContextBlock(block: RetainedContextBlock): boolean {\n if (!SKILL_CONTEXT_KEY.test(block.key)) return false;\n const skillName = block.key.slice(\"skill:\".length);\n return block.content.includes(`<skill_content name=\"${skillName}\">`)\n && block.content.includes(\"</skill_content>\");\n}\n\nexport function extractRetainedContextFromMetadata(\n metadata: Record<string, unknown> | undefined,\n): RetainedContextBlock | null {\n if (!metadata) return null;\n return isRetainedContextBlock(metadata.retainedContext) ? metadata.retainedContext : null;\n}\n\n/**\n * 从已持久化消息正文中提取 load_skill 生成的保留块。\n * 只接受 skill:<name> + 完整 skill_content 结构,普通用户文本不能凭前缀被永久保留。\n */\nexport function extractRetainedContextsFromMessages(\n messages: ChatMessage[],\n): RetainedContextBlock[] {\n const found = new Map<string, RetainedContextBlock>();\n const pattern = new RegExp(\n `${escapeRegExp(RETAINED_CONTEXT_START)}\\\\s+(skill:[a-z0-9]+(?:-[a-z0-9]+)*)\\\\r?\\\\n([\\\\s\\\\S]*?)\\\\r?\\\\n${escapeRegExp(RETAINED_CONTEXT_END)}`,\n \"g\",\n );\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i]!;\n // retained 块在持久化里是 tool 结果(load_skill 回执),压缩重建时作为\n // system 注入(见 retainedContextsAsMessages),两种角色都要识别\n if (message.role !== \"tool\" && message.role !== \"user\" && message.role !== \"system\") continue;\n for (const match of (message.content ?? \"\").matchAll(pattern)) {\n const key = match[1]!;\n const body = match[0]!;\n const block = { key, content: body };\n if (!found.has(key) && isRetainedContextBlock(block) && isSkillRetainedContextBlock(block)) {\n found.set(key, block);\n }\n }\n }\n return [...found.values()].reverse();\n}\n\nexport function mergeRetainedContexts(\n ...groups: Array<Iterable<RetainedContextBlock>>\n): RetainedContextBlock[] {\n const map = new Map<string, RetainedContextBlock>();\n for (const group of groups) {\n for (const block of group) {\n if (\n isRetainedContextBlock(block)\n && (!block.key.startsWith(\"skill:\") || isSkillRetainedContextBlock(block))\n && !map.has(block.key)\n ) {\n map.set(block.key, block);\n }\n }\n }\n return [...map.values()];\n}\n\nfunction approximateTokens(block: RetainedContextBlock): number {\n return Math.max(1, Math.ceil(Buffer.byteLength(block.content, \"utf-8\") / 4));\n}\n\n/** 把保留块作为独立 system 消息插入历史,并限制总量;优先保留最近激活的 skill。\n * 用 system 而非 user:skill 是系统能力指令,不应与用户原话同角色——两个协议\n * 适配器(responses → instructions、messages → 顶层 system)都会把 system\n * 聚合到最前,与主 system prompt 合并,不存在位置约束问题。 */\nexport function retainedContextsAsMessages(\n blocks: RetainedContextBlock[],\n maxTokens = RETAINED_CONTEXT_TOKEN_BUDGET,\n): ChatMessage[] {\n const selected: RetainedContextBlock[] = [];\n let remaining = Math.max(0, maxTokens);\n for (let i = blocks.length - 1; i >= 0; i -= 1) {\n const block = blocks[i]!;\n const tokens = approximateTokens(block);\n if (tokens > remaining) continue;\n selected.push(block);\n remaining -= tokens;\n }\n selected.reverse();\n return selected.map((block) => ({\n role: \"system\" as const,\n content: block.content.startsWith(RETAINED_CONTEXT_START)\n ? block.content\n : `${RETAINED_CONTEXT_START} ${block.key}\\n${block.content}\\n${RETAINED_CONTEXT_END}`,\n }));\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","/**\n * 上下文压缩 —— codex 本地压缩策略的移植(经 MovieClaw 验证的取舍)。\n *\n * 核心思路:\n * 1. 触发以服务端上报的 usage 为准:每步响应带回真实 prompt_tokens,无需引入\n * tokenizer;仅在没有服务端数据的场合(续聊冷启动、尚未发送的工具结果)用\n * 「UTF-8 字节数 ≈ 4 字节/token」的启发式补估;\n * 2. 压缩就是一次普通模型调用:把交接摘要指令作为 user 消息追加到全量历史\n * 末尾,不带任何工具定义——模型只能输出文本,天然保证这一轮只写摘要;\n * 3. 重建历史「宽进严出」:生成摘要时模型看得到全部现场;压缩落地后只保留\n * 「预算内最近的用户原话 + 摘要」,工具轨迹全部丢弃——用户原话永不经过\n * 有损摘要,防多次压缩后忘记原始意图;\n * 4. 失败一律降级:压缩失败只记日志、返回 null,绝不中断正在进行的运行。\n */\nimport type { ChatMessage, ModelSettings } from \"../llm/models.js\";\nimport type { LlmProtocol } from \"../llm/protocol.js\";\nimport { COMPACT_PROMPT, SUMMARY_PREFIX } from \"./prompts.js\";\nimport {\n extractRetainedContextsFromMessages,\n retainedContextsAsMessages,\n} from \"./retained-context.js\";\n\n/** 自动压缩水位线:上下文占用 ≥ 窗口的 90% 时触发(codex 同款比例) */\nexport const COMPACT_TRIGGER_RATIO = 0.9;\n\n/** 重建历史时保留近期用户消息的 token 预算(codex 同款 20k) */\nexport const RETAINED_USER_TOKEN_BUDGET = 20_000;\n\n/** 无 tokenizer 时的估算系数:约 4 字节(UTF-8)≈ 1 token。对中文同样适用——\n * 一个汉字 3 字节 ≈ 0.75 token,与主流 tokenizer 的量级一致,偏保守即可 */\nexport const APPROX_BYTES_PER_TOKEN = 4;\n\nexport interface CompactionResult {\n /** 交接摘要文本 */\n summary: string;\n /** 重建后的历史(不含 system,system 每次运行重拼) */\n replacement_history: ChatMessage[];\n /** 压缩前后的估算 token 数(bytes/4 启发式,展示与观测用,非精确值) */\n tokens_before: number;\n tokens_after: number;\n}\n\nexport function estimateTokens(target: ChatMessage[] | ChatMessage | string): number {\n if (typeof target === \"string\") {\n return Math.floor(Buffer.byteLength(target, \"utf-8\") / APPROX_BYTES_PER_TOKEN);\n }\n if (Array.isArray(target)) {\n return target.reduce((sum, m) => sum + estimateTokens(m), 0);\n }\n let total = Buffer.byteLength(target.content ?? \"\", \"utf-8\");\n for (const tc of target.tool_calls ?? []) {\n total += Buffer.byteLength(tc.name, \"utf-8\");\n total += Buffer.byteLength(tc.raw_arguments, \"utf-8\");\n }\n return Math.floor(total / APPROX_BYTES_PER_TOKEN);\n}\n\n/** 是否达到自动压缩水位线;模型未声明窗口时永不自动压缩(调用方负责日志) */\nexport function shouldCompact(contextTokens: number, contextWindow: number | undefined): boolean {\n if (!contextWindow) return false;\n return contextTokens >= Math.floor(contextWindow * COMPACT_TRIGGER_RATIO);\n}\n\n/** 识别历史里由压缩产生的摘要消息(user 角色 + 固定前缀) */\nexport function isSummaryMessage(message: ChatMessage): boolean {\n return message.role === \"user\" && (message.content ?? \"\").startsWith(SUMMARY_PREFIX);\n}\n\n/** 识别压缩后重新注入的合法保留上下文块(不是用户原话);system 角色注入 */\nexport function isRetainedContextMessage(message: ChatMessage): boolean {\n return (message.role === \"user\" || message.role === \"system\")\n && extractRetainedContextsFromMessages([message]).length > 0;\n}\n\n/** 中部截断:头尾各留一半预算,中间以标记替代(用户消息开头是诉求、结尾是\n * 最新补充,头尾信息密度最高)。按字节预算切,落在多字节字符中间时由\n * Buffer.toString 自动退回合法边界。 */\nfunction truncateMiddle(text: string, maxTokens: number): string {\n const budgetBytes = maxTokens * APPROX_BYTES_PER_TOKEN;\n const data = Buffer.from(text, \"utf-8\");\n if (data.length <= budgetBytes) return text;\n const half = Math.floor(budgetBytes / 2);\n const head = data.subarray(0, half).toString(\"utf-8\");\n const tail = data.subarray(data.length - half).toString(\"utf-8\");\n const omitted = Math.floor((data.length - budgetBytes) / APPROX_BYTES_PER_TOKEN);\n return `${head}\\n…(中间约 ${omitted} token 已截断)…\\n${tail}`;\n}\n\n/** 按 codex 策略重建历史:预算内逆序保留的用户原话 + 保留上下文 + 摘要收尾。\n * - 只保留真实 user 消息(排除 system / 旧压缩摘要 / 保留上下文块),从最新往旧装入预算,\n * 装不下的最旧一条中部截断;\n * - assistant / 普通 tool / 思考内容全部丢弃,信息由摘要承载;\n * - 带耐久标记的保留上下文(如已激活 skill)会重新注入,避免压缩后丢失;\n * - 摘要带固定前缀、作为最后一条 user 消息。 */\nexport function buildReplacementHistory(\n messages: ChatMessage[],\n summary: string,\n): ChatMessage[] {\n const retainedUsers: ChatMessage[] = [];\n let remaining = RETAINED_USER_TOKEN_BUDGET;\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i]!;\n if (message.role !== \"user\" || isSummaryMessage(message) || isRetainedContextMessage(message)) {\n continue;\n }\n if (remaining <= 0) break;\n const tokens = estimateTokens(message);\n if (tokens <= remaining) {\n retainedUsers.push(message);\n remaining -= tokens;\n } else {\n retainedUsers.push({ role: \"user\", content: truncateMiddle(message.content ?? \"\", remaining) });\n break;\n }\n }\n retainedUsers.reverse();\n const retainedContexts = retainedContextsAsMessages(extractRetainedContextsFromMessages(messages));\n return [\n ...retainedUsers,\n ...retainedContexts,\n { role: \"user\", content: `${SUMMARY_PREFIX}\\n${summary}` },\n ];\n}\n\n/**\n * 执行一次压缩:全量历史 + 摘要指令 → 模型写交接摘要 → 重建历史。\n *\n * messages 是完整现场(含 system 与全部工具往返);返回的\n * replacement_history 不含 system。任何失败(流错误、异常、空摘要)都\n * 返回 null,由调用方决定降级方式——本函数绝不抛异常。\n */\nexport async function compact(\n protocol: LlmProtocol,\n model: string,\n messages: ChatMessage[],\n settings: ModelSettings,\n): Promise<CompactionResult | null> {\n let summary: string | null = null;\n try {\n for await (const event of protocol.chatStream({\n model,\n // 摘要指令是普通 user 消息;不带工具定义,模型只能输出文本\n messages: [...messages, { role: \"user\", content: COMPACT_PROMPT }],\n settings,\n })) {\n if (event.type === \"error\") {\n console.warn(`上下文压缩失败(模型调用出错):${event.error}`);\n return null;\n }\n if (event.type === \"done\") summary = (event.response.content ?? \"\").trim();\n }\n } catch (err) {\n console.warn(`上下文压缩失败(请求异常):${err instanceof Error ? err.message : err}`);\n return null;\n }\n if (!summary) {\n console.warn(\"上下文压缩失败:模型返回了空摘要\");\n return null;\n }\n const replacement = buildReplacementHistory(messages, summary);\n const system = messages.slice(0, 1).filter((m) => m.role === \"system\");\n return {\n summary,\n replacement_history: replacement,\n tokens_before: estimateTokens(messages),\n tokens_after: estimateTokens([...system, ...replacement]),\n };\n}\n","/**\n * Agent 会话的 JSONL 持久化存储(事实源)。\n *\n * 设计定案(移植自 MovieClaw,调研 pi / codex / Claude Code 后的共识 + 取舍):\n *\n * 1. 一个会话一个 append-only JSONL 文件:首行是会话头,之后每行一条\n * 消息 entry。历史行永不改写——中断、重启都只会追加。唯一例外是\n * discardFromUserMessage(retry 的历史替换),见该方法说明;\n * 2. 只落定稿消息,不落流式 delta:文件里的 message 就是内部规范模型原样\n * 格式(ChatMessage),resume 重建上下文零转换;\n * 3. entry 带 uuid / parent_uuid:当前是纯线性链(parent 永远指向上一条),\n * 字段先留好,将来做历史分支时无需迁移文件格式;\n * 4. 读取容错:进程崩溃可能留下半行,逐行解析时静默跳过坏行并计数,\n * 绝不让整个会话打不开;\n * 5. 压缩行(type: \"compaction\"):含摘要与完整替换历史,buildHistory 从\n * 最后一条压缩行起重建(codex 的 Compacted 记录同款思路)。压缩前的\n * 原始消息仍完整留在文件里(回放展示用),但不再进入模型上下文。\n *\n * 存储位置默认 ~/.xlyra-agent/sessions(评审定案),构造参数可覆盖。\n */\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { chatMessageSchema, tokenUsageSchema, type ChatMessage } from \"../llm/models.js\";\nimport type { CompactionResult } from \"./compaction.js\";\n\n/** 文件格式版本;结构变化时 +1,读取端按版本做迁移\n * v3:新增 type=\"escalation\" 的提权请求行(读端向后兼容 v1/v2) */\nexport const SESSION_FORMAT_VERSION = 3;\n\n/** 会话标题 / 最后提示预览的截断长度 */\nexport const PREVIEW_MAX_CHARS = 80;\n\n/** 默认数据根目录(~/.xlyra-agent),sessions 与 index.json 均在其下 */\nexport function defaultDataDir(): string {\n return path.join(os.homedir(), \".xlyra-agent\");\n}\n\nexport function defaultSessionsDir(): string {\n return path.join(defaultDataDir(), \"sessions\");\n}\n\nconst sessionHeaderSchema = z.object({\n type: z.literal(\"session\").default(\"session\"),\n version: z.number().default(SESSION_FORMAT_VERSION),\n session_id: z.string(),\n created_at: z.string(),\n});\nexport type SessionHeader = z.infer<typeof sessionHeaderSchema>;\n\nconst sessionMessageEntrySchema = z.object({\n type: z.literal(\"message\").default(\"message\"),\n uuid: z.string(),\n parent_uuid: z.string().nullish(),\n timestamp: z.string(),\n message: chatMessageSchema,\n /** 以下仅 assistant 消息携带(运行元数据,不属于 message 本身,放信封层) */\n model: z.string().nullish(),\n usage: tokenUsageSchema.nullish(),\n finish_reason: z.string().nullish(),\n});\nexport type SessionMessageEntry = z.infer<typeof sessionMessageEntrySchema>;\n\nconst sessionCompactionEntrySchema = z.object({\n type: z.literal(\"compaction\").default(\"compaction\"),\n uuid: z.string(),\n parent_uuid: z.string().nullish(),\n timestamp: z.string(),\n summary: z.string(),\n replacement_history: z.array(chatMessageSchema),\n tokens_before: z.number().nullish(),\n tokens_after: z.number().nullish(),\n});\nexport type SessionCompactionEntry = z.infer<typeof sessionCompactionEntrySchema>;\n\n/** 提权请求行:越界访问的协商记录(回放时前端据此渲染确认卡片)。\n * granted=null 待确认;true 已授权;false 已拒绝 */\nconst sessionEscalationEntrySchema = z.object({\n type: z.literal(\"escalation\").default(\"escalation\"),\n uuid: z.string(),\n parent_uuid: z.string().nullish(),\n timestamp: z.string(),\n requested_path: z.string(),\n resolved_path: z.string(),\n tool_name: z.string(),\n resource_type: z.enum([\"path\", \"command\"]).default(\"path\"),\n requested_command: z.array(z.string()).nullish(),\n /** 旧记录可能省略待确认状态;读取时统一规范化为 null。 */\n granted: z.boolean().nullish().default(null),\n});\nexport type SessionEscalationEntry = z.infer<typeof sessionEscalationEntrySchema>;\n\nexport type SessionEntry = SessionMessageEntry | SessionCompactionEntry | SessionEscalationEntry;\n\nexport interface SessionSummary {\n session_id: string;\n created_at: string;\n entry_count: number;\n leaf_uuid: string | null;\n /** 首条 user 消息的截断文本;作为无自定义标题时的会话标题 */\n title: string | null;\n /** 最后一条 user 消息的截断文本 */\n last_prompt: string | null;\n last_timestamp: string;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction entryUuid(): string {\n return crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n}\n\nexport function isMessageEntry(e: SessionEntry): e is SessionMessageEntry {\n return e.type === \"message\";\n}\n\nexport function isCompactionEntry(e: SessionEntry): e is SessionCompactionEntry {\n return e.type === \"compaction\";\n}\n\nexport function isEscalationEntry(e: SessionEntry): e is SessionEscalationEntry {\n return e.type === \"escalation\";\n}\n\nfunction lastCompactionIndex(entries: SessionEntry[]): number {\n for (let i = entries.length - 1; i >= 0; i--) {\n if (isCompactionEntry(entries[i]!)) return i;\n }\n return -1;\n}\n\n/** 最后一条压缩行之后的消息(无压缩行时即全部消息) */\nfunction messagesAfterLastCompaction(entries: SessionEntry[]): ChatMessage[] {\n const last = lastCompactionIndex(entries);\n return entries.slice(last + 1).filter(isMessageEntry).map((e) => e.message);\n}\n\nexport class AgentSessionStore {\n private readonly root: string;\n /** session_id → 最后一条 entry 的 uuid(避免每次 append 都重读文件) */\n private readonly leafCache = new Map<string, string | null>();\n\n constructor(root?: string) {\n this.root = path.resolve(root ?? defaultSessionsDir());\n }\n\n get rootDir(): string {\n return this.root;\n }\n\n pathOf(sessionId: string): string {\n return path.join(this.root, `${sessionId}.jsonl`);\n }\n\n exists(sessionId: string): boolean {\n return fs.existsSync(this.pathOf(sessionId));\n }\n\n // ------------------------------------------------------------------\n // 写入\n // ------------------------------------------------------------------\n\n /** 新建会话文件并写入头行,返回头信息 */\n create(sessionId?: string): SessionHeader {\n const header: SessionHeader = {\n type: \"session\",\n version: SESSION_FORMAT_VERSION,\n session_id: sessionId ?? crypto.randomUUID().replaceAll(\"-\", \"\"),\n created_at: nowIso(),\n };\n fs.mkdirSync(this.root, { recursive: true });\n // wx:会话 id 冲突(几乎不可能)时宁可报错也不覆盖已有文件\n fs.writeFileSync(this.pathOf(header.session_id), JSON.stringify(header) + \"\\n\", { flag: \"wx\" });\n this.leafCache.set(header.session_id, null);\n return header;\n }\n\n /** 追加一条定稿消息,自动接到当前链尾,返回写入的 entry */\n append(\n sessionId: string,\n message: ChatMessage,\n meta?: { model?: string; usage?: z.infer<typeof tokenUsageSchema>; finish_reason?: string },\n ): SessionMessageEntry {\n const parent = this.currentLeaf(sessionId);\n const entry: SessionMessageEntry = {\n type: \"message\",\n uuid: entryUuid(),\n parent_uuid: parent,\n timestamp: nowIso(),\n message,\n model: meta?.model ?? null,\n usage: meta?.usage ?? null,\n finish_reason: meta?.finish_reason ?? null,\n };\n this.appendLine(sessionId, stripNulls(entry));\n this.leafCache.set(sessionId, entry.uuid);\n return entry;\n }\n\n /** 追加一条压缩行,与 append 同款接到当前链尾(parent 链线性穿过压缩行) */\n appendCompaction(sessionId: string, result: CompactionResult): SessionCompactionEntry {\n const parent = this.currentLeaf(sessionId);\n const entry: SessionCompactionEntry = {\n type: \"compaction\",\n uuid: entryUuid(),\n parent_uuid: parent,\n timestamp: nowIso(),\n summary: result.summary,\n replacement_history: result.replacement_history,\n tokens_before: result.tokens_before,\n tokens_after: result.tokens_after,\n };\n this.appendLine(sessionId, stripNulls(entry));\n this.leafCache.set(sessionId, entry.uuid);\n return entry;\n }\n\n /** 追加一条提权请求行(granted=null 待确认) */\n appendEscalation(\n sessionId: string,\n info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type?: \"path\" | \"command\";\n requested_command?: string[];\n },\n ): SessionEscalationEntry {\n const parent = this.currentLeaf(sessionId);\n const entry: SessionEscalationEntry = {\n type: \"escalation\",\n uuid: info.escalation_id,\n parent_uuid: parent,\n timestamp: nowIso(),\n requested_path: info.requested_path,\n resolved_path: info.resolved_path,\n tool_name: info.tool_name,\n resource_type: info.resource_type ?? \"path\",\n requested_command: info.requested_command,\n granted: null,\n };\n this.appendLine(sessionId, stripNulls(entry));\n this.leafCache.set(sessionId, entry.uuid);\n return entry;\n }\n\n /** 标记提权请求的确认结果(granted=true 授权 / false 拒绝)。\n * 这是 append-only 原则的第二个例外(另一个是 discardFromUserMessage):\n * 提权行的 granted 字段需要就地更新,否则确认状态无法在回放时保留。\n * 实现上仍是整文件原子重写(tmp + rename),与 discard 同款安全保证。 */\n resolveEscalation(sessionId: string, escalationId: string, granted: boolean): boolean {\n const { header, entries } = this.read(sessionId);\n const index = entries.findIndex((e) => isEscalationEntry(e) && e.uuid === escalationId);\n if (index === -1) return false;\n const target = entries[index]!;\n if (!isEscalationEntry(target)) return false;\n entries[index] = { ...target, granted };\n const filePath = this.pathOf(sessionId);\n const tmp = `${filePath}.tmp`;\n const lines = [JSON.stringify(header), ...entries.map((e) => JSON.stringify(stripNulls(e)))];\n fs.writeFileSync(tmp, lines.join(\"\\n\") + \"\\n\");\n fs.renameSync(tmp, filePath);\n return true;\n }\n\n /**\n * 中断收尾:给没有结果的 tool_call 补写错误回执,返回补写条数。\n *\n * 保证文件里 assistant 的 tool_calls 与 tool 消息任何时刻都配对完整,\n * resume 直接回喂 API 不需要修复逻辑(在写入侧一次做对)。\n * 只检查最后一条压缩行之后的消息:更早的往返已被压缩挡在上下文之外,\n * 给死上下文补回执毫无意义。\n */\n sealPendingToolCalls(sessionId: string, tone: \"interrupted\" | \"awaiting_authorization\" = \"interrupted\"): number {\n const { entries } = this.read(sessionId);\n const messages = messagesAfterLastCompaction(entries);\n const answered = new Set(\n messages.filter((m) => m.role === \"tool\").map((m) => m.tool_call_id),\n );\n // 提权暂停不是失败:回执用中性语义,回放时不会把这一步标红\n const receipt = tone === \"awaiting_authorization\"\n ? { content: \"等待用户授权,工具暂停执行。\", is_error: false }\n : { content: \"操作已被中断,工具未执行完成。\", is_error: true };\n let sealed = 0;\n for (const message of messages) {\n for (const tc of message.tool_calls ?? []) {\n if (answered.has(tc.id)) continue;\n this.append(sessionId, {\n role: \"tool\",\n content: receipt.content,\n tool_call_id: tc.id,\n name: tc.name,\n is_error: receipt.is_error,\n });\n sealed += 1;\n }\n }\n return sealed;\n }\n\n /**\n * 删除指定 user message 及其之后的全部 entry,返回删除条数。\n *\n * 这是本模块唯一改写历史行的方法,与「append-only」约定相悖,属于刻意的\n * 例外:用户要的就是「这些记录不该再存在」。整文件重写,写临时文件后\n * rename 原子换入:中途崩溃要么旧文件完好、要么新文件完整。\n * 只允许从 user message 切:从 assistant/tool 中间切会留下没有回执的\n * tool_call,重建出的上下文喂回模型直接 400。\n */\n discardFromUserMessage(sessionId: string, messageId: string): number {\n const { header, entries } = this.read(sessionId);\n const index = entries.findIndex((e) => e.uuid === messageId);\n if (index === -1) throw new Error(\"会话中没有这条记录,可能已被改写\");\n const target = entries[index]!;\n if (!isMessageEntry(target) || target.message.role !== \"user\") {\n throw new Error(\"只能重试用户消息\");\n }\n const kept = entries.slice(0, index);\n const filePath = this.pathOf(sessionId);\n const tmp = `${filePath}.tmp`;\n const lines = [JSON.stringify(header), ...kept.map((e) => JSON.stringify(stripNulls(e)))];\n fs.writeFileSync(tmp, lines.join(\"\\n\") + \"\\n\");\n fs.renameSync(tmp, filePath);\n this.leafCache.set(sessionId, kept.length > 0 ? kept[kept.length - 1]!.uuid : null);\n return entries.length - kept.length;\n }\n\n /** 删除会话文件(幂等) */\n delete(sessionId: string): void {\n fs.rmSync(this.pathOf(sessionId), { force: true });\n this.leafCache.delete(sessionId);\n }\n\n // ------------------------------------------------------------------\n // 读取\n // ------------------------------------------------------------------\n\n /** 读取整个会话(头 + 全部 entry,含压缩行),坏行静默跳过 */\n read(sessionId: string): { header: SessionHeader; entries: SessionEntry[]; badLines: number } {\n const filePath = this.pathOf(sessionId);\n if (!fs.existsSync(filePath)) throw new Error(\"会话不存在或转录文件已被删除\");\n const lines = fs.readFileSync(filePath, \"utf-8\").split(\"\\n\");\n let header: SessionHeader | null = null;\n const entries: SessionEntry[] = [];\n let bad = 0;\n for (const [lineNo, raw] of lines.entries()) {\n const line = raw.trim();\n if (!line) continue;\n if (lineNo === 0) {\n header = sessionHeaderSchema.parse(JSON.parse(line));\n continue;\n }\n try {\n const parsed: unknown = JSON.parse(line);\n const type = (parsed as { type?: string }).type;\n entries.push(\n type === \"compaction\"\n ? sessionCompactionEntrySchema.parse(parsed)\n : type === \"escalation\"\n ? sessionEscalationEntrySchema.parse(parsed)\n : sessionMessageEntrySchema.parse(parsed),\n );\n } catch {\n bad += 1;\n }\n }\n if (!header) throw new Error(\"会话文件为空或头记录损坏\");\n if (bad > 0) {\n console.warn(`会话文件存在 ${bad} 行无法解析的记录,已跳过(可能来自异常退出):${filePath}`);\n }\n return { header, entries, badLines: bad };\n }\n\n /**\n * 把会话重建成模型上下文消息列表(resume 喂回模型用)。\n * 有压缩行时,从最后一条压缩行的替换历史起步、只追加其后的增量消息;\n * system 提示词不入库(随代码版本演进),由 runner 每次运行时重新拼装。\n */\n buildHistory(sessionId: string): ChatMessage[] {\n const { entries } = this.read(sessionId);\n const last = lastCompactionIndex(entries);\n if (last < 0) return entries.filter(isMessageEntry).map((e) => e.message);\n const compaction = entries[last] as SessionCompactionEntry;\n return [\n ...compaction.replacement_history,\n ...entries.slice(last + 1).filter(isMessageEntry).map((e) => e.message),\n ];\n }\n\n /**\n * 重建提权中断前的上下文:保留原始 user 输入,但丢弃被中断的\n * assistant/tool 往返,授权后由 runner 从原输入继续推理。\n */\n buildHistoryBeforeEscalation(sessionId: string, escalationId: string): ChatMessage[] {\n const { entries } = this.read(sessionId);\n const escalationIndex = entries.findIndex(\n (entry) => isEscalationEntry(entry) && entry.uuid === escalationId,\n );\n if (escalationIndex < 0) return this.buildHistory(sessionId);\n const escalation = entries[escalationIndex]!;\n const assistantIndex = entries.findIndex(\n (entry) => entry.uuid === escalation.parent_uuid && isMessageEntry(entry)\n && entry.message.role === \"assistant\",\n );\n const cut = assistantIndex >= 0 ? assistantIndex : escalationIndex;\n const last = lastCompactionIndex(entries);\n if (last >= 0 && last < cut) {\n const compaction = entries[last] as SessionCompactionEntry;\n return [\n ...compaction.replacement_history,\n ...entries.slice(last + 1, cut).filter(isMessageEntry).map((e) => e.message),\n ];\n }\n return entries.slice(0, cut).filter(isMessageEntry).map((e) => e.message);\n }\n\n /** 扫描单个会话文件生成索引摘要 */\n summarize(sessionId: string): SessionSummary {\n const { header, entries } = this.read(sessionId);\n const userTexts = entries\n .filter(isMessageEntry)\n .filter((e) => e.message.role === \"user\" && (e.message.content ?? \"\").trim())\n .map((e) => (e.message.content ?? \"\").trim());\n const last = entries[entries.length - 1];\n return {\n session_id: header.session_id,\n created_at: header.created_at,\n entry_count: entries.length,\n leaf_uuid: last?.uuid ?? null,\n title: userTexts[0]?.slice(0, PREVIEW_MAX_CHARS) ?? null,\n last_prompt: userTexts[userTexts.length - 1]?.slice(0, PREVIEW_MAX_CHARS) ?? null,\n last_timestamp: last?.timestamp ?? header.created_at,\n };\n }\n\n /** 遍历目录下全部会话文件生成摘要(索引整体重建用;单文件损坏只跳过) */\n scanAll(): SessionSummary[] {\n if (!fs.existsSync(this.root)) return [];\n const summaries: SessionSummary[] = [];\n for (const name of fs.readdirSync(this.root).sort()) {\n if (!name.endsWith(\".jsonl\")) continue;\n const sessionId = name.slice(0, -\".jsonl\".length);\n try {\n summaries.push(this.summarize(sessionId));\n } catch (err) {\n console.warn(`会话文件无法解析,重建索引时已跳过:${name}(${err instanceof Error ? err.message : err})`);\n }\n }\n return summaries;\n }\n\n // ------------------------------------------------------------------\n\n private currentLeaf(sessionId: string): string | null {\n if (!this.leafCache.has(sessionId)) {\n const { entries } = this.read(sessionId);\n this.leafCache.set(sessionId, entries[entries.length - 1]?.uuid ?? null);\n }\n return this.leafCache.get(sessionId) ?? null;\n }\n\n private appendLine(sessionId: string, entry: SessionEntry): void {\n const filePath = this.pathOf(sessionId);\n if (!fs.existsSync(filePath)) throw new Error(\"会话不存在或转录文件已被删除\");\n fs.appendFileSync(filePath, JSON.stringify(entry) + \"\\n\");\n }\n}\n\n/** JSONL 序列化前去 null 字段(与 MovieClaw 的 exclude_none 对齐,文件更紧凑) */\nfunction stripNulls<T>(obj: T): T {\n return JSON.parse(\n JSON.stringify(obj, (_key, value: unknown) => (value === null || value === undefined ? undefined : value)),\n ) as T;\n}\n","/**\n * AgentRunner —— Agent loop 执行器。\n *\n * 循环语义(移植自 MovieClaw runner.py,设计要点逐条保留):\n * - 每一步 = 一次流式模型调用;模型输出的工具调用**以内容为准**判断是否\n * 继续循环——finish_reason 只作参考,因为兼容端点存在「stop 但带调用」\n * 「tool_calls 但数组为空」两类在案怪癖;\n * - 有工具调用 → 顺序执行每一个(参数先过 JSON Schema 校验),结果作为\n * tool 消息回喂,进入下一步;无工具调用 → STOP,正常结束;\n * - 工具的校验失败与执行异常都不中断循环:错误文本作为失败结果回喂,\n * 让模型自行修正;\n * - maxSteps(默认 200)防失控;错误一律以 agent_error 事件收尾,不抛异常。\n *\n * 取消语义(与编排层的分工):\n * - runner 接受外部 AbortSignal;signal 触发后本生成器尽快、安静地结束,\n * **不落终态事件**——agent_cancelled 由编排层在 abort 之前先落\n * (RunRegistry.cancel),保证订阅者永远先看到终态。\n */\nimport crypto from \"node:crypto\";\nimport type { ChatMessage, ChatResponse, TokenUsage } from \"../llm/models.js\";\nimport { addUsage, chatMessageSchema, emptyUsage, modelSettingsSchema, responseToMessage } from \"../llm/models.js\";\nimport type { LlmProtocol } from \"../llm/protocol.js\";\nimport { LlmError } from \"../llm/errors.js\";\nimport type { EndpointResolver } from \"../llm/router.js\";\nimport { validateToolCall } from \"../llm/validate.js\";\nimport type { AgentTool } from \"../tools/types.js\";\nimport { truncateMiddle } from \"../tools/types.js\";\nimport type { CompactionResult } from \"./compaction.js\";\nimport { compact, estimateTokens, shouldCompact } from \"./compaction.js\";\nimport { EscalationRequiredError } from \"./escalation.js\";\nimport type { AgentDone, AgentEvent, AgentStartParams, AgentToolResult } from \"./events.js\";\nimport { buildAvailableToolsPrompt, buildSystemPrompt } from \"./prompts.js\";\n\n/** tool_result 事件里输出的截断长度(完整输出仍进对话上下文喂给模型) */\nconst EVENT_OUTPUT_LIMIT = 2000;\n\n/**\n * 判断一次 LLM 调用失败是否值得 agent 侧重试(瞬态)。\n * 依据协议层抛出的固定错误前缀(见 responses/messages 的 yield error 文案),\n * 不靠错误对象类型——协议层只暴露文本。\n * 只覆盖「上游可用性问题」:网络抖动、5xx、流内声明失败、断流。\n * 凭证类错误(401/403)与参数类错误(400/404)不可重试。\n */\nfunction isTransientLLMError(message: string): boolean {\n const m = message.toLowerCase();\n if (m.includes(\"401\") || m.includes(\"403\") || m.includes(\"400\") || m.includes(\"404\")) return false;\n return (\n m.includes(\"网络错误\") ||\n m.includes(\"流读取失败\") ||\n m.includes(\"模型流异常终止\") ||\n m.includes(\"模型调用失败\") || // 上游流内 response.failed / error 事件\n m.includes(\"响应不完整\") ||\n m.includes(\"http 5\") || // 502/503/504 等,经 httpErrorSummary 带入\n m.includes(\"502\") ||\n m.includes(\"503\") ||\n m.includes(\"504\")\n );\n}\n\nexport interface AgentRunnerOptions {\n /** 直接使用单个协议实例(库形态的典型用法) */\n protocol?: LlmProtocol;\n /** 或经端点路由按 params.model 解析(服务层用法);两者必传其一 */\n resolver?: EndpointResolver;\n tools?: AgentTool[];\n maxSteps?: number;\n /** 定稿消息回调(会话持久化挂点):中间步 assistant(含 tool_calls)、\n * 每条 tool 结果、终答 assistant 各调用一次;流式 delta 不经过这里 */\n onMessage?: (message: ChatMessage, response: ChatResponse | null) => Promise<void>;\n /** 压缩定稿回调(转录落盘挂点):每次上下文压缩成功后调用一次 */\n onCompaction?: (result: CompactionResult) => Promise<void>;\n /** 提权请求回调(转录落盘挂点):回放时前端据此渲染确认卡片 */\n onEscalation?: (info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type: \"path\" | \"command\";\n requested_command?: string[];\n }) => Promise<void>;\n /** 日志输出(默认 console);测试可注入静默 logger */\n logger?: Pick<Console, \"info\" | \"warn\" | \"error\">;\n /** 提权事件里展示的工作区根(用户判断边界用);服务装配层从工具配置传入 */\n workdirHint?: string;\n}\n\nexport interface AgentRunOptions {\n runId?: string;\n signal?: AbortSignal;\n /**\n * 当前 run 的标识上下文(xlyra-callback 凭证用):sessionId 由会话层提供,\n * agentInstanceId 由部署方注入;仅标识 ID,不携带会话内容。\n * 提供 sessionId 时,runner 会在首次模型调用前把上下文推进协议实例。\n */\n sessionId?: string;\n agentInstanceId?: string;\n}\n\nexport class AgentRunner {\n private readonly protocol?: LlmProtocol;\n private readonly resolver?: EndpointResolver;\n private readonly tools: AgentTool[];\n private readonly toolsByName: Map<string, AgentTool>;\n private readonly maxSteps: number;\n private readonly onMessage?: AgentRunnerOptions[\"onMessage\"];\n private readonly onCompaction?: AgentRunnerOptions[\"onCompaction\"];\n private readonly onEscalation?: AgentRunnerOptions[\"onEscalation\"];\n private readonly logger: Pick<Console, \"info\" | \"warn\" | \"error\">;\n /** 提权事件里展示的工作区根(用户判断边界用);由构造方从工具配置传入 */\n private readonly workdirHint: string;\n\n constructor(opts: AgentRunnerOptions) {\n if (!opts.protocol && !opts.resolver) {\n throw new Error(\"AgentRunner 需要 protocol 或 resolver 之一\");\n }\n this.protocol = opts.protocol;\n this.resolver = opts.resolver;\n this.tools = opts.tools ?? [];\n this.toolsByName = new Map(this.tools.map((t) => [t.definition.name, t]));\n this.maxSteps = opts.maxSteps ?? 200;\n this.onMessage = opts.onMessage;\n this.onCompaction = opts.onCompaction;\n this.onEscalation = opts.onEscalation;\n this.logger = opts.logger ?? console;\n this.workdirHint = opts.workdirHint ?? \"\";\n }\n\n async *start(\n params: AgentStartParams,\n runOpts: AgentRunOptions = {},\n ): AsyncGenerator<AgentEvent> {\n const runId = runOpts.runId ?? crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n const started = Date.now();\n\n // 路由解析放在发事件之前:解析失败也要以 agent_error 事件告知,而不是断流\n let protocol: LlmProtocol;\n let providerName: string;\n let modelId: string;\n let contextWindow: number | undefined;\n try {\n if (this.resolver) {\n const resolved = this.resolver.resolve(params.model ?? \"\");\n protocol = resolved.protocol;\n providerName = resolved.endpoint.name;\n modelId = resolved.modelId;\n contextWindow = resolved.contextWindow;\n } else {\n protocol = this.protocol!;\n providerName = protocol.name;\n modelId = params.model ?? \"\";\n contextWindow = undefined;\n }\n } catch (err) {\n if (err instanceof LlmError) {\n yield { type: \"agent_error\", run_id: runId, error: err.message };\n return;\n }\n throw err;\n }\n if (!contextWindow) {\n this.logger.info(`模型未声明上下文窗口,自动压缩停用 model=${modelId}`);\n }\n\n // xlyra-callback 凭证:把本次 run 的标识上下文推进协议实例(协议实例按\n // 端点缓存、跨 run 复用;换 run 后旧 token 作废)。direct 凭证为 no-op。\n if (runOpts.sessionId) {\n protocol.setRunContext?.({\n agentInstanceId: runOpts.agentInstanceId ?? \"default\",\n sessionId: runOpts.sessionId,\n runId,\n model: modelId,\n });\n }\n\n // history 来自外部输入(z.input 形态,content 可选):统一过一遍 schema\n // 补全默认值,同时挡掉调用方传来的结构错误\n const history = (params.history ?? []).map((m) => chatMessageSchema.parse(m));\n const settings = modelSettingsSchema.parse(params.settings ?? {});\n const definitions = this.tools.map((t) => t.definition);\n const availableToolsPrompt = buildAvailableToolsPrompt(\n definitions.map(({ name, description }) => ({ name, description })),\n );\n const messages: ChatMessage[] = [\n {\n role: \"system\",\n content:\n params.system_prompt\n ? `${params.system_prompt.trim()}\\n\\n${availableToolsPrompt}`\n : buildSystemPrompt({ availableTools: definitions.map(({ name, description }) => ({ name, description })) }),\n },\n ...history,\n ...(params.include_input === false ? [] : [{ role: \"user\" as const, content: params.input }]),\n ];\n\n yield { type: \"agent_start\", run_id: runId, provider: providerName, model: modelId };\n\n // pre-run 检查:续聊重建的历史可能已经逼近窗口(此时还没有服务端 usage\n // 可用,用字节启发式估算),先压缩再进入循环\n const preCompact = await this.maybeCompact(\n protocol, runId, modelId, messages, estimateTokens(messages), contextWindow, settings,\n );\n if (preCompact) yield preCompact;\n\n let usage = emptyUsage();\n for (let step = 1; step <= this.maxSteps; step++) {\n if (runOpts.signal?.aborted) return; // 取消:安静退出,终态已由编排层落\n\n let final: ChatResponse | null = null;\n // step 级重试:上游网络抖动/流内声明失败时,在没向外界吐出任何增量\n // (text_delta/tool_call)之前允许换同一路由重试一次;一旦已有增量\n // 流出就不再重试,避免重复生成。可重试判定收敛在协议层固定前缀上。\n const maxStepAttempts = 2;\n let attempt = 0;\n let buffered: AgentEvent[] | null = null;\n while (true) {\n attempt += 1;\n const attemptEvents: AgentEvent[] = [];\n let sawDelta = false;\n let attemptFailed: string | null = null;\n for await (const event of protocol.chatStream({\n model: modelId,\n messages,\n tools: definitions.length ? definitions : undefined,\n settings,\n signal: runOpts.signal,\n })) {\n if (event.type === \"thinking_delta\") {\n sawDelta = true;\n attemptEvents.push({ type: \"thinking_delta\", run_id: runId, delta: event.delta });\n } else if (event.type === \"text_delta\") {\n sawDelta = true;\n attemptEvents.push({ type: \"text_delta\", run_id: runId, delta: event.delta });\n } else if (event.type === \"toolcall_start\") {\n sawDelta = true;\n attemptEvents.push({ type: \"tool_call_start\", run_id: runId, tool_call: event.tool_call });\n } else if (event.type === \"toolcall_delta\") {\n sawDelta = true;\n attemptEvents.push({\n type: \"tool_call_delta\",\n run_id: runId,\n delta: event.delta,\n tool_call_id: event.tool_call.id,\n });\n } else if (event.type === \"toolcall_end\") {\n sawDelta = true;\n attemptEvents.push({ type: \"tool_call\", run_id: runId, tool_call: event.tool_call });\n } else if (event.type === \"error\") {\n attemptFailed = event.error || \"模型调用失败,原因未知\";\n } else if (event.type === \"done\") {\n final = event.response;\n }\n }\n\n if (attemptFailed === null) {\n buffered = attemptEvents; // 成功:保留本次增量,重放给订阅者\n break;\n }\n\n // 失败:没有任何增量流出且还可重试 → 丢弃本次缓冲重来\n const retryable = !sawDelta\n && attempt < maxStepAttempts\n && isTransientLLMError(attemptFailed)\n && !runOpts.signal?.aborted;\n if (retryable) {\n this.logger.warn(`Agent LLM 调用失败(重试 ${attempt + 1}/${maxStepAttempts})run=${runId}:${attemptFailed}`);\n buffered = null;\n continue;\n }\n // 不可重试:重放缓冲(若有)后按原语义报错\n buffered = attemptEvents;\n for (const event of buffered) yield event;\n this.logger.warn(`Agent 运行失败 run=${runId}:${attemptFailed}`);\n yield { type: \"agent_error\", run_id: runId, error: attemptFailed };\n return;\n }\n\n // 成功路径:重放本次产生的全部增量事件\n for (const event of buffered ?? []) yield event;\n buffered = null;\n\n if (runOpts.signal?.aborted) return;\n if (!final) {\n yield { type: \"agent_error\", run_id: runId, error: \"模型流异常终止,未返回结果\" };\n return;\n }\n usage = addUsage(usage, final.usage);\n\n // 循环判据:以 tool_calls 内容为准(finish_reason 只作参考)\n if (final.tool_calls.length === 0) {\n await this.notify(responseToMessage(final), final);\n const result: AgentDone = {\n text: final.content,\n thinking: final.thinking,\n finish_reason: final.finish_reason,\n usage,\n steps: step,\n model: final.model,\n provider: final.provider,\n elapsed_ms: Date.now() - started,\n };\n yield { type: \"agent_done\", run_id: runId, result };\n return;\n }\n\n // assistant 消息(含 tool_calls)入上下文,随后逐个执行工具\n messages.push(responseToMessage(final));\n await this.notify(responseToMessage(final), final);\n const stepToolMessages: ChatMessage[] = [];\n let callIndex = 0;\n while (callIndex < final.tool_calls.length) {\n const firstCall = final.tool_calls[callIndex]!;\n const firstTool = this.toolsByName.get(firstCall.name);\n const canRunParallel =\n firstTool?.annotations?.readOnly === true &&\n firstTool.annotations.parallelSafe === true;\n const batch = [firstCall];\n callIndex += 1;\n if (canRunParallel) {\n while (callIndex < final.tool_calls.length) {\n const candidate = final.tool_calls[callIndex]!;\n const tool = this.toolsByName.get(candidate.name);\n if (tool?.annotations?.readOnly !== true || tool.annotations.parallelSafe !== true) break;\n batch.push(candidate);\n callIndex += 1;\n }\n }\n\n const settled = await Promise.allSettled(\n batch.map((tc) => this.executeTool(tc, definitions, {\n signal: runOpts.signal,\n runId,\n })),\n );\n for (const [index, outcome] of settled.entries()) {\n const tc = batch[index]!;\n // 提权协商:工具抛 EscalationRequiredError 时,发协商事件并以\n // agent_cancelled 收尾暂停本轮(assistant 的 tool_calls 已由\n // recorder 终态收尾补配对)。用户确认后由编排层授权并重发续跑。\n let result: Awaited<ReturnType<typeof this.executeTool>>;\n if (outcome.status === \"rejected\") {\n const err = outcome.reason;\n if (err instanceof EscalationRequiredError) {\n const escalation = {\n escalation_id: crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12),\n requested_path: err.requestedPath,\n resolved_path: err.resolvedPath,\n tool_name: tc.name,\n workdir: this.workdirHint,\n resource_type: err.resourceType,\n requested_command: err.requestedCommand,\n };\n // 先落盘(回放时前端才能渲染确认卡片),再发事件\n await this.notifyEscalation(escalation);\n yield { type: \"escalation_request\", run_id: runId, escalation };\n yield { type: \"agent_cancelled\", run_id: runId, reason: \"escalation\" };\n return;\n }\n throw err;\n } else {\n result = outcome.value;\n }\n const toolResult: AgentToolResult = {\n tool_call_id: result.tool_call_id,\n name: result.name,\n output: result.output.slice(0, EVENT_OUTPUT_LIMIT),\n is_error: result.is_error,\n elapsed_ms: result.elapsed_ms,\n };\n yield { type: \"tool_result\", run_id: runId, tool_result: toolResult };\n const toolMessage: ChatMessage = {\n role: \"tool\",\n content: result.output,\n tool_call_id: tc.id,\n name: tc.name,\n ...(result.is_error ? { is_error: true } : {}),\n };\n messages.push(toolMessage);\n stepToolMessages.push(toolMessage);\n await this.notify(toolMessage, null);\n }\n }\n\n // mid-run 检查:本步全部工具结果已回喂、call/output 配对完整,\n // 此刻丢弃历史不会产生孤儿调用,是压缩的安全点。用量以服务端上报为准,\n // 仅对尚未发送的新工具结果补估\n const stepUsage = final.usage.prompt_tokens + final.usage.completion_tokens;\n const contextTokens =\n stepUsage > 0 ? stepUsage + estimateTokens(stepToolMessages) : estimateTokens(messages);\n const midCompact = await this.maybeCompact(\n protocol, runId, modelId, messages, contextTokens, contextWindow, settings,\n );\n if (midCompact) yield midCompact;\n }\n\n this.logger.warn(`Agent 达到最大步数上限 run=${runId} steps=${this.maxSteps}`);\n yield {\n type: \"agent_error\",\n run_id: runId,\n error:\n `已达到最大执行步数上限(${this.maxSteps} 步)仍未完成,运行终止。` +\n \"请把任务拆小后重试,或检查是否陷入了循环。\",\n };\n }\n\n /** 达到水位线时压缩上下文并原地替换 messages,返回压缩事件。\n * 任何失败都降级为「本次不压缩」:记日志后照常返回 null,运行继续。 */\n private async maybeCompact(\n protocol: LlmProtocol,\n runId: string,\n modelId: string,\n messages: ChatMessage[],\n contextTokens: number,\n contextWindow: number | undefined,\n settings: import(\"../llm/models.js\").ModelSettings,\n ): Promise<AgentEvent | null> {\n if (!shouldCompact(contextTokens, contextWindow)) return null;\n let result: CompactionResult | null = null;\n try {\n result = await compact(protocol, modelId, messages, settings);\n } catch (err) {\n // 压缩是优化路径,任何故障都不应拖垮运行\n this.logger.warn(`上下文压缩发生意外错误,本次跳过压缩 run=${runId}:${err instanceof Error ? err.message : err}`);\n return null;\n }\n if (!result) return null;\n // 原地替换:system 保留在首位,其后是重建历史(保留的用户原话 + 摘要)\n messages.splice(0, messages.length, messages[0]!, ...result.replacement_history);\n await this.notifyCompaction(result);\n this.logger.info(\n `上下文已压缩 run=${runId} tokens=${result.tokens_before}→${result.tokens_after}`,\n );\n return {\n type: \"context_compacted\",\n run_id: runId,\n compaction: {\n summary: result.summary,\n tokens_before: result.tokens_before,\n tokens_after: result.tokens_after,\n },\n };\n }\n\n private async notifyCompaction(result: CompactionResult): Promise<void> {\n if (!this.onCompaction) return;\n try {\n await this.onCompaction(result);\n } catch (err) {\n this.logger.warn(`压缩记录持久化回调失败(本次压缩可能未落盘):${err instanceof Error ? err.message : err}`);\n }\n }\n\n private async notifyEscalation(info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type: \"path\" | \"command\";\n requested_command?: string[];\n }): Promise<void> {\n if (!this.onEscalation) return;\n try {\n await this.onEscalation(info);\n } catch (err) {\n this.logger.warn(`提权请求持久化回调失败(本次请求可能未落盘):${err instanceof Error ? err.message : err}`);\n }\n }\n\n private async notify(message: ChatMessage, response: ChatResponse | null): Promise<void> {\n if (!this.onMessage) return;\n try {\n await this.onMessage(message, response);\n } catch (err) {\n this.logger.warn(`Agent 消息持久化回调失败(本条消息可能未落盘):${err instanceof Error ? err.message : err}`);\n }\n }\n\n /** 执行单个工具调用:校验 → 执行;任何失败都转为回喂文本,不抛异常 */\n private async executeTool(\n tc: { id: string; name: string; raw_arguments: string },\n definitions: { name: string; description: string; parameters: Record<string, unknown> }[],\n context: import(\"../tools/types.js\").ToolContext = {},\n ): Promise<{ tool_call_id: string; name: string; output: string; is_error: boolean; elapsed_ms: number }> {\n const started = Date.now();\n const { args, error } = validateToolCall(definitions, tc);\n let output: string;\n let isError: boolean;\n if (error !== null) {\n output = error;\n isError = true;\n } else {\n const tool = this.toolsByName.get(tc.name)!; // validate 已确认工具存在\n try {\n const handled = await tool.handler(args!, context);\n output = truncateMiddle(typeof handled === \"string\" ? handled : handled.content);\n isError = typeof handled === \"string\" ? false : (handled.isError ?? false);\n } catch (err) {\n // 提权信号不上行到普通失败路径——由 runner 转成协商事件\n if (err instanceof EscalationRequiredError) throw err;\n this.logger.warn(`工具执行失败 tool=${tc.name}:${err instanceof Error ? err.message : err}`);\n output = `工具执行失败:${err instanceof Error ? err.message : err}`;\n isError = true;\n }\n }\n return {\n tool_call_id: tc.id,\n name: tc.name,\n output,\n is_error: isError,\n elapsed_ms: Date.now() - started,\n };\n }\n}\n","/**\n * 工具挂点:声明 + 执行器的绑定。\n *\n * 工具的「声明」(definition,暴露给模型)与「执行」(handler,真正干活)\n * 在此绑成一个单元——改行为时提示词与实现不会漂移。handler 约定:\n * - 入参是已通过 JSON Schema 校验的参数 dict;\n * - 返回喂回模型的文本(紧凑、模型可读即可);\n * - 业务失败 throw new Error(中文说明):runner 会把异常转成失败结果\n * 回喂模型,不中断 loop。\n */\nimport type { ToolDefinition } from \"../llm/models.js\";\n\nexport interface ToolAnnotations {\n /** 不修改文件、进程或外部状态。 */\n readOnly: boolean;\n /** 可与同一模型响应中的其他只读工具并发执行。 */\n parallelSafe: boolean;\n}\n\nexport interface ToolContext {\n /** 当前 Agent 运行的取消信号;长任务必须主动监听。 */\n signal?: AbortSignal;\n /** 当前运行编号,供进程会话与诊断日志关联。 */\n runId?: string;\n}\n\nexport interface ToolHandlerResult {\n /** 回喂模型的紧凑文本。 */\n content: string;\n /** 工具可显式返回业务失败,而不必抛异常。 */\n isError?: boolean;\n /** 仅供宿主扩展使用;当前消息协议不会把它回喂模型。 */\n metadata?: Record<string, unknown>;\n}\n\nexport interface AgentTool {\n definition: ToolDefinition;\n /** 省略时按“有副作用、不可并行”的保守策略处理。 */\n annotations?: ToolAnnotations;\n /** 字符串返回值继续兼容已有自定义工具。 */\n handler: (\n args: Record<string, unknown>,\n context?: ToolContext,\n ) => Promise<string | ToolHandlerResult>;\n}\n\n/** 工具输出统一上限:单工具单次输出 ≤ 50KB,超限保留头尾(中部截断) */\nexport const TOOL_OUTPUT_MAX_BYTES = 50_000;\n\n/** 中部截断:头尾各留一半预算(头尾信息密度最高),按字节切、退回合法 UTF-8 边界 */\nexport function truncateMiddle(text: string, maxBytes = TOOL_OUTPUT_MAX_BYTES): string {\n const data = Buffer.from(text, \"utf-8\");\n if (data.length <= maxBytes) return text;\n const half = Math.floor(maxBytes / 2);\n const head = data.subarray(0, half).toString(\"utf-8\");\n const tail = data.subarray(data.length - half).toString(\"utf-8\");\n const omitted = Math.floor((data.length - maxBytes) / 4);\n return `${head}\\n…(中间约 ${omitted} token 已截断)…\\n${tail}`;\n}\n","/**\n * 路径提权协商 —— 沙箱硬闸与「用户明确授权」之间的桥梁。\n *\n * 设计(与沙箱的关系):\n * - resolveSandboxed 的硬闸不变:默认一切越界访问都被拦下;\n * - 新增「提权请求」通道:工具 handler 在拒绝时抛出 EscalationRequiredError\n * (携带目标路径),runner 捕获后不发 tool_result,而是发 escalation_request\n * 事件并暂停本轮运行;用户在前端确认后,服务端把路径登记进会话级授权\n * 清单并自动重发上一条用户消息(续跑);\n * - 授权粒度是「会话 × 路径前缀」,随会话生命周期存在(不落盘到全局配置,\n * 重启服务即失效)——宁可每次新会话重新确认,也不留持久的越界后门。\n */\n\nimport path from \"node:path\";\n\nexport const COMMAND_EXECUTION_GRANT = \"capability://exec_command\";\n\nexport type EscalationResourceType = \"path\" | \"command\";\n\n/** 工具层抛出的提权信号(runner 识别它并转成协商流程,不作为普通工具失败回喂) */\nexport class EscalationRequiredError extends Error {\n constructor(\n /** 请求访问的原始路径(用户或模型给出的形态,用于展示) */\n public readonly requestedPath: string,\n /** 沙箱解析后的绝对路径(授权登记的键) */\n public readonly resolvedPath: string,\n message?: string,\n public readonly resourceType: EscalationResourceType = \"path\",\n public readonly requestedCommand?: string[],\n ) {\n super(message ?? (resourceType === \"command\"\n ? \"执行本机命令需要用户授权\"\n : `路径超出工作区范围,需要用户授权:${resolvedPath}`));\n this.name = \"EscalationRequiredError\";\n }\n}\n\n/**\n * 会话级路径授权登记表(进程内)。\n * key = sessionId,value = 已授权的路径前缀集合(realpath 后的绝对路径)。\n */\nexport class EscalationGrants {\n private readonly grants = new Map<string, Set<string>>();\n /** 会话级完全访问开关(前端 permission_mode=full 注入;ask 时撤销,不随消息残留) */\n private readonly fullAccess = new Set<string>();\n\n /** 完全访问模式:跳过一切路径与能力提权检查(用户已在 UI 二次确认) */\n setFullAccess(sessionId: string, enabled: boolean): void {\n if (enabled) {\n this.fullAccess.add(sessionId);\n } else {\n this.fullAccess.delete(sessionId);\n }\n }\n\n hasFullAccess(sessionId: string): boolean {\n return this.fullAccess.has(sessionId);\n }\n\n grant(sessionId: string, resolvedPath: string): void {\n let set = this.grants.get(sessionId);\n if (!set) {\n set = new Set();\n this.grants.set(sessionId, set);\n }\n set.add(resolvedPath);\n }\n\n grantCapability(sessionId: string, capability: string): void {\n this.grant(sessionId, capability);\n }\n\n /** 已授权路径或其子路径视为已放开;完全访问模式直接放行 */\n isGranted(sessionId: string, resolvedPath: string): boolean {\n if (this.fullAccess.has(sessionId)) return true;\n const set = this.grants.get(sessionId);\n if (!set) return false;\n for (const prefix of set) {\n const relative = path.relative(prefix, resolvedPath);\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) return true;\n }\n return false;\n }\n\n isCapabilityGranted(sessionId: string, capability: string): boolean {\n if (this.fullAccess.has(sessionId)) return true;\n return this.grants.get(sessionId)?.has(capability) ?? false;\n }\n\n /** 会话删除时清掉授权(授权随会话生命周期) */\n drop(sessionId: string): void {\n this.grants.delete(sessionId);\n this.fullAccess.delete(sessionId);\n }\n}\n","/**\n * 内置工具集:文件读写、精确编辑、内容搜索,以及需要授权的本机命令会话工具。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { EscalationGrants } from \"../agent/escalation.js\";\nimport type { SkillInfo } from \"../context/skills.js\";\nimport { makeApplyPatchTool } from \"./apply-patch.js\";\nimport { makeCreateTool } from \"./create.js\";\nimport { makeEditTool } from \"./edit.js\";\nimport { makeExecCommandTool } from \"./exec-command.js\";\nimport { makeListTool } from \"./list.js\";\nimport { makeLoadSkillTool } from \"./load-skill.js\";\nimport { makeReadTool } from \"./read.js\";\nimport { makeSearchTool } from \"./search.js\";\nimport { ProcessManager } from \"./process-manager.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { makeWriteTool } from \"./write.js\";\nimport { makeWriteStdinTool } from \"./write-stdin.js\";\n\nexport interface BuiltinToolsOptions {\n /** 工作目录:相对路径解析基准 + 沙箱边界 */\n workdir: string;\n /** 显式放开沙箱(默认 false:全部路径限制在 workdir 内) */\n allowOutsideWorkdir?: boolean;\n /** 会话级路径授权清单(与 sessionId 一起提供时生效) */\n grants?: EscalationGrants;\n /** 当前会话 id(授权清单的查询键) */\n sessionId?: string;\n /** 预授权本机命令执行;关闭时工具仍会声明,但首次调用触发提权协商。 */\n enableCommandExecution?: boolean;\n /** 当前会话已发现的 skills;非空时注册 load_skill */\n skills?: SkillInfo[];\n}\n\nexport function builtinTools(opts: BuiltinToolsOptions): AgentTool[] {\n const workdir = path.resolve(opts.workdir);\n fs.mkdirSync(workdir, { recursive: true });\n const sandbox = {\n allowOutsideWorkdir: opts.allowOutsideWorkdir ?? false,\n grants: opts.grants,\n sessionId: opts.sessionId,\n };\n const tools: AgentTool[] = [\n makeListTool(workdir, sandbox),\n makeReadTool(workdir, sandbox),\n makeSearchTool(workdir, sandbox),\n makeCreateTool(workdir, sandbox),\n makeEditTool(workdir, sandbox),\n makeWriteTool(workdir, sandbox),\n makeApplyPatchTool(workdir, sandbox),\n ];\n const commandSandbox = { ...sandbox, commandExecutionEnabled: opts.enableCommandExecution ?? false };\n const processes = new ProcessManager();\n tools.push(\n makeExecCommandTool(workdir, processes, commandSandbox),\n makeWriteStdinTool(processes, commandSandbox),\n );\n if (opts.skills && opts.skills.length > 0) {\n tools.push(makeLoadSkillTool(opts.skills));\n }\n return tools;\n}\n\nexport type { AgentTool, ToolAnnotations, ToolContext, ToolHandlerResult } from \"./types.js\";\nexport { makeLoadSkillTool } from \"./load-skill.js\";\nexport { makeListTool } from \"./list.js\";\nexport { makeReadTool } from \"./read.js\";\nexport { makeCreateTool } from \"./create.js\";\nexport { makeApplyPatchTool } from \"./apply-patch.js\";\nexport { makeEditTool } from \"./edit.js\";\nexport { makeSearchTool } from \"./search.js\";\nexport { makeExecCommandTool, formatProcessResult } from \"./exec-command.js\";\nexport { makeWriteStdinTool } from \"./write-stdin.js\";\nexport { ProcessManager } from \"./process-manager.js\";\nexport { makeWriteTool } from \"./write.js\";\nexport { resolveSandboxed } from \"./workdir.js\";\nexport type { SandboxOptions } from \"./sandbox-types.js\";\n","/** 多文件补丁工具:解析 Codex 风格补丁,全部预校验后再原子落盘。 */\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst argsSchema = z.object({ patch: z.string().min(1) });\n\ntype PatchOperation =\n | { kind: \"add\"; rawPath: string; file: string; content: string }\n | { kind: \"delete\"; rawPath: string; file: string }\n | { kind: \"update\"; rawPath: string; file: string; hunks: Hunk[] };\n\ninterface Hunk {\n before: string[];\n after: string[];\n}\n\ninterface PreparedWrite {\n kind: \"add\" | \"update\";\n rawPath: string;\n file: string;\n content: string;\n}\n\nexport function makeApplyPatchTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"apply_patch\",\n description:\n \"应用 Codex 风格的多文件补丁。输入须以 *** Begin Patch 开始、*** End Patch 结束,\" +\n \"支持 *** Add File、*** Update File、*** Delete File。所有文件先校验,任何一处失败都不会写入。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { patch } = argsSchema.parse(args);\n const operations = parsePatch(patch, workdir, sandbox);\n const writes: PreparedWrite[] = [];\n const deletes: Array<{ rawPath: string; file: string }> = [];\n\n for (const operation of operations) {\n if (operation.kind === \"add\") {\n if (fs.existsSync(operation.file)) throw new Error(`新增文件已存在:${operation.rawPath}`);\n writes.push({ ...operation, kind: \"add\" });\n } else if (operation.kind === \"delete\") {\n assertRegularFile(operation.rawPath, operation.file);\n deletes.push(operation);\n } else {\n assertRegularFile(operation.rawPath, operation.file);\n let content = fs.readFileSync(operation.file, \"utf-8\");\n for (const hunk of operation.hunks) content = applyHunk(content, hunk, operation.rawPath);\n writes.push({ kind: \"update\", rawPath: operation.rawPath, file: operation.file, content });\n }\n }\n\n const staged: Array<PreparedWrite & { tmp: string }> = [];\n try {\n for (const write of writes) staged.push(stageWrite(write));\n } catch (err) {\n for (const item of staged) fs.rmSync(item.tmp, { force: true });\n throw err;\n }\n const backups = new Map<string, string>();\n const installedAdds: string[] = [];\n try {\n for (const item of staged) {\n if (item.kind === \"update\") {\n const backup = backupPath(item.file);\n fs.renameSync(item.file, backup);\n backups.set(item.file, backup);\n } else {\n installedAdds.push(item.file);\n }\n fs.mkdirSync(path.dirname(item.file), { recursive: true });\n fs.renameSync(item.tmp, item.file);\n }\n for (const deletion of deletes) {\n const backup = backupPath(deletion.file);\n fs.renameSync(deletion.file, backup);\n backups.set(deletion.file, backup);\n }\n } catch (err) {\n for (const item of staged) fs.rmSync(item.tmp, { force: true });\n for (const file of installedAdds) fs.rmSync(file, { force: true });\n for (const [file, backup] of [...backups].reverse()) {\n fs.rmSync(file, { force: true });\n if (fs.existsSync(backup)) fs.renameSync(backup, file);\n }\n throw err;\n }\n for (const backup of backups.values()) fs.rmSync(backup, { force: true });\n\n const summary = operations.map((operation) => `${operation.kind} ${operation.rawPath}`).join(\"\\n\");\n return `补丁已应用(${operations.length} 个文件):\\n${summary}`;\n },\n };\n}\n\nfunction parsePatch(patch: string, workdir: string, sandbox: SandboxOptions): PatchOperation[] {\n const lines = patch.replace(/\\r\\n/g, \"\\n\").split(\"\\n\");\n if (lines[0] !== \"*** Begin Patch\") throw new Error(\"补丁必须以 *** Begin Patch 开始\");\n const end = lines.lastIndexOf(\"*** End Patch\");\n if (end < 0) throw new Error(\"补丁缺少 *** End Patch\");\n if (lines.slice(end + 1).some((line) => line.trim())) throw new Error(\"*** End Patch 后不能有内容\");\n\n const operations: PatchOperation[] = [];\n const seen = new Set<string>();\n let index = 1;\n while (index < end) {\n if (!lines[index]) {\n index += 1;\n continue;\n }\n const header = lines[index]!;\n const matched = header.match(/^\\*\\*\\* (Add|Update|Delete) File: (.+)$/);\n if (!matched) throw new Error(`无法识别的补丁行 ${index + 1}:${header}`);\n const kind = matched[1]!.toLowerCase() as PatchOperation[\"kind\"];\n const rawPath = matched[2]!.trim();\n if (!rawPath) throw new Error(`补丁第 ${index + 1} 行缺少文件路径`);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (seen.has(file)) throw new Error(`同一补丁不能多次操作文件:${rawPath}`);\n seen.add(file);\n index += 1;\n\n const body: string[] = [];\n while (index < end && !lines[index]!.startsWith(\"*** \")) {\n body.push(lines[index]!);\n index += 1;\n }\n if (kind === \"add\") {\n if (body.some((line) => !line.startsWith(\"+\"))) {\n throw new Error(`新增文件 ${rawPath} 的每一行都必须以 + 开头`);\n }\n operations.push({ kind, rawPath, file, content: body.map((line) => line.slice(1)).join(\"\\n\") });\n } else if (kind === \"delete\") {\n if (body.some((line) => line.length > 0)) throw new Error(`删除文件 ${rawPath} 不接受补丁正文`);\n operations.push({ kind, rawPath, file });\n } else {\n const hunks = parseHunks(body, rawPath);\n operations.push({ kind, rawPath, file, hunks });\n }\n }\n if (operations.length === 0) throw new Error(\"补丁不包含任何文件操作\");\n return operations;\n}\n\nfunction parseHunks(lines: string[], rawPath: string): Hunk[] {\n const hunks: Hunk[] = [];\n let current: Hunk | null = null;\n for (const line of lines) {\n if (line.startsWith(\"@@\")) {\n current = { before: [], after: [] };\n hunks.push(current);\n continue;\n }\n if (!current) throw new Error(`更新文件 ${rawPath} 的正文必须从 @@ 开始`);\n const marker = line[0];\n const text = line.slice(1);\n if (marker === \" \") {\n current.before.push(text);\n current.after.push(text);\n } else if (marker === \"-\") {\n current.before.push(text);\n } else if (marker === \"+\") {\n current.after.push(text);\n } else {\n throw new Error(`更新文件 ${rawPath} 包含非法补丁行:${line}`);\n }\n }\n if (hunks.length === 0) throw new Error(`更新文件 ${rawPath} 缺少 @@ hunk`);\n return hunks;\n}\n\nfunction applyHunk(content: string, hunk: Hunk, rawPath: string): string {\n const before = hunk.before.join(\"\\n\");\n const after = hunk.after.join(\"\\n\");\n if (!before) throw new Error(`更新文件 ${rawPath} 的 hunk 缺少上下文或删除行`);\n const first = content.indexOf(before);\n if (first < 0) throw new Error(`更新文件 ${rawPath} 时未找到 hunk 上下文`);\n if (content.indexOf(before, first + before.length) >= 0) {\n throw new Error(`更新文件 ${rawPath} 的 hunk 上下文不唯一`);\n }\n return content.slice(0, first) + after + content.slice(first + before.length);\n}\n\nfunction assertRegularFile(rawPath: string, file: string): void {\n if (!fs.existsSync(file)) throw new Error(`文件不存在:${rawPath}`);\n if (!fs.statSync(file).isFile()) throw new Error(`${rawPath} 不是普通文件`);\n}\n\nfunction stageWrite(write: PreparedWrite): PreparedWrite & { tmp: string } {\n fs.mkdirSync(path.dirname(write.file), { recursive: true });\n const tmp = path.join(path.dirname(write.file), `.xlyra-tmp-${crypto.randomUUID()}${path.extname(write.file)}`);\n fs.writeFileSync(tmp, write.content);\n return { ...write, tmp };\n}\n\nfunction backupPath(file: string): string {\n return path.join(path.dirname(file), `.xlyra-backup-${crypto.randomUUID()}${path.extname(file)}`);\n}\n","/**\n * 工作区沙箱:四个文件工具共用的路径解析。\n *\n * 默认全部路径限制在 workdir 内:相对路径基于 workdir 解析;解析结果经\n * realpath 校验仍须落在 workdir 内——**含符号链接逃逸拦截**(指向 workdir\n * 外的符号链接会被拒绝)。\n *\n * 越界时的行为分两层:\n * - 无授权 → 抛 EscalationRequiredError(runner 转成提权协商事件,等待用户确认);\n * - 会话级授权清单(grants)已覆盖该路径 → 放行;\n * - allowOutsideWorkdir 显式放开(本机部署的完全信任模式)→ 直接放行。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { EscalationRequiredError, type EscalationGrants } from \"../agent/escalation.js\";\n\n/**\n * 解析目标路径并做沙箱校验;返回可直接用于 fs 操作的绝对路径。\n * 目标不存在时(create 场景):取最深的已存在祖先做 realpath,再拼回剩余段。\n */\nexport function resolveSandboxed(\n workdir: string,\n raw: string,\n opts: {\n allowOutsideWorkdir?: boolean;\n /** 会话级授权清单(提供 sessionId 时生效) */\n grants?: EscalationGrants;\n sessionId?: string;\n } = {},\n): string {\n const baseReal = fs.realpathSync(workdir);\n const candidate = path.resolve(path.isAbsolute(raw) ? raw : path.join(baseReal, raw));\n if (opts.allowOutsideWorkdir) return candidate;\n\n // 目标或最深已存在祖先的 realpath(处理符号链接与 .. 逃逸)\n let existing = candidate;\n const missing: string[] = [];\n while (!fs.existsSync(existing)) {\n missing.unshift(path.basename(existing));\n const parent = path.dirname(existing);\n if (parent === existing) break; // 已到根\n existing = parent;\n }\n const existingReal = fs.realpathSync(existing);\n const realTarget = path.join(existingReal, ...missing);\n\n if (realTarget !== baseReal && !realTarget.startsWith(baseReal + path.sep)) {\n // 会话级授权覆盖 → 放行\n if (opts.grants && opts.sessionId && opts.grants.isGranted(opts.sessionId, realTarget)) {\n return realTarget;\n }\n throw new EscalationRequiredError(raw, realTarget);\n }\n return realTarget;\n}\n","/**\n * create 工具:新建文件(已存在则失败)。\n *\n * 与 write 形成对称硬闸:create 只建不覆盖(wx 语义),write 只覆盖不新建。\n * 设计意图是把「覆盖已有内容」变成模型必须显式选择的动作,防误覆盖。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst argsSchema = z.object({\n path: z.string(),\n content: z.string(),\n});\n\nexport function makeCreateTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"create\",\n description:\n \"新建文件并写入内容(自动创建父目录)。目标已存在时失败——\" +\n \"如需修改已有文件请用 write 工具。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { path: rawPath, content } = argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n fs.mkdirSync(path.dirname(file), { recursive: true });\n try {\n fs.writeFileSync(file, content, { flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n throw new Error(`文件已存在:${rawPath};如需修改请用 write 工具`);\n }\n throw err;\n }\n return `已创建 ${rawPath}(${content.length} 字符,${content.split(\"\\n\").length} 行)`;\n },\n };\n}\n","/** 精确编辑工具:old_text 唯一命中替换,避免整文件重写。 */\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst argsSchema = z.object({\n path: z.string(),\n old_text: z.string().min(1),\n new_text: z.string(),\n replace_all: z.boolean().default(false),\n});\n\nexport function makeEditTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"edit\",\n description:\n \"精确修改已有文本文件。默认要求 old_text 在文件中恰好出现一次;\" +\n \"未命中或多次命中都会失败。确需替换全部匹配时传 replace_all=true。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { path: rawPath, old_text: oldText, new_text: newText, replace_all: replaceAll } =\n argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(file)) throw new Error(`文件不存在:${rawPath}`);\n if (fs.statSync(file).isDirectory()) throw new Error(`${rawPath} 是目录不是文件`);\n\n const original = fs.readFileSync(file, \"utf-8\");\n const matches = countMatches(original, oldText);\n if (matches === 0) throw new Error(`未找到要替换的 old_text:${rawPath}`);\n if (!replaceAll && matches !== 1) {\n throw new Error(\n `old_text 在 ${rawPath} 中出现 ${matches} 次;请提供更长的唯一上下文,` +\n \"或明确传 replace_all=true\",\n );\n }\n\n const first = original.indexOf(oldText);\n const updated = replaceAll\n ? original.split(oldText).join(newText)\n : original.slice(0, first) + newText + original.slice(first + oldText.length);\n atomicReplace(file, updated);\n return `已编辑 ${rawPath}(替换 ${replaceAll ? matches : 1} 处)`;\n },\n };\n}\n\nfunction countMatches(text: string, needle: string): number {\n let count = 0;\n let cursor = 0;\n while (true) {\n const index = text.indexOf(needle, cursor);\n if (index < 0) return count;\n count += 1;\n cursor = index + needle.length;\n }\n}\n\nfunction atomicReplace(file: string, content: string): void {\n const tmp = path.join(path.dirname(file), `.xlyra-tmp-${crypto.randomUUID()}${path.extname(file)}`);\n try {\n fs.writeFileSync(tmp, content);\n fs.renameSync(tmp, file);\n } catch (err) {\n fs.rmSync(tmp, { force: true });\n throw err;\n }\n}\n","import fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { COMMAND_EXECUTION_GRANT, EscalationRequiredError } from \"../agent/escalation.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport { ProcessManager, type ProcessPollResult } from \"./process-manager.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst argsSchema = z.object({\n command: z.array(z.string()).min(1),\n cwd: z.string().default(\".\"),\n timeout_ms: z.number().int().min(100).max(1_800_000).default(300_000),\n yield_time_ms: z.number().int().min(0).max(600_000).default(10_000),\n max_output_bytes: z.number().int().min(1_000).max(100_000).default(50_000),\n});\n\nexport function makeExecCommandTool(\n workdir: string,\n manager: ProcessManager,\n sandbox: SandboxOptions = {},\n): AgentTool {\n return {\n definition: {\n name: \"exec_command\",\n description:\n \"直接执行命令 argv,不经过 shell。command 必须是字符串数组,例如 \" +\n '[\"pnpm\",\"test\"]。预计执行较久的命令(克隆仓库、安装依赖、构建等)' +\n \"务必把 yield_time_ms 和 timeout_ms 都设大(最高分别为 600000 和 1800000):\" +\n \"进程一结束调用就立即返回,不会白等。只有超过 yield_time_ms 仍在运行时\" +\n \"才返回 session_id,此时用 write_stdin 以较长 yield_time_ms(如 120000)继续等待,\" +\n \"不要短时间反复轮询。执行前可能需要用户授权。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args, context) => {\n const parsed = argsSchema.parse(args);\n const commandAllowed = sandbox.commandExecutionEnabled === true\n || (sandbox.grants !== undefined && sandbox.sessionId !== undefined\n && sandbox.grants.isCapabilityGranted(sandbox.sessionId, COMMAND_EXECUTION_GRANT));\n if (!commandAllowed) {\n throw new EscalationRequiredError(\n parsed.command.join(\" \"),\n COMMAND_EXECUTION_GRANT,\n \"执行本机命令需要用户授权\",\n \"command\",\n parsed.command,\n );\n }\n const cwd = resolveSandboxed(workdir, parsed.cwd, sandbox);\n if (!fs.existsSync(cwd)) throw new Error(`工作目录不存在:${parsed.cwd}`);\n if (!fs.statSync(cwd).isDirectory()) throw new Error(`cwd 不是目录:${parsed.cwd}`);\n const sessionId = manager.start({\n command: parsed.command,\n cwd,\n timeoutMs: parsed.timeout_ms,\n signal: context?.signal,\n });\n const result = await manager.poll(sessionId, parsed.yield_time_ms, parsed.max_output_bytes);\n return formatProcessResult(result);\n },\n };\n}\n\nexport function formatProcessResult(result: ProcessPollResult): { content: string; isError: boolean } {\n const sections = [\n `session_id: ${result.sessionId}`,\n result.running\n ? \"status: running\"\n : `status: exited${result.exitCode !== null ? `\\nexit_code: ${result.exitCode}` : \"\"}` +\n `${result.exitSignal ? `\\nexit_signal: ${result.exitSignal}` : \"\"}`,\n ];\n if (result.output) sections.push(`output:\\n${result.output}`);\n else sections.push(\"output: (暂无新输出)\");\n if (result.error) sections.push(`error: ${result.error}`);\n return {\n content: sections.join(\"\\n\"),\n isError: Boolean(result.error) || (!result.running && result.exitCode !== null && result.exitCode !== 0),\n };\n}\n","import crypto from \"node:crypto\";\nimport { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { truncateMiddle } from \"./types.js\";\n\nconst TRANSCRIPT_MAX_CHARS = 200_000;\nconst COMPLETED_SESSION_RETENTION_MS = 60 * 60 * 1000;\nconst MAX_SESSIONS = 128;\n\ninterface ProcessSession {\n id: string;\n child: ChildProcessWithoutNullStreams;\n output: string;\n readCursor: number;\n exitCode: number | null;\n exitSignal: NodeJS.Signals | null;\n error: string | null;\n completedAt: number | null;\n done: Promise<void>;\n resolveDone: () => void;\n timeout: ReturnType<typeof setTimeout>;\n abortSignal?: AbortSignal;\n abortListener?: () => void;\n}\n\nexport interface SpawnProcessOptions {\n command: string[];\n cwd: string;\n timeoutMs: number;\n signal?: AbortSignal;\n}\n\nexport interface ProcessPollResult {\n sessionId: string;\n output: string;\n running: boolean;\n exitCode: number | null;\n exitSignal: NodeJS.Signals | null;\n error: string | null;\n}\n\nexport class ProcessManager {\n private readonly sessions = new Map<string, ProcessSession>();\n\n start(options: SpawnProcessOptions): string {\n this.prune();\n if (this.sessions.size >= MAX_SESSIONS) {\n const completed = [...this.sessions.values()]\n .filter((session) => session.completedAt !== null)\n .sort((a, b) => a.completedAt! - b.completedAt!);\n for (const session of completed) {\n this.sessions.delete(session.id);\n if (this.sessions.size < MAX_SESSIONS) break;\n }\n }\n if (this.sessions.size >= MAX_SESSIONS) {\n throw new Error(`进程会话已达到上限(${MAX_SESSIONS});请等待已有命令结束后重试`);\n }\n const id = crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n const child = spawn(options.command[0]!, options.command.slice(1), {\n cwd: options.cwd,\n env: process.env,\n stdio: \"pipe\",\n shell: false,\n });\n let resolveDone = (): void => {};\n const done = new Promise<void>((resolve) => { resolveDone = resolve; });\n const session: ProcessSession = {\n id,\n child,\n output: \"\",\n readCursor: 0,\n exitCode: null,\n exitSignal: null,\n error: null,\n completedAt: null,\n done,\n resolveDone,\n timeout: setTimeout(() => this.terminate(id, \"命令执行超时\"), options.timeoutMs),\n abortSignal: options.signal,\n };\n session.timeout.unref?.();\n this.sessions.set(id, session);\n\n const append = (chunk: Buffer): void => {\n session.output += chunk.toString(\"utf-8\");\n if (session.output.length > TRANSCRIPT_MAX_CHARS) {\n const removed = session.output.length - TRANSCRIPT_MAX_CHARS;\n session.output = session.output.slice(removed);\n session.readCursor = Math.max(0, session.readCursor - removed);\n }\n };\n child.stdout.on(\"data\", append);\n child.stderr.on(\"data\", append);\n child.once(\"error\", (err) => {\n session.error = err.message;\n this.finish(session, child.exitCode, child.signalCode);\n });\n child.once(\"close\", (code, signal) => this.finish(session, code, signal));\n\n if (options.signal) {\n const onAbort = (): void => this.terminate(id, \"命令已取消\");\n session.abortListener = onAbort;\n if (options.signal.aborted) onAbort();\n else options.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n return id;\n }\n\n async poll(sessionId: string, yieldTimeMs: number, maxOutputBytes: number): Promise<ProcessPollResult> {\n const session = this.require(sessionId);\n if (session.child.exitCode === null && session.exitSignal === null && !session.error) {\n await Promise.race([\n session.done,\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, yieldTimeMs);\n timer.unref?.();\n }),\n ]);\n }\n const unread = session.output.slice(session.readCursor);\n session.readCursor = session.output.length;\n return {\n sessionId,\n output: truncateMiddle(unread, maxOutputBytes),\n running: session.child.exitCode === null && session.exitSignal === null && !session.error,\n exitCode: session.exitCode,\n exitSignal: session.exitSignal,\n error: session.error,\n };\n }\n\n write(sessionId: string, chars: string): void {\n const session = this.require(sessionId);\n if (session.child.exitCode !== null || session.exitSignal !== null || session.error) {\n throw new Error(`进程会话已结束:${sessionId}`);\n }\n session.child.stdin.write(chars);\n }\n\n private require(sessionId: string): ProcessSession {\n this.prune();\n const session = this.sessions.get(sessionId);\n if (!session) throw new Error(`进程会话不存在:${sessionId}`);\n return session;\n }\n\n private terminate(sessionId: string, reason: string): void {\n const session = this.sessions.get(sessionId);\n if (!session || session.completedAt !== null) return;\n session.error = reason;\n session.child.kill(\"SIGTERM\");\n const force = setTimeout(() => session.child.kill(\"SIGKILL\"), 1_000);\n force.unref?.();\n }\n\n private finish(\n session: ProcessSession,\n code: number | null,\n signal: NodeJS.Signals | null,\n ): void {\n if (session.completedAt !== null) return;\n clearTimeout(session.timeout);\n session.exitCode = code;\n session.exitSignal = signal;\n session.completedAt = Date.now();\n if (session.abortSignal && session.abortListener) {\n session.abortSignal.removeEventListener(\"abort\", session.abortListener);\n }\n session.resolveDone();\n }\n\n private prune(): void {\n const cutoff = Date.now() - COMPLETED_SESSION_RETENTION_MS;\n for (const [id, session] of this.sessions) {\n if (session.completedAt !== null && session.completedAt <= cutoff) this.sessions.delete(id);\n }\n }\n}\n","/**\n * list 工具:列目录内容。\n *\n * 落地细节:\n * - 内置 ignore 清单(.git / node_modules / dist 等),否则一次递归列目录\n * 可能产出几万行直接打爆上下文;\n * - 单次最多 500 条,截断时附「共 N 条,已省略 M 条」;\n * - 输出相对 workdir 的路径,目录带 / 后缀;\n * - pattern 是简化 glob:* 匹配段内任意字符,** 跨段匹配,? 匹配单字符。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst MAX_ENTRIES = 500;\n\nconst IGNORE_NAMES = new Set([\n \".git\",\n \"node_modules\",\n \"dist\",\n \".next\",\n \"out\",\n \"coverage\",\n \".turbo\",\n \".cache\",\n \"__pycache__\",\n \".venv\",\n]);\n\nconst argsSchema = z.object({\n path: z.string().default(\".\"),\n recursive: z.boolean().default(false),\n pattern: z.string().optional(),\n});\n\n/** 简化 glob → RegExp(* 段内任意,** 跨段,? 单字符) */\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"\u0000\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/\\?/g, \"[^/]\")\n .replace(/\u0000/g, \".*\");\n return new RegExp(`(^|/)${escaped}$|^${escaped}$`);\n}\n\nexport function makeListTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"list\",\n description:\n \"列出目录内容(文件与子目录,目录带 / 后缀)。默认只列一层,\" +\n `recursive=true 递归列出。内置忽略 .git、node_modules 等目录。` +\n `单次最多返回 ${MAX_ENTRIES} 条,超出时提示省略数量。`,\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: true, parallelSafe: true },\n handler: async (args) => {\n const { path: rawPath, recursive, pattern } = argsSchema.parse(args);\n const dir = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(dir)) throw new Error(`目录不存在:${rawPath}`);\n if (!fs.statSync(dir).isDirectory()) throw new Error(`${rawPath} 是文件不是目录;读取文件请用 read 工具`);\n\n const matcher = pattern ? globToRegExp(pattern) : null;\n const results: string[] = [];\n let omitted = 0;\n\n const walk = (current: string): void => {\n if (results.length >= MAX_ENTRIES) {\n omitted += countRemaining(current, recursive);\n return;\n }\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(current, { withFileTypes: true });\n } catch {\n return; // 无权限等:跳过该目录\n }\n entries.sort((a, b) => a.name.localeCompare(b.name));\n for (const entry of entries) {\n if (IGNORE_NAMES.has(entry.name)) continue;\n const full = path.join(current, entry.name);\n const rel = path.relative(dir, full);\n const display = entry.isDirectory() ? `${rel}/` : rel;\n if (!matcher || matcher.test(display)) {\n if (results.length < MAX_ENTRIES) results.push(display);\n else omitted += 1;\n }\n if (recursive && entry.isDirectory()) walk(full);\n }\n };\n walk(dir);\n\n const header = `目录 ${rawPath} 的内容:`;\n if (results.length === 0) return `${header}\\n(空目录或无匹配项)`;\n const body = results.join(\"\\n\");\n return omitted > 0\n ? `${header}\\n${body}\\n(共 ${results.length + omitted} 条,已省略 ${omitted} 条;可用 pattern 缩小范围)`\n : `${header}\\n${body}`;\n },\n };\n}\n\nfunction countRemaining(dir: string, recursive: boolean): number {\n let count = 0;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return 0;\n }\n for (const entry of entries) {\n if (IGNORE_NAMES.has(entry.name)) continue;\n count += 1;\n if (recursive && entry.isDirectory()) count += countRemaining(path.join(dir, entry.name), true);\n }\n return count;\n}\n","/**\n * load_skill —— 按名称激活已发现的 Agent Skill。\n *\n * 返回结构化正文 + 资源清单(不预读资源)。metadata.retainedContext 供压缩层\n * 识别并在重建历史时保留;正文同时带耐久标记,跨 run 续聊也能靠消息内容识别。\n */\nimport path from \"node:path\";\nimport { loadSkillContent, type SkillInfo } from \"../context/skills.js\";\nimport type { AgentTool } from \"./types.js\";\nimport {\n RETAINED_CONTEXT_END,\n RETAINED_CONTEXT_START,\n type RetainedContextBlock,\n} from \"../agent/retained-context.js\";\n\nfunction escapeXml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n\nexport function makeLoadSkillTool(skills: SkillInfo[]): AgentTool {\n const byName = new Map(skills.map((skill) => [skill.name, skill]));\n const names = skills.map((skill) => skill.name);\n\n return {\n definition: {\n name: \"load_skill\",\n description:\n \"按名称激活一个 Agent Skill,返回 SKILL.md 全文和可按需读取的资源相对路径列表。\" +\n \"仅在任务匹配 skill 描述时调用;不要猜测未列出的名称。\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n enum: names,\n description: \"要激活的 skill 名称(必须是当前会话已发现的名称)\",\n },\n },\n required: [\"name\"],\n additionalProperties: false,\n },\n },\n annotations: { readOnly: true, parallelSafe: false },\n handler: async (args) => {\n const name = String(args.name ?? \"\");\n const info = byName.get(name);\n if (!info) throw new Error(`未知 skill:${name}`);\n\n const loaded = loadSkillContent(info);\n const resourceLines =\n loaded.resources.length > 0\n ? loaded.resources.map((rel) => `- ${path.join(info.root, rel)}`).join(\"\\n\")\n : \"(无额外资源)\";\n\n const body = [\n `<skill_content name=\"${escapeXml(info.name)}\">`,\n loaded.content.trimEnd(),\n \"\",\n `Skill directory: ${info.root}`,\n \"Relative paths in this skill are relative to the skill directory.\",\n \"<skill_resources>\",\n ...loaded.resources.map((rel) => ` <file>${escapeXml(rel)}</file>`),\n \"</skill_resources>\",\n \"</skill_content>\",\n ...(loaded.warnings.length > 0\n ? [\"\", \"加载告警:\", ...loaded.warnings.map((warning) => `- ${warning}`)]\n : []),\n \"\",\n \"资源绝对路径(未读取内容):\",\n resourceLines,\n ].join(\"\\n\");\n\n const retained: RetainedContextBlock = {\n key: `skill:${info.name}`,\n content: body,\n };\n\n return {\n content: `${RETAINED_CONTEXT_START} ${retained.key}\\n${body}\\n${RETAINED_CONTEXT_END}`,\n metadata: { retainedContext: retained },\n };\n },\n };\n}\n","/**\n * Agent Skills 发现与解析(对齐 https://agentskills.io/specification)。\n *\n * 实现要点(见官方 client-implementation 指南):\n * - 只扫描各 skills 根下的一级子目录中名为 SKILL.md 的文件;\n * - 渐进披露:启动时只暴露 name + description;正文在激活时再读;\n * - 项目级路径优先于用户级;同名后者忽略并告警;\n * - 解析严格遵循规范,单个无效 skill 跳过并告警,不阻断其他 skill。\n */\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\n\n/** 激活时资源清单上限 */\nexport const SKILL_RESOURCE_LIST_LIMIT = 200;\n/** 资源目录递归最大深度 */\nexport const SKILL_RESOURCE_MAX_DEPTH = 8;\n/** 宿主显式启用截断时的建议上限;默认加载不截断 SKILL.md。 */\nexport const SKILL_MD_MAX_BYTES = 32_000;\n/** 单次发现最多暴露的 skill 数量 */\nexport const SKILL_DISCOVERY_LIMIT = 200;\n/** Skill catalog 的总字节上限,避免大量描述占满 system prompt。 */\nexport const SKILL_CATALOG_MAX_BYTES = 32_000;\n\nconst NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport interface SkillInfo {\n name: string;\n description: string;\n /** skill 目录绝对路径 */\n root: string;\n /** SKILL.md 绝对路径 */\n skillFile: string;\n /** 来源作用域:project 覆盖 user / extra */\n scope: \"project\" | \"user\" | \"extra\";\n license?: string;\n compatibility?: string;\n metadata?: Record<string, string>;\n /** 官方实验字段;本实现解析但不强制执行 */\n allowedTools?: string;\n warnings: string[];\n}\n\nexport interface SkillsContext {\n skills: SkillInfo[];\n warnings: string[];\n}\n\nexport interface DiscoverSkillsOptions {\n /** 额外 skills 根目录(优先级低于标准项目/用户路径,高于冲突时被标准路径压制) */\n extraDirs?: string[];\n /** 覆盖默认 home(测试用) */\n homeDir?: string;\n}\n\nexport interface LoadedSkillContent {\n /** SKILL.md 全文(含 frontmatter);超限时为合法 UTF-8 前缀 */\n content: string;\n /** 相对 skill 根的资源路径(不含 SKILL.md),跳过符号链接 */\n resources: string[];\n /** 正文是否因上限被截断 */\n contentTruncated: boolean;\n /** 资源清单是否因数量或深度上限被截断 */\n resourcesTruncated: boolean;\n /** 加载阶段的可恢复告警 */\n warnings: string[];\n}\n\ninterface SkillRoot {\n dir: string;\n scope: SkillInfo[\"scope\"];\n}\n\nfunction skillRoots(workdir: string, opts: DiscoverSkillsOptions): SkillRoot[] {\n const home = opts.homeDir ?? os.homedir();\n const project = path.resolve(workdir);\n const roots: SkillRoot[] = [\n { dir: path.join(project, \".agents\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".xlyra\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".codex\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".claude\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".pi\", \"skills\"), scope: \"project\" },\n { dir: path.join(home, \".agents\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".xlyra\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".codex\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".claude\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".pi\", \"agent\", \"skills\"), scope: \"user\" },\n ];\n for (const extra of opts.extraDirs ?? []) {\n // 配置中的相对路径以 workdir 为基准,绝对路径保持显式配置的语义。\n roots.push({\n dir: path.isAbsolute(extra) ? path.resolve(extra) : path.resolve(project, extra),\n scope: \"extra\",\n });\n }\n return roots;\n}\n\nfunction stringMap(value: unknown): Record<string, string> | undefined | null {\n if (value === undefined) return undefined;\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const out: Record<string, string> = {};\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n if (typeof entry !== \"string\") return null;\n out[key] = entry;\n }\n return out;\n}\n\nfunction stringField(value: unknown): string | undefined {\n return typeof value === \"string\" ? value.trim() : undefined;\n}\n\nfunction charLength(value: string): number {\n return [...value].length;\n}\n\nfunction parseFrontmatter(text: string): Record<string, unknown> | null {\n const normalized = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n const lines = normalized.split(/\\r?\\n/);\n if (lines[0] !== \"---\") return null;\n const end = lines.findIndex((line, index) => index > 0 && line === \"---\");\n if (end < 0) return null;\n\n let parsed: unknown;\n try {\n parsed = parseYaml(lines.slice(1, end).join(\"\\n\"));\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return null;\n return parsed as Record<string, unknown>;\n}\n\n/**\n * 解析单个 SKILL.md。返回 null 表示应跳过(缺必填或不符合规范)。\n * Skill specification 要求 name 与目录名一致;无效名称不进入 catalog。\n */\nexport function parseSkillFile(skillFile: string, skillRoot: string): SkillInfo | null {\n let text: string;\n try {\n text = fs.readFileSync(skillFile, \"utf-8\");\n } catch (err) {\n throw new Error(`无法读取 ${skillFile}:${err instanceof Error ? err.message : err}`);\n }\n\n const front = parseFrontmatter(text);\n if (!front) return null;\n\n const name = stringField(front.name);\n const description = stringField(front.description);\n if (!name || !description) return null;\n\n const dirName = path.basename(path.resolve(skillRoot));\n if (\n name !== dirName ||\n charLength(name) > 64 ||\n !NAME_PATTERN.test(name) ||\n name.startsWith(\"-\") ||\n name.endsWith(\"-\") ||\n name.includes(\"--\") ||\n charLength(description) > 1024\n ) {\n return null;\n }\n\n const compatibility = stringField(front.compatibility);\n if (front.compatibility !== undefined && (!compatibility || charLength(compatibility) > 500)) {\n return null;\n }\n\n const metadata = stringMap(front.metadata);\n if (metadata === null) return null;\n\n const warnings: string[] = [];\n if (description.length < 1) return null;\n if (typeof front.license !== \"undefined\" && typeof front.license !== \"string\") {\n warnings.push(`skill license 不是字符串:${name}`);\n }\n if (typeof front[\"allowed-tools\"] !== \"undefined\" && typeof front[\"allowed-tools\"] !== \"string\") {\n warnings.push(`skill allowed-tools 不是字符串,已忽略:${name}`);\n }\n\n return {\n name,\n description,\n root: path.resolve(skillRoot),\n skillFile: path.resolve(skillFile),\n scope: \"project\",\n warnings,\n ...(stringField(front.license) ? { license: stringField(front.license) } : {}),\n ...(compatibility ? { compatibility } : {}),\n ...(metadata ? { metadata } : {}),\n ...(stringField(front[\"allowed-tools\"]) ? { allowedTools: stringField(front[\"allowed-tools\"]) } : {}),\n };\n}\n\nexport function discoverSkills(\n workdir: string,\n opts: DiscoverSkillsOptions = {},\n): SkillsContext {\n const skills: SkillInfo[] = [];\n const warnings: string[] = [];\n const seen = new Map<string, SkillInfo>();\n let discovered = 0;\n\n // 扫描顺序:项目 → 用户 → extra;先到先得,项目天然覆盖用户\n for (const { dir, scope } of skillRoots(workdir, opts)) {\n if (discovered >= SKILL_DISCOVERY_LIMIT) {\n warnings.push(`skill 发现达到上限 ${SKILL_DISCOVERY_LIMIT},已停止扫描`);\n break;\n }\n let entries: fs.Dirent[];\n try {\n if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) continue;\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (err) {\n warnings.push(`无法扫描 skills 目录 ${dir}:${err instanceof Error ? err.message : err}`);\n continue;\n }\n\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n if (discovered >= SKILL_DISCOVERY_LIMIT) {\n warnings.push(`skill 发现达到上限 ${SKILL_DISCOVERY_LIMIT},已停止扫描`);\n break;\n }\n if (!entry.isDirectory() || entry.isSymbolicLink()) continue;\n discovered += 1;\n const skillRoot = path.join(dir, entry.name);\n const skillFile = path.join(skillRoot, \"SKILL.md\");\n try {\n const stat = fs.lstatSync(skillFile);\n if (stat.isSymbolicLink() || !stat.isFile()) continue;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n warnings.push(`无法检查 skill 文件:${skillFile}`);\n }\n continue;\n }\n\n let parsed: SkillInfo | null = null;\n try {\n parsed = parseSkillFile(skillFile, skillRoot);\n } catch (err) {\n warnings.push(`无法解析 ${skillFile}:${err instanceof Error ? err.message : err}`);\n continue;\n }\n if (!parsed) {\n warnings.push(`跳过不符合规范的 skill:${skillFile}`);\n continue;\n }\n\n parsed.scope = scope;\n warnings.push(...parsed.warnings);\n\n const existing = seen.get(parsed.name);\n if (existing) {\n warnings.push(\n `skill 名称冲突「${parsed.name}」:保留 ${existing.root},忽略 ${skillRoot}`,\n );\n continue;\n }\n seen.set(parsed.name, parsed);\n skills.push(parsed);\n }\n }\n\n return { skills, warnings };\n}\n\n/** 格式化为系统提示中的 skill 目录;无 skill 时返回空串(勿注入空段)。 */\nexport function formatSkillsCatalog(context: SkillsContext, maxBytes = SKILL_CATALOG_MAX_BYTES): string {\n if (context.skills.length === 0) return \"\";\n const lines = [\n \"# 可用 Agent Skills\",\n \"以下技能提供特定任务的专用指令。任务匹配某 skill 的描述时,先调用 load_skill(name) 加载全文,再按其指引行动。\",\n \"不要臆造未列出的 skill 名。相对路径相对于该 skill 目录;若路径在工作区外,现有文件沙箱仍会生效。\",\n ];\n let omitted = 0;\n for (const [index, skill] of context.skills.entries()) {\n const description = skill.description.replace(/\\s+/g, \" \").trim();\n const fullLine = `- ${skill.name}:${description}(${skill.skillFile})`;\n const compactLine = `- ${skill.name}`;\n if (Buffer.byteLength([...lines, fullLine].join(\"\\n\"), \"utf-8\") <= maxBytes) {\n lines.push(fullLine);\n continue;\n }\n // Keep every discovered name visible even when long descriptions or paths fill the budget.\n if (Buffer.byteLength([...lines, compactLine].join(\"\\n\"), \"utf-8\") <= maxBytes) {\n lines.push(compactLine);\n continue;\n }\n omitted = context.skills.length - index;\n break;\n }\n if (omitted > 0) {\n const marker = `- (skill catalog 已截断,尚有 ${omitted} 个 skill 未列出)`;\n if (Buffer.byteLength([...lines, marker].join(\"\\n\"), \"utf-8\") <= maxBytes) lines.push(marker);\n }\n return boundedUtf8Prefix(Buffer.from(lines.join(\"\\n\"), \"utf-8\"), maxBytes);\n}\n\nfunction boundedUtf8Prefix(data: Buffer, maxBytes: number): string {\n if (data.length <= maxBytes) return data.toString(\"utf-8\");\n let end = Math.max(0, maxBytes);\n while (end > 0) {\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(data.subarray(0, end));\n } catch {\n end -= 1;\n }\n }\n return \"\";\n}\n\n/** 激活时重新读取 SKILL.md,并枚举资源(不预读内容) */\nexport function loadSkillContent(\n info: SkillInfo,\n opts: {\n /** 显式设置时才启用正文截断;默认遵循规范完整读取。 */\n maxBytes?: number;\n resourceLimit?: number;\n maxDepth?: number;\n } = {},\n): LoadedSkillContent {\n const resourceLimit = opts.resourceLimit ?? SKILL_RESOURCE_LIST_LIMIT;\n const maxDepth = opts.maxDepth ?? SKILL_RESOURCE_MAX_DEPTH;\n const data = fs.readFileSync(info.skillFile);\n const contentTruncated = opts.maxBytes !== undefined && data.length > opts.maxBytes;\n const content = opts.maxBytes === undefined\n ? data.toString(\"utf-8\")\n : boundedUtf8Prefix(data, opts.maxBytes);\n const resources: string[] = [];\n const warnings: string[] = [];\n let resourcesTruncated = false;\n\n if (contentTruncated && opts.maxBytes !== undefined) {\n warnings.push(`SKILL.md 超过 ${opts.maxBytes} 字节,已截断注入;完整内容请用 read 工具读取 ${info.skillFile}`);\n }\n\n const walk = (dir: string, relative: string, depth: number): void => {\n if (resources.length >= resourceLimit) {\n resourcesTruncated = true;\n return;\n }\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n warnings.push(`无法扫描 skill 资源目录:${dir}`);\n return;\n }\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n if (resources.length >= resourceLimit) {\n resourcesTruncated = true;\n return;\n }\n if (entry.isSymbolicLink()) continue;\n const rel = relative ? `${relative}/${entry.name}` : entry.name;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (depth >= maxDepth) {\n resourcesTruncated = true;\n continue;\n }\n walk(full, rel, depth + 1);\n continue;\n }\n if (entry.isFile() && rel !== \"SKILL.md\") resources.push(rel.split(path.sep).join(\"/\"));\n }\n };\n\n walk(info.root, \"\", 0);\n if (resourcesTruncated) {\n warnings.push(`skill 资源清单超过限制(最多 ${resourceLimit} 项、深度 ${maxDepth}),仅列出部分路径`);\n }\n\n return { content, resources, contentTruncated, resourcesTruncated, warnings };\n}\n","/**\n * read 工具:读文本文件。\n *\n * 落地细节:\n * - offset(1 起)/ limit 分段读取;单次最多 2000 行或 50KB 先到为准,\n * 截断时在尾部附「继续读请传 offset=N」;\n * - 目录 → 报错并提示用 list;图片后缀 → 明确报错不支持(纯文本管线)。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst MAX_LINES = 2000;\nconst MAX_BYTES = 50_000;\n\nconst IMAGE_SUFFIXES = new Set([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\", \".svg\"]);\n\nconst argsSchema = z.object({\n path: z.string(),\n offset: z.number().int().min(1).default(1),\n limit: z.number().int().min(1).optional(),\n});\n\nexport function makeReadTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"read\",\n description:\n \"读取文本文件内容。单次最多返回 2000 行或 50KB(先到为准),\" +\n \"大文件用 offset/limit 分段读取,直到读完为止。不支持图片。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: true, parallelSafe: true },\n handler: async (args) => {\n const { path: rawPath, offset, limit } = argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(file)) throw new Error(`文件不存在:${rawPath}`);\n if (fs.statSync(file).isDirectory()) {\n throw new Error(`${rawPath} 是目录不是文件;查看目录内容请用 list 工具`);\n }\n if (IMAGE_SUFFIXES.has(path.extname(file).toLowerCase())) {\n throw new Error(\"暂不支持读取图片文件,只支持文本文件\");\n }\n\n const lines = fs.readFileSync(file, \"utf-8\").split(\"\\n\");\n const total = lines.length;\n if (offset > total && total > 0) {\n throw new Error(`offset 超出范围:文件共 ${total} 行,offset=${offset}`);\n }\n const cap = Math.min(limit ?? MAX_LINES, MAX_LINES);\n const window = lines.slice(offset - 1, offset - 1 + cap);\n\n // 字节上限:逐行累加,超限即停\n const picked: string[] = [];\n let size = 0;\n for (const line of window) {\n size += Buffer.byteLength(line, \"utf-8\") + 1;\n if (picked.length > 0 && size > MAX_BYTES) break;\n picked.push(line);\n }\n const end = offset - 1 + picked.length;\n\n let body = picked.join(\"\\n\");\n if (end < total) {\n body += `\\n(文件共 ${total} 行,本次返回第 ${offset}-${end} 行;继续读取请传 offset=${end + 1})`;\n }\n return body || \"(空文件)\";\n },\n };\n}\n","/** 文件内容搜索工具:有界遍历、跳过二进制与常见生成目录。 */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst MAX_FILE_BYTES = 2 * 1024 * 1024;\nconst HARD_MAX_RESULTS = 500;\nconst IGNORE_NAMES = new Set([\n \".git\", \"node_modules\", \"dist\", \".next\", \"out\", \"coverage\", \".turbo\", \".cache\",\n \"__pycache__\", \".venv\",\n]);\n\nconst argsSchema = z.object({\n query: z.string().min(1),\n path: z.string().default(\".\"),\n glob: z.string().optional(),\n case_sensitive: z.boolean().default(false),\n max_results: z.number().int().min(1).max(HARD_MAX_RESULTS).default(100),\n});\n\nexport function makeSearchTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"search\",\n description:\n \"在工作区文本文件中搜索内容,返回 path:line:match。可用 glob 按文件路径筛选,\" +\n \"例如 **/*.ts;默认忽略 .git、node_modules、dist 等目录和二进制文件。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: true, parallelSafe: true },\n handler: async (args, context) => {\n const parsed = argsSchema.parse(args);\n const target = resolveSandboxed(workdir, parsed.path, sandbox);\n if (!fs.existsSync(target)) throw new Error(`路径不存在:${parsed.path}`);\n const matcher = parsed.glob ? globToRegExp(parsed.glob) : null;\n const needle = parsed.case_sensitive ? parsed.query : parsed.query.toLocaleLowerCase();\n const results: string[] = [];\n let truncated = false;\n\n const visit = (entryPath: string): void => {\n if (context?.signal?.aborted || results.length >= parsed.max_results) {\n truncated = results.length >= parsed.max_results;\n return;\n }\n const lstat = fs.lstatSync(entryPath);\n if (lstat.isSymbolicLink()) return;\n const stat = lstat;\n if (stat.isDirectory()) {\n for (const entry of fs.readdirSync(entryPath, { withFileTypes: true })) {\n if (IGNORE_NAMES.has(entry.name)) continue;\n visit(path.join(entryPath, entry.name));\n if (results.length >= parsed.max_results || context?.signal?.aborted) break;\n }\n return;\n }\n const relative = path.relative(workdir, entryPath) || path.basename(entryPath);\n const portable = relative.split(path.sep).join(\"/\");\n if (matcher && !matcher.test(portable)) return;\n if (stat.size > MAX_FILE_BYTES || isBinary(entryPath)) return;\n let text: string;\n try {\n text = fs.readFileSync(entryPath, \"utf-8\");\n } catch {\n return;\n }\n for (const [index, line] of text.split(\"\\n\").entries()) {\n const haystack = parsed.case_sensitive ? line : line.toLocaleLowerCase();\n if (!haystack.includes(needle)) continue;\n results.push(`${portable}:${index + 1}:${line}`);\n if (results.length >= parsed.max_results) {\n truncated = true;\n break;\n }\n }\n };\n\n visit(target);\n if (context?.signal?.aborted) throw new Error(\"搜索已取消\");\n if (results.length === 0) return `未找到匹配:${parsed.query}`;\n return results.join(\"\\n\") +\n (truncated ? `\\n(结果已截断到 ${parsed.max_results} 条;请缩小 path 或 glob)` : \"\");\n },\n };\n}\n\nfunction isBinary(file: string): boolean {\n const fd = fs.openSync(file, \"r\");\n try {\n const buffer = Buffer.alloc(4096);\n const read = fs.readSync(fd, buffer, 0, buffer.length, 0);\n return buffer.subarray(0, read).includes(0);\n } finally {\n fs.closeSync(fd);\n }\n}\n\nfunction globToRegExp(glob: string): RegExp {\n let source = \"\";\n for (let index = 0; index < glob.length; index += 1) {\n const char = glob[index]!;\n if (char === \"*\") {\n if (glob[index + 1] === \"*\") {\n if (glob[index + 2] === \"/\") {\n source += \"(?:.*/)?\";\n index += 2;\n } else {\n source += \".*\";\n index += 1;\n }\n } else {\n source += \"[^/]*\";\n }\n } else if (char === \"?\") {\n source += \"[^/]\";\n } else {\n source += char.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\");\n }\n }\n return new RegExp(`^${source}$`);\n}\n","/**\n * write 工具:覆盖写已有文件(不存在则失败)。\n *\n * 与 create 形成对称硬闸(见 create.ts)。写入用临时文件 + rename 原子换入:\n * 写一半进程崩溃要么旧文件完好、要么新文件完整,不留残文件。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst argsSchema = z.object({\n path: z.string(),\n content: z.string(),\n});\n\nexport function makeWriteTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"write\",\n description:\n \"整体覆盖已有文件的内容。目标不存在时失败——新建文件请用 create 工具。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { path: rawPath, content } = argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(file)) {\n throw new Error(`文件不存在:${rawPath};新建文件请用 create 工具`);\n }\n if (fs.statSync(file).isDirectory()) {\n throw new Error(`${rawPath} 是目录不是文件`);\n }\n // 同目录临时文件 + rename:保证原子性(同文件系统内 rename 才原子)\n const tmp = path.join(\n path.dirname(file),\n `.xlyra-tmp-${crypto.randomUUID()}${path.extname(file)}`,\n );\n try {\n fs.writeFileSync(tmp, content);\n fs.renameSync(tmp, file);\n } catch (err) {\n fs.rmSync(tmp, { force: true });\n throw err;\n }\n return `已覆盖 ${rawPath}(${content.length} 字符,${content.split(\"\\n\").length} 行)`;\n },\n };\n}\n","import { z } from \"zod\";\nimport { COMMAND_EXECUTION_GRANT, EscalationRequiredError } from \"../agent/escalation.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport { formatProcessResult } from \"./exec-command.js\";\nimport { ProcessManager } from \"./process-manager.js\";\nimport type { AgentTool } from \"./types.js\";\n\nconst argsSchema = z.object({\n session_id: z.string().min(1),\n chars: z.string().optional(),\n yield_time_ms: z.number().int().min(0).max(600_000).default(30_000),\n max_output_bytes: z.number().int().min(1_000).max(100_000).default(50_000),\n});\n\nexport function makeWriteStdinTool(manager: ProcessManager, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"write_stdin\",\n description:\n \"继续读取 exec_command 返回的进程会话;提供 chars 时先向进程标准输入写入内容。\" +\n \"等待长任务输出时务必把 yield_time_ms 设大(建议 120000,进程结束会立即返回),避免短时间反复空轮询;\" +\n \"仅当需要向进程输入内容时才提供 chars。交互式输入通常需要自行附加换行符。\" +\n \"使用前可能需要用户授权。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const parsed = argsSchema.parse(args);\n const commandAllowed = sandbox.commandExecutionEnabled === true\n || (sandbox.grants !== undefined && sandbox.sessionId !== undefined\n && sandbox.grants.isCapabilityGranted(sandbox.sessionId, COMMAND_EXECUTION_GRANT));\n if (!commandAllowed) {\n throw new EscalationRequiredError(\n `exec_command session ${parsed.session_id}`,\n COMMAND_EXECUTION_GRANT,\n \"继续命令会话需要用户授权\",\n \"command\",\n );\n }\n if (parsed.chars !== undefined) manager.write(parsed.session_id, parsed.chars);\n const result = await manager.poll(parsed.session_id, parsed.yield_time_ms, parsed.max_output_bytes);\n return formatProcessResult(result);\n },\n };\n}\n","/**\n * 服务装配:把配置、协议路由、存储、注册表、路由组装成一个可运行的服务。\n */\nimport path from \"node:path\";\nimport { serve } from \"@hono/node-server\";\nimport type { Hono } from \"hono\";\nimport { defaultDataDir, AgentSessionStore } from \"../agent/sessions.js\";\nimport { EscalationGrants } from \"../agent/escalation.js\";\nimport { EndpointResolver } from \"../llm/router.js\";\nimport { builtinTools } from \"../tools/index.js\";\nimport { loadConfig, type AppConfig } from \"./config.js\";\nimport { createConfigRoutes } from \"./config-routes.js\";\nimport { AgentRunRecorder } from \"./recorder.js\";\nimport { createAgentRoutes } from \"./routes.js\";\nimport { RunRegistry } from \"./run-registry.js\";\nimport { SessionIndex } from \"./session-index.js\";\n\nexport interface AgentServer {\n app: Hono;\n registry: RunRegistry;\n store: AgentSessionStore;\n index: SessionIndex;\n}\n\n/** 以代码方式装配服务(嵌入用法) */\nexport function createAgentServer(\n config: AppConfig,\n opts: { configPath?: string; dataDir?: string } = {},\n): AgentServer {\n const dataDir = path.resolve(opts.dataDir ?? defaultDataDir());\n const configPath = opts.configPath ?? path.join(dataDir, \"config.json\");\n const resolver = new EndpointResolver(config.endpoints);\n const store = new AgentSessionStore(path.join(dataDir, \"sessions\"));\n const index = new SessionIndex(path.join(dataDir, \"index.json\"));\n // 启动自愈:从事实源(JSONL 文件)整体重建索引\n index.rebuild(store.scanAll());\n const registry = new RunRegistry();\n const workdir = path.resolve(config.agent?.workdir ?? path.join(dataDir, \"workspace\"));\n const grants = new EscalationGrants();\n const buildWorkspaceContext = (agentConfig: AppConfig[\"agent\"]) => ({\n enableAgentsMd: agentConfig?.enable_agents_md !== false,\n enableSkills: agentConfig?.enable_skills !== false,\n ...(agentConfig?.disabled_skills?.length ? { disabledSkills: agentConfig.disabled_skills } : {}),\n ...(agentConfig?.skills_dirs?.length ? { skills: { extraDirs: agentConfig.skills_dirs } } : {}),\n });\n // 每次 run 前重新读配置装配上下文选项:Web 端改开关/停用名单后下一轮对话即生效,\n // 无需重启服务;配置损坏时回退启动时的快照\n const startupWorkspaceContext = buildWorkspaceContext(config.agent);\n const resolveWorkspaceContext = () => {\n try {\n return buildWorkspaceContext(loadConfig(configPath).agent);\n } catch (error) {\n console.warn(`[workspace-context] 配置读取失败,沿用启动快照:${error instanceof Error ? error.message : error}`);\n return startupWorkspaceContext;\n }\n };\n const app = createAgentRoutes({\n resolver,\n store,\n index,\n registry,\n grants,\n makeTools: (sessionId, skills) => builtinTools({\n workdir,\n grants,\n sessionId,\n enableCommandExecution: config.agent?.enable_command_execution ?? false,\n ...(skills?.length ? { skills } : {}),\n }),\n workdir,\n workspaceContext: startupWorkspaceContext,\n resolveWorkspaceContext,\n ...(config.agent?.agent_name ? { agentName: config.agent.agent_name } : {}),\n ...(config.agent?.persona ? { persona: config.agent.persona } : {}),\n ...(config.agent?.agent_instance_id ? { agentInstanceId: config.agent.agent_instance_id } : {}),\n ...(config.server?.token ? { token: config.server.token } : {}),\n });\n // 配置管理 API。\n const configRoutes = createConfigRoutes({ configPath });\n if (config.server?.token) {\n configRoutes.use(\"*\", async (c, next) => {\n const header = c.req.header(\"authorization\") ?? \"\";\n if (header !== `Bearer ${config.server!.token}`) {\n return c.json({ success: false, code: 401, message: \"未授权:缺少或错误的 Bearer token\" }, 401);\n }\n await next();\n });\n }\n app.route(\"/\", configRoutes);\n return { app, registry, store, index };\n}\n\n/** 以配置文件启动 HTTP 服务(CLI serve 命令) */\nexport function serveFromConfig(opts: { configPath?: string; port?: number; dataDir?: string }): void {\n const dataDir = opts.dataDir ? path.resolve(opts.dataDir) : defaultDataDir();\n const configPath = opts.configPath ?? path.join(dataDir, \"config.json\");\n const config = loadConfig(configPath);\n const { app } = createAgentServer(config, { configPath, dataDir });\n const port = opts.port ?? config.server?.port ?? 3210;\n const server = serve({ fetch: app.fetch, port }, (info) => {\n console.log(`xlyra-agent 服务已启动:http://127.0.0.1:${info.port}`);\n console.log(`数据目录:${dataDir}(sessions/ 会话转录,workspace/ 工具工作区)`);\n if (!config.server?.token) {\n console.warn(\"⚠ 未配置 server.token,接口无鉴权——请勿暴露到公网\");\n }\n });\n // 优雅退出:tsx watch 重启依赖进程响应 SIGTERM;\n // SSE 长连接会拖住 server.close(),2 秒兜底强退\n const shutdown = () => {\n server.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 2000).unref();\n };\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n}\n\nexport { AgentRunRecorder, RunRegistry, SessionIndex };\nexport { createAgentRoutes } from \"./routes.js\";\nexport {\n loadConfig,\n saveConfig,\n upsertEndpoint,\n removeEndpoint,\n configExists,\n defaultConfigPath,\n} from \"./config.js\";\nexport type { AppConfig, ServerConfig, AgentServiceConfig } from \"./config.js\";\nexport { createConfigRoutes } from \"./config-routes.js\";\nexport { HttpError, type StoredAgentEvent } from \"./run-registry.js\";\n","/**\n * 服务配置:~/.xlyra-agent/config.json。\n *\n * 职责:\n * - 端点配置(base_url / api_key / models / protocol 类型)统一落在这里,\n * 由 `xlyra config` 子命令管理(add/list/remove),也可手编;\n * - api_key 支持 \"${ENV_VAR}\" 环境变量插值——配置文件可以入库/共享而不泄漏\n * 凭证;\n * - 加载时经 Zod schema 校验:结构错误在启动时给出明确中文报错,\n * 而不是运行到一半才以奇怪方式失败;\n * - 保存一律 tmp + rename 原子换入。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { defaultDataDir } from \"../agent/sessions.js\";\n\n// ---------------------------------------------------------------------------\n// Schema(加载/保存共用同一份定义,防漂移)\n// ---------------------------------------------------------------------------\n\nconst endpointSchema = z\n .object({\n name: z.string().min(1, \"端点名不能为空\"),\n protocol: z.enum([\"openai-responses\", \"anthropic-messages\"]),\n /** 省略时按 direct 处理(兼容旧配置) */\n mode: z.enum([\"direct\", \"remote-xlyra\"]).default(\"direct\"),\n base_url: z.url(\"base_url 必须是合法 URL\"),\n api_key: z.string().min(1, \"api_key 不能为空(可用 ${ENV_VAR} 引用环境变量)\").optional(),\n credential: z\n .discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"temporary-bearer\"),\n token: z.string().min(1, \"credential.token 不能为空(可用 ${ENV_VAR} 引用环境变量)\"),\n }),\n z.object({\n type: z.literal(\"xlyra-callback\"),\n url: z.url(\"credential.url 必须是合法 URL\"),\n }),\n ])\n .optional(),\n models: z.record(z.string(), z.object({ context_window: z.number().positive().optional() })).optional(),\n default_model: z.string().optional(),\n })\n .superRefine((endpoint, ctx) => {\n // 凭证互斥规则(docs 第 4/5 章):direct 只要 api_key;remote-xlyra 只要 credential\n if (endpoint.mode === \"remote-xlyra\") {\n if (!endpoint.credential) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"credential\"],\n message: \"remote-xlyra 模式必须配置临时凭证(temporary-bearer 或 xlyra-callback)\",\n });\n }\n if (endpoint.api_key !== undefined) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"api_key\"],\n message: \"remote-xlyra 模式不允许配置 api_key\",\n });\n }\n return;\n }\n\n if (!endpoint.api_key) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"api_key\"],\n message: \"direct 模式必须配置 api_key\",\n });\n }\n if (endpoint.credential !== undefined) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"credential\"],\n message: \"direct 模式不允许配置 credential\",\n });\n }\n });\n\nconst appConfigSchema = z.object({\n endpoints: z.array(endpointSchema).min(1, \"endpoints 为空:至少配置一个模型端点\"),\n server: z\n .object({\n port: z.number().int().positive().optional(),\n token: z.string().optional(),\n })\n .optional(),\n agent: z\n .object({\n workdir: z.string().optional(),\n agent_name: z.string().optional(),\n persona: z.string().optional(),\n /** 部署方注入的 agent 实例标识(xlyra-callback 凭证用),run 启动参数可覆盖 */\n agent_instance_id: z.string().optional(),\n /** 本机命令可访问当前用户权限范围内的系统资源,必须显式开启。 */\n enable_command_execution: z.boolean().optional(),\n /** 是否注入 workdir 下的 AGENTS.md(默认 true) */\n enable_agents_md: z.boolean().optional(),\n /** 是否发现并暴露 Agent Skills(默认 true) */\n enable_skills: z.boolean().optional(),\n /** 停用的 skill 名称名单(不删文件,run 时跳过注入;在 enable_skills 之后生效) */\n disabled_skills: z.array(z.string()).optional(),\n /** 额外 skills 根目录(不替换标准路径) */\n skills_dirs: z.array(z.string()).optional(),\n })\n .optional(),\n});\n\nexport type AppConfig = z.infer<typeof appConfigSchema>;\n/** 配置输入类型:mode 等带默认值的字段可省略(saveConfig 校验时补齐) */\nexport type AppConfigInput = z.input<typeof appConfigSchema>;\nexport type ServerConfig = NonNullable<AppConfig[\"server\"]>;\nexport type AgentServiceConfig = NonNullable<AppConfig[\"agent\"]>;\n/** 端点输入类型:mode 可省略(schema 解析后补 direct),供 CLI/调用方构造 */\nexport type EndpointInput = z.input<typeof endpointSchema>;\n/** 供 config-routes 的 PUT payload 复用(保证加载/写入同一套校验规则) */\nexport { endpointSchema, appConfigSchema };\n\n// ---------------------------------------------------------------------------\n// 路径与读写\n// ---------------------------------------------------------------------------\n\nexport function defaultConfigPath(): string {\n return path.join(defaultDataDir(), \"config.json\");\n}\n\n/** 加载并校验配置;文件不存在/结构非法时抛出明确中文错误 */\nexport function loadConfig(configPath?: string): AppConfig {\n const file = configPath ?? defaultConfigPath();\n if (!fs.existsSync(file)) {\n throw new Error(\n `配置文件不存在:${file}\\n先运行 xlyra config init 交互式创建,或参考 README 手工编写。`,\n );\n }\n let raw: unknown;\n try {\n raw = JSON.parse(fs.readFileSync(file, \"utf-8\"));\n } catch (err) {\n throw new Error(`配置文件不是合法 JSON:${file}(${err instanceof Error ? err.message : err})`);\n }\n const parsed = appConfigSchema.safeParse(raw);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => ` - ${i.path.join(\".\") || \"(根)\"}:${i.message}`)\n .join(\"\\n\");\n throw new Error(`配置文件校验失败:${file}\\n${issues}`);\n }\n for (const endpoint of parsed.data.endpoints) {\n if (endpoint.api_key !== undefined) {\n endpoint.api_key = interpolateEnv(endpoint.api_key, file);\n }\n if (endpoint.credential?.type === \"temporary-bearer\") {\n endpoint.credential.token = interpolateEnv(endpoint.credential.token, file);\n }\n }\n return parsed.data;\n}\n\n/** 保存配置(schema 校验并补默认值,tmp + rename 原子写入)。\n * 配置可能含凭证:目录 0700、文件 0600(docs §12.4) */\nexport function saveConfig(config: AppConfigInput, configPath?: string): void {\n const file = configPath ?? defaultConfigPath();\n const validated = appConfigSchema.parse(config);\n fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });\n const tmp = `${file}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(validated, null, 2) + \"\\n\", { mode: 0o600 });\n fs.renameSync(tmp, file);\n // rename 保留 tmp 的权限;对既有文件(早期版本可能更宽)显式收紧\n fs.chmodSync(file, 0o600);\n}\n\n/** 配置是否存在(config init 判重 / 首次运行引导用) */\nexport function configExists(configPath?: string): boolean {\n return fs.existsSync(configPath ?? defaultConfigPath());\n}\n\n// ---------------------------------------------------------------------------\n// 端点管理(config add/remove 子命令的实现)\n// ---------------------------------------------------------------------------\n\n/** 新增或更新端点(按 name 匹配,同名覆盖);返回写入后的完整配置 */\nexport function upsertEndpoint(\n endpoint: EndpointInput,\n configPath?: string,\n): AppConfig {\n const file = configPath ?? defaultConfigPath();\n let config: AppConfig;\n if (fs.existsSync(file)) {\n // 已有配置:加载校验后合并(loadConfig 会插值 api_key,写回前需还原原始配置——\n // 因此这里读原始 JSON 而不是走 loadConfig)\n const raw = JSON.parse(fs.readFileSync(file, \"utf-8\")) as AppConfig;\n config = appConfigSchema.parse({ ...raw, endpoints: raw.endpoints ?? [] });\n } else {\n config = { endpoints: [] };\n }\n const idx = config.endpoints.findIndex((e) => e.name === endpoint.name);\n // 先单条过 schema(补 mode 默认值并执行互斥校验),再合并进整体配置\n const parsedEndpoint = endpointSchema.parse(endpoint);\n if (idx >= 0) {\n config.endpoints[idx] = parsedEndpoint;\n } else {\n config.endpoints.push(parsedEndpoint);\n }\n // 写回前整体过一遍 schema(endpoints 至少一条此时必然成立)\n const validated = appConfigSchema.parse(config);\n saveConfig(validated, file);\n return validated;\n}\n\n/** 按 name 删除端点;不存在时返回 false。不允许删除最后一条(配置必须非空) */\nexport function removeEndpoint(name: string, configPath?: string): boolean {\n const file = configPath ?? defaultConfigPath();\n if (!fs.existsSync(file)) return false;\n const raw = JSON.parse(fs.readFileSync(file, \"utf-8\")) as AppConfig;\n const endpoints = (raw.endpoints ?? []).filter((e) => e.name !== name);\n if (endpoints.length === (raw.endpoints ?? []).length) return false;\n if (endpoints.length === 0) {\n throw new Error(`不能删除最后一个端点(配置必须保留至少一个模型端点):${file}`);\n }\n saveConfig({ ...raw, endpoints }, file);\n return true;\n}\n\n/** \"${ENV_VAR}\" → 环境变量值;未设置时报出可读错误 */\nfunction interpolateEnv(value: string, file: string): string {\n return value.replace(/\\$\\{([A-Z0-9_]+)\\}/g, (whole, name: string) => {\n const v = process.env[name];\n if (v === undefined) {\n throw new Error(`配置文件 ${file} 引用了未设置的环境变量 ${name}(来自 \"${whole}\")`);\n }\n return v;\n });\n}\n","/**\n * 配置管理 API:\n * - GET /config 读取完整配置;api_key 打码回显(头 4 + 尾 4),\n * \"${ENV_VAR}\" 引用保持原文不插值——不回显真实凭证;\n * - PUT /config 整体保存配置(经 schema 校验,原子写盘);\n * - POST /config/test 端点连通性测试(最小真实调用,返回延迟/错误)。\n *\n * 注意:PUT 只落盘——运行中的服务下一次请求才生效的部分(工具 workdir 等\n * 启动期装配的项)需要重启服务;端点列表由 EndpointResolver 惰性构建,\n * 新增端点保存后立即可用。\n */\nimport { Hono } from \"hono\";\nimport fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { resolveCredentialProvider } from \"../llm/credential.js\";\nimport { AnthropicMessagesProtocol } from \"../llm/protocols/messages.js\";\nimport { OpenAIResponsesProtocol } from \"../llm/protocols/responses.js\";\nimport type { EndpointCredential } from \"../llm/router.js\";\nimport {\n appConfigSchema,\n endpointSchema,\n loadConfig,\n saveConfig,\n type AppConfig,\n} from \"./config.js\";\nimport { HttpError } from \"./run-registry.js\";\n\nexport interface ConfigRoutesContext {\n configPath: string;\n}\n\n/** api_key/token 打码:只留头 4 尾 4;\"${ENV_VAR}\" 引用原样保留(不是真实凭证) */\nfunction maskApiKey(key: string): string {\n if (key.includes(\"${\")) return key;\n if (key.length <= 8) return \"****\";\n return `${key.slice(0, 4)}…${key.slice(-4)}`;\n}\n\n/**\n * credential 打码回显:\n * - temporary-bearer:token 比照 api_key 打码(PUT 回传打码值时据此保留原值);\n * - xlyra-callback:运行时 token 只在内存,不回显不掩码,只报 configured 状态。\n */\nfunction maskCredential(credential: EndpointCredential): Record<string, unknown> {\n if (credential.type === \"temporary-bearer\") {\n return { type: credential.type, token: maskApiKey(credential.token) };\n }\n return {\n type: credential.type,\n url: credential.url,\n configured: true,\n };\n}\n\ntype MaskedEndpoint = Omit<AppConfig[\"endpoints\"][number], \"api_key\" | \"credential\"> & {\n api_key?: string;\n credential?: Record<string, unknown>;\n};\n\nfunction maskedConfig(config: AppConfig): Omit<AppConfig, \"endpoints\"> & { endpoints: MaskedEndpoint[] } {\n return {\n ...config,\n endpoints: config.endpoints.map((e) => ({\n ...e,\n ...(e.api_key !== undefined ? { api_key: maskApiKey(e.api_key) } : {}),\n ...(e.credential ? { credential: maskCredential(e.credential) } : {}),\n })),\n };\n}\n\n/**\n * 保留语义(以磁盘原始值为准):\n * - incoming 与原始值一致(含 \"${ENV_VAR}\" 引用原样回传)→ 保留原始值;\n * - incoming 是插值后真实值的打码形式 → 保留原始值(可能是引用,不写明文);\n * - 其余 → 按新值。\n */\nfunction retainSecret(\n incoming: string | undefined,\n existingRaw: string | undefined,\n existingResolved: string | undefined,\n): string | undefined {\n if (incoming === undefined || existingRaw === undefined) return incoming;\n if (incoming === existingRaw) return existingRaw;\n if (existingResolved !== undefined && incoming === maskApiKey(existingResolved)) return existingRaw;\n return incoming;\n}\n\n/**\n * credential 保留语义:\n * - temporary-bearer:token 走 retainSecret(原始值可能是 \"${ENV_VAR}\" 引用);\n * - xlyra-callback:type+url 与现有一致(含只带 configured 标记的回传)→ 保留原有配置;\n * - 其余情况按新值保存(由 schema 校验)。\n */\nfunction retainCredential(\n incoming: EndpointCredential | undefined,\n existingRaw: AppConfig[\"endpoints\"][number] | undefined,\n existingResolved: AppConfig[\"endpoints\"][number] | undefined,\n): EndpointCredential | undefined {\n const prevRaw = existingRaw?.credential;\n const prevResolved = existingResolved?.credential;\n if (!incoming || !prevRaw) return incoming;\n if (prevRaw.type === \"temporary-bearer\" && incoming.type === \"temporary-bearer\") {\n const resolvedToken = prevResolved?.type === \"temporary-bearer\" ? prevResolved.token : undefined;\n const token = retainSecret(incoming.token, prevRaw.token, resolvedToken);\n return token === undefined ? incoming : { type: \"temporary-bearer\", token };\n }\n if (prevRaw.type === \"xlyra-callback\" && incoming.type === \"xlyra-callback\" && incoming.url === prevRaw.url) {\n return prevRaw;\n }\n return incoming;\n}\n\nconst putPayloadSchema = z.object({\n endpoints: z.array(endpointSchema).min(1, \"endpoints 为空:至少配置一个模型端点\"),\n /** 显式确认修改 remote-xlyra 端点的 base_url/callback 地址(SSRF 防护闸) */\n allow_remote_endpoint_override: z.boolean().optional(),\n server: z.object({ port: z.number().int().positive().optional(), token: z.string().optional() }).optional(),\n agent: z.object({\n workdir: z.string().optional(),\n agent_name: z.string().optional(),\n persona: z.string().optional(),\n agent_instance_id: z.string().optional(),\n enable_command_execution: z.boolean().optional(),\n enable_agents_md: z.boolean().optional(),\n enable_skills: z.boolean().optional(),\n disabled_skills: z.array(z.string()).optional(),\n skills_dirs: z.array(z.string()).optional(),\n }).optional(),\n});\n\n/**\n * 读取磁盘上的原始配置(未插值):PUT 的保留语义必须以原始值为准,\n * 否则 loadConfig 插值后的明文会把磁盘上的 \"${ENV_VAR}\" 引用固化成明文。\n */\nfunction loadRawConfig(configPath: string): AppConfig {\n const raw = JSON.parse(fs.readFileSync(configPath, \"utf-8\")) as unknown;\n return appConfigSchema.parse(raw);\n}\n\nexport function createConfigRoutes(ctx: ConfigRoutesContext): Hono {\n const app = new Hono();\n\n app.onError((err, c) => {\n if (err instanceof HttpError) {\n return c.json({ success: false, code: err.status, message: err.message }, err.status as 400);\n }\n console.error(`配置接口处理失败:${err instanceof Error ? err.message : err}`);\n return c.json({ success: false, code: 500, message: err instanceof Error ? err.message : \"服务内部错误\" }, 500);\n });\n\n /** 读取配置(api_key 打码) */\n app.get(\"/config\", (c) => {\n const config = loadConfig(ctx.configPath);\n return c.json({ success: true, code: 0, message: \"\", data: maskedConfig(config) });\n });\n\n /**\n * 整体保存配置。api_key / credential.token 与打码形式一致(含 …)时视为\n * 「未修改」,保留磁盘上的原值——Web 表单回显打码值后直接提交不会把凭证冲掉。\n * xlyra-callback 回传 type+url(或 configured 标记)视为未修改。\n * 保留比对基于磁盘原始值:含 \"${ENV_VAR}\" 的引用保持引用形态,不回写明文。\n */\n app.put(\"/config\", async (c) => {\n const payload = putPayloadSchema.parse(await c.req.json());\n const current = loadRawConfig(ctx.configPath); // 原始值(可能含 ${ENV_VAR})\n const resolved = loadConfig(ctx.configPath); // 插值后的真实值(打码基准)\n const endpoints = payload.endpoints.map((incoming) => {\n const existingRaw = current.endpoints.find((e) => e.name === incoming.name);\n const existingResolved = resolved.endpoints.find((e) => e.name === incoming.name);\n const apiKey = retainSecret(incoming.api_key, existingRaw?.api_key, existingResolved?.api_key);\n const credential = retainCredential(incoming.credential, existingRaw, existingResolved);\n const merged = { ...incoming, credential };\n if (apiKey !== undefined) merged.api_key = apiKey;\n else delete merged.api_key;\n\n // SSRF 防护(docs §5/§12.5):已存在的 remote-xlyra 端点,普通 PUT 修改\n // base_url 或 callback url 需要显式确认——这两个地址决定 agent 的 LLM 流量\n // 与 run 标识上下文发往何处,默认只能由 runner/受信接口生成配置时设定。\n if (incoming.mode === \"remote-xlyra\" && existingRaw?.mode === \"remote-xlyra\") {\n const callbackUrlChanged =\n incoming.credential?.type === \"xlyra-callback\" &&\n existingRaw.credential?.type === \"xlyra-callback\" &&\n incoming.credential.url !== existingRaw.credential.url;\n if (incoming.base_url !== existingRaw.base_url || callbackUrlChanged) {\n if (payload.allow_remote_endpoint_override !== true) {\n throw new HttpError(\n 400,\n `端点 ${incoming.name} 是 remote-xlyra 模式,base_url/callback 地址只能由 runner 或受信任管理接口修改(PUT 需带 allow_remote_endpoint_override: true 显式确认)`,\n );\n }\n }\n }\n return merged;\n });\n // 保留语义合并后再整体过一遍 schema(互斥规则在最终形态上校验)\n const next: AppConfig = appConfigSchema.parse({\n endpoints,\n ...(payload.server ? { server: payload.server } : {}),\n ...(payload.agent ? { agent: payload.agent } : {}),\n });\n saveConfig(next, ctx.configPath);\n return c.json({ success: true, code: 0, message: \"配置已保存(部分启动期装配项需重启服务后生效)\", data: maskedConfig(next) });\n });\n\n /**\n * 端点连通性测试:一次最小真实调用(max_tokens=1),返回延迟或错误。\n * xlyra-callback 的 callback 需要 session_id/run_id 才能签发 token,\n * 无活动 run 上下文时不可测试,返回明确错误(docs §10.3)。\n */\n app.post(\"/config/test\", async (c) => {\n const { name } = z.object({ name: z.string().min(1) }).parse(await c.req.json());\n const config = loadConfig(ctx.configPath);\n const endpoint = config.endpoints.find((e) => e.name === name);\n if (!endpoint) throw new HttpError(404, `端点不存在:${name}`);\n if (endpoint.mode === \"remote-xlyra\" && endpoint.credential?.type === \"xlyra-callback\") {\n throw new HttpError(400, `端点 ${name} 使用 xlyra-callback 凭证,需在 run 上下文中测试(此处无活动 run)`);\n }\n const model = endpoint.default_model ?? Object.keys(endpoint.models ?? {})[0];\n if (!model) throw new HttpError(400, `端点 ${name} 未配置 default_model 或 models,无法测试`);\n const credential = resolveCredentialProvider(endpoint);\n const protocol =\n endpoint.protocol === \"anthropic-messages\"\n ? new AnthropicMessagesProtocol({ baseUrl: endpoint.base_url, credential, providerName: endpoint.name })\n : new OpenAIResponsesProtocol({ baseUrl: endpoint.base_url, credential, providerName: endpoint.name });\n\n const started = Date.now();\n for await (const event of protocol.chatStream({\n model,\n messages: [{ role: \"user\", content: \"ping\" }],\n settings: { max_tokens: endpoint.protocol === \"anthropic-messages\" ? 16 : 16 },\n })) {\n if (event.type === \"error\") {\n return c.json({ success: false, code: 502, message: `连通性测试失败:${event.error}`, data: null }, 502);\n }\n if (event.type === \"done\") {\n return c.json({\n success: true, code: 0,\n message: `端点 ${name} 连通正常(${Date.now() - started}ms)`,\n data: { elapsed_ms: Date.now() - started, model: event.response.model || model },\n });\n }\n }\n return c.json({ success: false, code: 502, message: \"连通性测试失败:流异常终止\", data: null }, 502);\n });\n\n return app;\n}\n","/**\n * 进程内 Agent 运行注册表:后台执行、事件回放与广播订阅。\n *\n * 设计(移植自 MovieClaw agent_runs.py):为每次运行维护一份只追加的事件\n * 日志,订阅者各自持有序号游标——不用消息队列(队列消息只会被一个消费者\n * 取走,无法同时满足多个 SSE 订阅者,也无法让断线客户端回放历史)。\n * Promise 通知链只负责在新事件到达时唤醒等待者,消息本身始终以日志为准。\n *\n * 注册表仅在单个进程内有效;若未来需要多实例部署,应把这一层替换为\n * Redis 等共享存储,而不是改变 AgentRunner 或 SSE 事件协议。\n */\nimport crypto from \"node:crypto\";\nimport type { AgentEvent, AgentEventType, AgentStartParams } from \"../agent/events.js\";\nimport { TERMINAL_EVENT_TYPES } from \"../agent/events.js\";\nimport type { AgentRunner } from \"../agent/runner.js\";\n\nexport const DEFAULT_RETENTION_MS = 24 * 60 * 60 * 1000;\n\nexport interface StoredAgentEvent {\n /** 运行内递增序号;直接用作 SSE 的 id */\n sequence: number;\n event: AgentEvent;\n}\n\ninterface Run {\n runId: string;\n sessionId: string;\n events: StoredAgentEvent[];\n terminal: boolean;\n completedAt: number | null;\n controller: AbortController;\n /** 等待新事件的唤醒回调(一次性,触发后移除) */\n waiters: Set<() => void>;\n /** 终态钩子:运行进入终态后调用一次(停心跳、补配对、清运行标记) */\n onTerminal: ((event: AgentEvent) => Promise<void>) | null;\n}\n\nexport class RunRegistry {\n private readonly retentionMs: number;\n private readonly runs = new Map<string, Run>();\n private readonly latestBySession = new Map<string, string>();\n private closing = false;\n\n constructor(opts: { retentionMs?: number } = {}) {\n this.retentionMs = opts.retentionMs ?? DEFAULT_RETENTION_MS;\n }\n\n /** 分配运行编号并把 runner 放入后台执行,立即返回编号 */\n start(\n runner: AgentRunner,\n params: AgentStartParams,\n opts: {\n sessionId: string;\n onTerminal?: (event: AgentEvent) => Promise<void>;\n /** 部署方注入的 agent 实例标识(xlyra-callback 凭证用) */\n agentInstanceId?: string;\n },\n ): string {\n if (this.closing) throw new Error(\"运行注册表正在关闭,无法创建新运行\");\n this.pruneExpired();\n const runId = crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n const run: Run = {\n runId,\n sessionId: opts.sessionId,\n events: [],\n terminal: false,\n completedAt: null,\n controller: new AbortController(),\n waiters: new Set(),\n onTerminal: opts.onTerminal ?? null,\n };\n this.runs.set(runId, run);\n this.latestBySession.set(opts.sessionId, runId);\n void this.execute(run, runner, params, opts.agentInstanceId);\n return runId;\n }\n\n /** 按公开会话编号读取当前(或最近一轮)事件 */\n async getSessionEvents(\n sessionId: string,\n afterSequence: number,\n timeoutSeconds: number,\n ): Promise<{ events: StoredAgentEvent[]; terminal: boolean }> {\n return this.getEvents(this.sessionRun(sessionId).runId, afterSequence, timeoutSeconds);\n }\n\n /**\n * 返回游标后的事件;暂无事件时等待通知,超时返回空列表供 SSE 发心跳。\n * 调用方应先发送本批事件,再在 terminal=true 且批次已追平时关闭连接。\n */\n async getEvents(\n runId: string,\n afterSequence: number,\n timeoutSeconds: number,\n ): Promise<{ events: StoredAgentEvent[]; terminal: boolean }> {\n if (afterSequence < 0) throw new HttpError(400, \"SSE 事件游标不能为负数\");\n const run = this.getRun(runId);\n if (afterSequence > run.events.length) {\n throw new HttpError(400, `SSE 事件游标 ${afterSequence} 超出当前事件范围`);\n }\n if (afterSequence === run.events.length && !run.terminal && timeoutSeconds > 0) {\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n run.waiters.delete(wake);\n resolve();\n }, timeoutSeconds * 1000);\n const wake = (): void => {\n clearTimeout(timer);\n run.waiters.delete(wake);\n resolve();\n };\n run.waiters.add(wake);\n });\n }\n return { events: run.events.slice(afterSequence), terminal: run.terminal };\n }\n\n /**\n * 幂等取消一次运行:**先落可回放的 agent_cancelled 终态事件,再 abort**。\n * 顺序很重要:运行刚创建、事件循环尚未开始消费时,直接 abort 会让 runner\n * 一次都不执行,订阅者会永久等待——先落终态事件保证任何情况下订阅者\n * 都能看到收尾。\n */\n async cancel(runId: string): Promise<void> {\n const run = this.getRun(runId);\n if (run.terminal) return;\n await this.publish(run, { type: \"agent_cancelled\", run_id: run.runId });\n run.controller.abort();\n }\n\n async cancelSession(sessionId: string): Promise<void> {\n await this.cancel(this.sessionRun(sessionId).runId);\n }\n\n /** 应用关闭时取消全部活动运行 */\n async close(): Promise<void> {\n this.closing = true;\n for (const run of this.runs.values()) {\n if (!run.terminal) await this.cancel(run.runId);\n }\n this.runs.clear();\n this.latestBySession.clear();\n }\n\n /** 消费 runner 事件并写入日志,兜住所有退出路径补齐终态 */\n private async execute(\n run: Run,\n runner: AgentRunner,\n params: AgentStartParams,\n agentInstanceId?: string,\n ): Promise<void> {\n try {\n for await (const event of runner.start(params, {\n runId: run.runId,\n signal: run.controller.signal,\n sessionId: run.sessionId,\n ...(agentInstanceId ? { agentInstanceId } : {}),\n })) {\n await this.publish(run, event);\n }\n if (!run.terminal) {\n await this.publish(run, {\n type: \"agent_error\",\n run_id: run.runId,\n error: \"Agent 运行异常结束,未返回终态事件\",\n });\n }\n } catch (err) {\n // runner 设计为不抛异常;这里是最后防线——后台任务必须转成可见终态\n if (!run.terminal) {\n await this.publish(run, {\n type: \"agent_error\",\n run_id: run.runId,\n error: `Agent 运行发生未知错误:${err instanceof Error ? err.message : err}`,\n });\n }\n }\n }\n\n /** 原子追加事件并广播唤醒;终态之后的迟到事件直接忽略 */\n private async publish(run: Run, event: AgentEvent): Promise<void> {\n if (run.terminal) return;\n run.events.push({ sequence: run.events.length + 1, event });\n let becameTerminal = false;\n if (TERMINAL_EVENT_TYPES.has(event.type as AgentEventType)) {\n run.terminal = true;\n run.completedAt = Date.now();\n becameTerminal = true;\n }\n for (const wake of [...run.waiters]) wake();\n // 终态钩子在事件广播之后调用:收尾涉及文件 IO,不应阻塞事件流;\n // terminal 置位保证本钩子最多触发一次\n if (becameTerminal && run.onTerminal) {\n try {\n await run.onTerminal(event);\n } catch (err) {\n console.error(`Agent 运行终态钩子执行失败 run=${run.runId}:${err instanceof Error ? err.message : err}`);\n }\n }\n }\n\n getRun(runId: string): Run {\n this.pruneExpired();\n const run = this.runs.get(runId);\n if (!run) throw new HttpError(404, \"Agent 运行不存在或事件历史已过期\");\n return run;\n }\n\n private sessionRun(sessionId: string): Run {\n this.pruneExpired();\n const runId = this.latestBySession.get(sessionId);\n const run = runId ? this.runs.get(runId) : undefined;\n if (!run) throw new HttpError(404, \"会话没有可跟随或停止的运行\");\n return run;\n }\n\n /** 惰性清理超过保留期的终态运行;活动运行永不在这里删除 */\n private pruneExpired(): void {\n const cutoff = Date.now() - this.retentionMs;\n for (const [runId, run] of [...this.runs]) {\n if (run.completedAt !== null && run.completedAt <= cutoff) {\n this.runs.delete(runId);\n if (this.latestBySession.get(run.sessionId) === runId) {\n this.latestBySession.delete(run.sessionId);\n }\n }\n }\n }\n}\n\n/** 路由层可直接转成统一错误响应的异常 */\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n ) {\n super(message);\n this.name = \"HttpError\";\n }\n}\n","/**\n * 会话记录器:把一次 Agent 运行的定稿消息接进 JSONL 存储与会话索引。\n *\n * 一次运行一个实例,由路由层创建并挂到两个钩子上:\n * - AgentRunner(onMessage / onCompaction)——定稿消息与压缩行落盘并刷新\n * 索引(先文件后索引,见 sessions.ts 的写入顺序约定);\n * - RunRegistry.start(onTerminal)——运行终态时收尾:停心跳、给未配对的\n * tool_call 补错误回执、清空运行标记(列表立即显示已结束)。\n *\n * 心跳独立于消息追加:长工具执行期间可能几十秒没有新消息,心跳任务保证\n * last_heartbeat 持续刷新,调用方才能正确区分「还在跑」和「已崩溃」。\n * 进程硬崩时心跳自然停止,超时窗过后状态自愈为已结束——这正是不持久化\n * 静态 status 字段的原因。\n */\nimport type { AgentEvent } from \"../agent/events.js\";\nimport type { CompactionResult } from \"../agent/compaction.js\";\nimport { PREVIEW_MAX_CHARS, type AgentSessionStore } from \"../agent/sessions.js\";\nimport type { ChatMessage, ChatResponse } from \"../llm/models.js\";\nimport type { SessionIndex } from \"./session-index.js\";\n\n/** 心跳间隔(毫秒);超时窗见 session-index 的 HEARTBEAT_TIMEOUT_MS(须大于本值) */\nexport const HEARTBEAT_INTERVAL_MS = 10_000;\n\nexport class AgentRunRecorder {\n private readonly store: AgentSessionStore;\n private readonly index: SessionIndex;\n private readonly sessionId: string;\n /** 运行开始时会话已有的 entry 数;之后每次落盘递增,避免反复重读文件 */\n private entryCount: number;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n /** begin 与 onTerminal 分别由路由层和后台任务并发调用:用同一根 Promise\n * 链串行化,防「极速结束的运行被误标为永远运行中」的竞态 */\n private lifecycle: Promise<void> = Promise.resolve();\n private terminated = false;\n\n constructor(store: AgentSessionStore, index: SessionIndex, sessionId: string, entryCount: number) {\n this.store = store;\n this.index = index;\n this.sessionId = sessionId;\n this.entryCount = entryCount;\n }\n\n /** 运行启动:标记 running 并开启心跳。运行已先一步终态时跳过。 */\n async begin(runId: string): Promise<void> {\n this.lifecycle = this.lifecycle.then(() => {\n if (this.terminated) return;\n this.index.markRunning(this.sessionId, runId);\n this.heartbeatTimer = setInterval(() => {\n try {\n this.index.heartbeat(this.sessionId);\n } catch (err) {\n console.warn(`会话心跳刷新失败 session=${this.sessionId}:${err instanceof Error ? err.message : err}`);\n }\n }, HEARTBEAT_INTERVAL_MS);\n this.heartbeatTimer.unref?.();\n });\n await this.lifecycle;\n }\n\n /** 落盘 user message,刷新标题(仅首条)与最后提示预览,返回 message id */\n async recordUserMessage(text: string): Promise<string> {\n const entry = this.store.append(this.sessionId, { role: \"user\", content: text });\n this.entryCount += 1;\n const preview = text.trim().slice(0, PREVIEW_MAX_CHARS);\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n last_prompt: preview,\n title: preview,\n });\n return entry.uuid;\n }\n\n /** runner 定稿消息回调:assistant 带响应元数据,tool 结果不带 */\n onMessage = async (message: ChatMessage, response: ChatResponse | null): Promise<void> => {\n const entry = this.store.append(this.sessionId, message, {\n ...(response?.model ? { model: response.model } : {}),\n ...(response?.usage ? { usage: response.usage } : {}),\n ...(response?.finish_reason ? { finish_reason: response.finish_reason } : {}),\n });\n this.entryCount += 1;\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n });\n };\n\n /** runner 压缩定稿回调:压缩行落盘并刷新索引(与 onMessage 同一节奏) */\n onCompaction = async (result: CompactionResult): Promise<void> => {\n const entry = this.store.appendCompaction(this.sessionId, result);\n this.entryCount += 1;\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n });\n };\n\n /** runner 提权请求回调:提权行落盘并刷新索引(回放时前端渲染确认卡片) */\n onEscalation = async (info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type?: \"path\" | \"command\";\n requested_command?: string[];\n }): Promise<void> => {\n const entry = this.store.appendEscalation(this.sessionId, {\n escalation_id: info.escalation_id,\n requested_path: info.requested_path,\n resolved_path: info.resolved_path,\n tool_name: info.tool_name,\n resource_type: info.resource_type,\n requested_command: info.requested_command,\n });\n this.entryCount += 1;\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n });\n };\n\n /** 运行终态收尾(done / error / cancelled 统一路径) */\n onTerminal = async (_event: AgentEvent): Promise<void> => {\n this.lifecycle = this.lifecycle.then(() => {\n this.terminated = true;\n if (this.heartbeatTimer !== null) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n // 取消/出错的运行可能留下没有回执的 tool_call,补齐保证配对完整;\n // 提权协商暂停(等待用户确认)用中性回执,不标为失败\n let sealed = 0;\n try {\n const awaitingAuth = _event.type === \"agent_cancelled\" && _event.reason === \"escalation\";\n sealed = this.store.sealPendingToolCalls(this.sessionId, awaitingAuth ? \"awaiting_authorization\" : \"interrupted\");\n } catch (err) {\n console.warn(`会话中断收尾失败 session=${this.sessionId}:${err instanceof Error ? err.message : err}`);\n }\n if (sealed > 0) {\n this.entryCount += sealed;\n const { entries } = this.store.read(this.sessionId);\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entries[entries.length - 1]?.uuid ?? \"\",\n entry_count: this.entryCount,\n });\n }\n this.index.finishRun(this.sessionId);\n });\n await this.lifecycle;\n };\n}\n","/**\n * REST + SSE 路由(Hono)—— Agent 会话的 HTTP 面。\n *\n * 响应统一信封:成功 {success:true, code, message, data};\n * 错误 {success:false, code, message}(HTTP 状态码同步表达错误类别)。\n */\nimport { Hono } from \"hono\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { buildSystemPrompt } from \"../agent/prompts.js\";\nimport { compact, type CompactionResult } from \"../agent/compaction.js\";\nimport {\n isCompactionEntry,\n isEscalationEntry,\n isMessageEntry,\n type AgentSessionStore,\n} from \"../agent/sessions.js\";\nimport { AgentRunner } from \"../agent/runner.js\";\nimport type { AgentEvent } from \"../agent/events.js\";\nimport type { EndpointResolver } from \"../llm/router.js\";\nimport { modelSettingsSchema } from \"../llm/models.js\";\nimport type { AgentTool } from \"../tools/types.js\";\nimport type { SkillInfo } from \"../context/skills.js\";\nimport {\n discoverSkills,\n loadSkillContent,\n loadWorkspaceContext,\n type WorkspaceContext,\n type WorkspaceContextOptions,\n} from \"../context/index.js\";\nimport { AgentRunRecorder } from \"./recorder.js\";\nimport { HttpError, RunRegistry } from \"./run-registry.js\";\nimport type { SessionIndex } from \"./session-index.js\";\n\nexport interface RoutesContext {\n resolver: EndpointResolver;\n store: AgentSessionStore;\n index: SessionIndex;\n registry: RunRegistry;\n /** 会话级路径授权登记表(提权协商的确认落点) */\n grants: import(\"../agent/escalation.js\").EscalationGrants;\n /** 工具工厂:按会话构建工具集;skills 由每次 run 刷新后传入 */\n makeTools: (sessionId: string, skills?: SkillInfo[]) => AgentTool[];\n /** 提权事件展示的工作区根 */\n workdir: string;\n agentName?: string;\n persona?: string;\n /** 部署方注入的 agent 实例标识默认值(xlyra-callback 凭证用);run 启动参数可覆盖 */\n agentInstanceId?: string;\n /** AGENTS.md / Skills 发现开关与额外目录(启动快照) */\n workspaceContext?: WorkspaceContextOptions;\n /** 每次 run/查询时解析最新上下文选项(配置热生效);缺省回退 workspaceContext */\n resolveWorkspaceContext?: () => WorkspaceContextOptions;\n /** 可选静态 Bearer token;配置后全部端点要求鉴权 */\n token?: string;\n}\n\nfunction ok<T>(data: T, message = \"\"): { success: true; code: number; message: string; data: T } {\n return { success: true, code: 0, message, data };\n}\n\nfunction fail(status: number, message: string): never {\n throw new HttpError(status, message);\n}\n\nconst startPayloadSchema = z.object({\n content: z.string().min(1, \"消息内容不能为空\"),\n session_id: z.string().optional(),\n model: z.string().default(\"\"),\n settings: modelSettingsSchema.optional(),\n reasoning_effort: modelSettingsSchema.shape.reasoning_effort,\n /** 部署方注入的 agent 实例标识(xlyra-callback 凭证用),缺省用服务级配置 */\n agent_instance_id: z.string().optional(),\n /** 权限模式:ask(默认,越界操作走提权协商)/ full(本会话完全访问,跳过硬闸确认) */\n permission_mode: z.enum([\"ask\", \"full\"]).optional(),\n});\n\nconst retryPayloadSchema = z.object({\n message_id: z.string().min(1),\n content: z.string().optional(),\n model: z.string().default(\"\"),\n settings: modelSettingsSchema.optional(),\n reasoning_effort: modelSettingsSchema.shape.reasoning_effort,\n agent_instance_id: z.string().optional(),\n permission_mode: z.enum([\"ask\", \"full\"]).optional(),\n});\n\n/** PATCH /sessions/:id 请求体:title 与 archived 至少提供一个 */\nconst patchPayloadSchema = z\n .object({\n title: z.string().min(1).optional(),\n archived: z.boolean().optional(),\n })\n .refine((v) => v.title !== undefined || v.archived !== undefined, {\n message: \"至少提供 title 或 archived 之一\",\n });\n\nexport function createAgentRoutes(ctx: RoutesContext): Hono {\n const app = new Hono();\n\n // 统一错误处理:HttpError → 对应状态码;其余 → 500\n app.onError((err, c) => {\n if (err instanceof HttpError) {\n return c.json({ success: false, code: err.status, message: err.message }, err.status as 400);\n }\n // 请求体校验失败是客户端错误:返回 400 与具体字段,不淹没在 500 里\n if (err instanceof z.ZodError) {\n const issue = err.issues[0];\n const where = issue && issue.path.length > 0 ? `${issue.path.join(\".\")}: ` : \"\";\n return c.json({ success: false, code: 400, message: `参数校验失败:${where}${issue?.message ?? \"非法请求\"}` }, 400);\n }\n console.error(`请求处理失败:${err instanceof Error ? (err.stack ?? err.message) : err}`);\n return c.json({ success: false, code: 500, message: \"服务内部错误\" }, 500);\n });\n\n // 可选 Bearer 鉴权\n if (ctx.token) {\n app.use(\"*\", async (c, next) => {\n const header = c.req.header(\"authorization\") ?? \"\";\n if (header !== `Bearer ${ctx.token}`) {\n return c.json({ success: false, code: 401, message: \"未授权:缺少或错误的 Bearer token\" }, 401);\n }\n await next();\n });\n }\n\n const currentWorkspaceOptions = () => ctx.resolveWorkspaceContext?.() ?? ctx.workspaceContext ?? {};\n\n const refreshWorkspace = () => {\n const workspace = loadWorkspaceContext(ctx.workdir, currentWorkspaceOptions());\n for (const warning of workspace.warnings) {\n console.warn(`[workspace-context] ${warning}`);\n }\n return workspace;\n };\n\n const buildSystem = (fragments: string[] = []): string =>\n buildSystemPrompt({\n agentName: ctx.agentName,\n persona: ctx.persona,\n contextFragments: fragments,\n });\n\n /** 在已校验的会话链尾追加用户消息并启动后台运行(start / retry 共用) */\n async function launchUserMessage(args: {\n sessionId: string;\n content: string;\n model: string;\n history: import(\"../llm/models.js\").ChatMessage[];\n entryCount: number;\n settings?: import(\"../llm/models.js\").ModelSettings;\n systemPrompt?: string;\n recordUser?: boolean;\n agentInstanceId?: string;\n workspace?: WorkspaceContext;\n }): Promise<{ sessionId: string; messageId: string; runId: string }> {\n const workspace = args.workspace ?? refreshWorkspace();\n const recorder = new AgentRunRecorder(ctx.store, ctx.index, args.sessionId, args.entryCount);\n const messageId = args.recordUser === false ? \"\" : await recorder.recordUserMessage(args.content);\n const runner = new AgentRunner({\n resolver: ctx.resolver,\n tools: ctx.makeTools(args.sessionId, workspace.skills.skills),\n onMessage: recorder.onMessage,\n onCompaction: recorder.onCompaction,\n onEscalation: recorder.onEscalation,\n workdirHint: ctx.workdir,\n });\n const runId = ctx.registry.start(\n runner,\n {\n input: args.content,\n include_input: args.recordUser !== false,\n history: args.history,\n model: args.model,\n settings: args.settings,\n system_prompt: args.systemPrompt ?? buildSystem(workspace.fragments),\n },\n {\n sessionId: args.sessionId,\n onTerminal: recorder.onTerminal,\n ...(args.agentInstanceId ?? ctx.agentInstanceId\n ? { agentInstanceId: args.agentInstanceId ?? ctx.agentInstanceId }\n : {}),\n },\n );\n await recorder.begin(runId);\n return { sessionId: args.sessionId, messageId, runId };\n }\n\n /** 开始新会话,或向已有会话发送用户消息(202 异步) */\n app.post(\"/sessions\", async (c) => {\n const payload = startPayloadSchema.parse(await c.req.json());\n // 路由解析先行:端点未配置/模型不存在时必须在会话落盘前失败,\n // 否则磁盘上会残留一条空会话\n ctx.resolver.resolve(payload.model);\n\n let sessionId: string;\n let history: import(\"../llm/models.js\").ChatMessage[];\n let entryCount: number;\n if (payload.session_id) {\n sessionId = payload.session_id;\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再发送消息\");\n if (ctx.index.isRunning(sessionId)) {\n fail(400, \"该会话已有正在进行的运行,请先停止或等待完成\");\n }\n history = ctx.store.buildHistory(sessionId);\n entryCount = ctx.store.read(sessionId).entries.length;\n } else {\n const header = ctx.store.create();\n sessionId = header.session_id;\n ctx.index.create(sessionId);\n history = [];\n entryCount = 0;\n }\n // 权限模式随每条消息注入:full 放开本会话全部提权检查,ask 撤销(不含已逐项授权的路径)\n if (payload.permission_mode !== undefined) {\n ctx.grants.setFullAccess(sessionId, payload.permission_mode === \"full\");\n }\n const { messageId, runId } = await launchUserMessage({\n sessionId,\n content: payload.content,\n model: payload.model,\n history,\n entryCount,\n settings: {\n ...payload.settings,\n ...(payload.reasoning_effort ? { reasoning_effort: payload.reasoning_effort } : {}),\n },\n ...(payload.agent_instance_id ? { agentInstanceId: payload.agent_instance_id } : {}),\n });\n return c.json(ok({ session_id: sessionId, message_id: messageId, run_id: runId }, \"用户消息已提交\"), 202);\n });\n\n /** 最近会话列表(按最后活跃时间倒序) */\n app.get(\"/sessions\", (c) => {\n const limit = Math.min(Number(c.req.query(\"limit\") ?? 50), 200);\n const offset = Math.max(Number(c.req.query(\"offset\") ?? 0), 0);\n const list = ctx.index.list(limit, offset).map((meta) => ({\n ...meta,\n running: ctx.index.isRunning(meta.session_id),\n }));\n return c.json(ok(list));\n });\n\n /** 读取会话完整轨迹(message/compaction 按写入顺序) */\n app.get(\"/sessions/:id/transcript\", (c) => {\n const sessionId = c.req.param(\"id\");\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n const { entries } = ctx.store.read(sessionId);\n return c.json(\n ok({\n session: ctx.index.get(sessionId) ?? null,\n entries: entries.map((e) =>\n isCompactionEntry(e)\n ? {\n type: \"compaction\" as const,\n compaction_id: e.uuid,\n parent_id: e.parent_uuid,\n timestamp: e.timestamp,\n summary: e.summary,\n replacement_history: e.replacement_history,\n tokens_before: e.tokens_before,\n tokens_after: e.tokens_after,\n }\n : isEscalationEntry(e)\n ? {\n type: \"escalation\" as const,\n escalation_id: e.uuid,\n parent_id: e.parent_uuid,\n timestamp: e.timestamp,\n requested_path: e.requested_path,\n resolved_path: e.resolved_path,\n tool_name: e.tool_name,\n resource_type: e.resource_type,\n requested_command: e.requested_command,\n workdir: ctx.workdir,\n granted: e.granted,\n }\n : {\n type: \"message\" as const,\n message_id: e.uuid,\n parent_id: e.parent_uuid,\n timestamp: e.timestamp,\n message: e.message,\n model: e.model,\n usage: e.usage,\n finish_reason: e.finish_reason,\n },\n ),\n }),\n );\n });\n\n /** 重命名 / 归档状态(归档 = 只读,恢复后才可继续会话) */\n app.patch(\"/sessions/:id\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const { title, archived } = patchPayloadSchema.parse(await c.req.json());\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (archived === true && ctx.index.isRunning(sessionId)) {\n fail(400, \"该会话正在运行中,请先停止运行再归档\");\n }\n if (title !== undefined) ctx.index.rename(sessionId, title);\n if (archived !== undefined) ctx.index.setArchived(sessionId, archived);\n return c.json(\n ok(ctx.index.get(sessionId), archived === undefined ? \"会话已重命名\" : archived ? \"会话已归档\" : \"会话已恢复\"),\n );\n });\n\n /** 手动压缩会话上下文(不删除完整轨迹) */\n app.post(\"/sessions/:id/compact-context\", async (c) => {\n const sessionId = c.req.param(\"id\");\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再压缩\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中,请等待完成后再压缩\");\n const history = ctx.store.buildHistory(sessionId);\n if (history.length === 0) fail(400, \"会话没有可压缩的内容\");\n\n // 沿用会话最近一次运行的模型(转录里 assistant 行带 model 元数据)\n const { entries } = ctx.store.read(sessionId);\n const lastModel = [...entries].reverse().find((e) => isMessageEntry(e) && e.model);\n const modelRef = (lastModel && isMessageEntry(lastModel) && lastModel.model) || \"\";\n const resolved = ctx.resolver.resolve(modelRef);\n\n const result: CompactionResult | null = await compact(\n resolved.protocol,\n resolved.modelId,\n [{ role: \"system\", content: buildSystem(refreshWorkspace().fragments) }, ...history],\n {},\n );\n if (!result) fail(502, \"压缩失败:模型未能生成摘要,请稍后重试\");\n\n const entry = ctx.store.appendCompaction(sessionId, result);\n ctx.index.touchAfterAppend(sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: entries.length + 1,\n });\n return c.json(\n ok(\n {\n summary: result.summary,\n tokens_before: result.tokens_before,\n tokens_after: result.tokens_after,\n compaction_id: entry.uuid,\n },\n \"会话上下文已压缩\",\n ),\n );\n });\n\n /** 从指定 user message 重新提问(可替换问题内容) */\n app.post(\"/sessions/:id/retry\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const payload = retryPayloadSchema.parse(await c.req.json());\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再重试\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中,请先停止运行再重试\");\n\n const { entries } = ctx.store.read(sessionId);\n const target = entries.find((e) => e.uuid === payload.message_id);\n if (!target) fail(404, \"会话中没有这条记录,可能已被改写\");\n if (!isMessageEntry(target) || target.message.role !== \"user\") {\n fail(400, \"只能重试用户消息\");\n }\n const content = payload.content ?? (target.message.content ?? \"\");\n if (payload.permission_mode !== undefined) {\n ctx.grants.setFullAccess(sessionId, payload.permission_mode === \"full\");\n }\n\n // 端点和工作区上下文校验先于不可逆的历史删除。\n ctx.resolver.resolve(payload.model);\n const workspace = refreshWorkspace();\n ctx.store.discardFromUserMessage(sessionId, payload.message_id);\n const history = ctx.store.buildHistory(sessionId);\n const remaining = ctx.store.read(sessionId).entries.length;\n\n const { messageId, runId } = await launchUserMessage({\n sessionId,\n content,\n model: payload.model,\n history,\n entryCount: remaining,\n workspace,\n settings: {\n ...payload.settings,\n ...(payload.reasoning_effort ? { reasoning_effort: payload.reasoning_effort } : {}),\n },\n ...(payload.agent_instance_id ? { agentInstanceId: payload.agent_instance_id } : {}),\n });\n return c.json(ok({ session_id: sessionId, message_id: messageId, run_id: runId }, \"已重新提交\"), 202);\n });\n\n /**\n * 提权确认:用户在前端确认后,把路径登记进会话级授权清单,并自动\n * 重发最近一条用户消息续跑(效果 = 授权后从中断处继续)。\n * 授权粒度是「会话 × 路径前缀」,随会话生命周期存在(进程内,不落盘)。\n */\n app.post(\"/sessions/:id/grant-access\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const { escalation_id, granted, resolved_path } = z.object({\n escalation_id: z.string().min(1),\n granted: z.boolean(),\n resolved_path: z.string().min(1),\n }).parse(await c.req.json());\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再授权\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中\");\n\n // 用 escalation_id 定位并校验目标路径,防前端传错/被篡改\n const { entries } = ctx.store.read(sessionId);\n const esc = entries.find(\n (e) => e.type === \"escalation\" && e.uuid === escalation_id,\n );\n if (!esc || esc.type !== \"escalation\") fail(404, \"提权请求不存在或已过期\");\n if (esc.resolved_path !== resolved_path) fail(400, \"授权路径与提权请求不一致\");\n if (esc.granted !== null && esc.granted !== undefined) fail(400, \"该提权请求已处理过\");\n\n // 落确认结果(回放时卡片显示已授权/已拒绝)\n ctx.store.resolveEscalation(sessionId, escalation_id, granted);\n\n if (!granted) {\n // 拒绝不回死对话:用「工具被拒」的回执补齐上下文后续跑,\n // 让模型直接向用户说明或给出替代方案,而不是静默结束\n const history = ctx.store.buildHistoryBeforeEscalation(sessionId, escalation_id);\n const assistantEntry = entries.find(\n (e) => e.uuid === esc.parent_uuid && isMessageEntry(e) && e.message.role === \"assistant\",\n );\n if (assistantEntry && isMessageEntry(assistantEntry)) {\n history.push(assistantEntry.message);\n for (const call of assistantEntry.message.tool_calls ?? []) {\n const recorded = entries.find(\n (e) => isMessageEntry(e) && e.message.role === \"tool\" && e.message.tool_call_id === call.id,\n );\n // 被提权拦下的调用(无真实结果或只有中断回执)改写为明确的拒绝语义,\n // 其余调用沿用已记录的真实结果\n const interrupted = !recorded\n || (isMessageEntry(recorded) && recorded.message.is_error === true\n && recorded.message.content === \"操作已被中断,工具未执行完成。\");\n if (call.name === esc.tool_name && interrupted) {\n history.push({\n role: \"tool\",\n tool_call_id: call.id,\n name: call.name,\n content: \"用户拒绝了本次权限请求,该操作未执行。不要重试相同或类似的越权操作;直接向用户说明无法执行的原因,或给出不需要该权限的替代方案。\",\n is_error: true,\n });\n } else if (recorded && isMessageEntry(recorded)) {\n history.push(recorded.message);\n } else {\n history.push({\n role: \"tool\",\n tool_call_id: call.id,\n name: call.name,\n content: \"操作已被中断,工具未执行完成。\",\n is_error: true,\n });\n }\n }\n }\n const { runId } = await launchUserMessage({\n sessionId,\n content: \"\",\n model: \"\",\n history,\n entryCount: entries.length,\n recordUser: false,\n });\n return c.json(ok({ session_id: sessionId, granted: false, run_id: runId }, \"已拒绝授权,由模型继续应答\"), 202);\n }\n if (esc.resource_type === \"command\") {\n ctx.grants.grantCapability(sessionId, resolved_path);\n } else {\n ctx.grants.grant(sessionId, resolved_path);\n }\n\n // 自动续跑:沿用原始 user 历史,不追加新的 user 记录;\n // 提权中断的运行已由 recorder 终态收尾补配对,轨迹仍可完整回放。\n const lastUser = [...entries].reverse().find(\n (e) => isMessageEntry(e) && e.message.role === \"user\",\n );\n if (!lastUser || !isMessageEntry(lastUser)) fail(400, \"会话中没有可续跑的用户消息\");\n ctx.resolver.resolve(\"\");\n const history = ctx.store.buildHistoryBeforeEscalation(sessionId, escalation_id);\n const { messageId, runId } = await launchUserMessage({\n sessionId,\n content: \"\",\n model: \"\",\n history,\n entryCount: entries.length,\n recordUser: false,\n });\n return c.json(\n ok({ session_id: sessionId, message_id: messageId, run_id: runId, granted_path: resolved_path }, \"已授权并继续执行\"),\n 202,\n );\n });\n\n /** 删除会话(转录文件与索引一并删除;运行中拒绝) */\n app.delete(\"/sessions/:id\", (c) => {\n const sessionId = c.req.param(\"id\");\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中,请先停止运行再删除\");\n ctx.store.delete(sessionId);\n ctx.index.remove(sessionId);\n ctx.grants.drop(sessionId); // 授权随会话生命周期\n return c.json(ok({}, \"会话已删除\"));\n });\n\n /** SSE 跟随会话当前消息的处理事件(支持 Last-Event-ID 断线续传) */\n app.get(\"/sessions/:id/events\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const cursor = Number(c.req.header(\"last-event-id\") ?? 0);\n // 在响应建立前完成存在性和游标校验,404/400 仍能以标准 JSON 返回\n const initial = await ctx.registry.getSessionEvents(sessionId, cursor, 0);\n\n const stream = new ReadableStream<Uint8Array>({\n async start(controller) {\n const encoder = new TextEncoder();\n let current = cursor;\n let { events, terminal } = initial;\n try {\n for (;;) {\n for (const stored of events) {\n current = stored.sequence;\n const { run_id: _omit, ...payload } = stored.event;\n controller.enqueue(\n encoder.encode(\n `id: ${stored.sequence}\\nevent: ${stored.event.type}\\ndata: ${JSON.stringify(payload)}\\n\\n`,\n ),\n );\n }\n if (terminal) return;\n ({ events, terminal } = await ctx.registry.getSessionEvents(sessionId, current, 15));\n if (events.length === 0 && !terminal) {\n controller.enqueue(encoder.encode(\": heartbeat\\n\\n\"));\n }\n }\n } finally {\n controller.close();\n }\n },\n });\n return new Response(stream, {\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n },\n });\n });\n\n /** 停止会话当前消息的模型处理(幂等) */\n app.post(\"/sessions/:id/stop\", async (c) => {\n await ctx.registry.cancelSession(c.req.param(\"id\"));\n return c.json(ok({}, \"已请求停止会话\"));\n });\n\n /**\n * Skills 权威列表:与 run 启动时同一套发现逻辑,附全局开关与逐项启用状态。\n * 全局停用(enable_skills=false)时仍返回清单,便于管理界面操作开关。\n */\n app.get(\"/skills\", (c) => {\n const opts = currentWorkspaceOptions();\n const disabled = new Set(opts.disabledSkills ?? []);\n const discovered = discoverSkills(ctx.workdir, opts.skills ?? {});\n return c.json(ok({\n enabled: opts.enableSkills !== false,\n skills: discovered.skills.map((skill) => ({\n name: skill.name,\n description: skill.description,\n scope: skill.scope,\n enabled: !disabled.has(skill.name),\n path: skill.skillFile,\n ...(skill.license ? { license: skill.license } : {}),\n })),\n warnings: discovered.warnings,\n }));\n });\n\n /** 单文件查看上限(文档/脚本查看场景,超出部分截断返回) */\n const SKILL_FILE_VIEW_MAX_BYTES = 256_000;\n\n /** 按名称解析当前生效的 skill(与 run 注入同一套发现与覆盖规则) */\n const findSkill = (name: string): { skill: SkillInfo; disabled: Set<string> } | null => {\n const opts = currentWorkspaceOptions();\n const discovered = discoverSkills(ctx.workdir, opts.skills ?? {});\n const skill = discovered.skills.find((item) => item.name === name);\n return skill ? { skill, disabled: new Set(opts.disabledSkills ?? []) } : null;\n };\n\n /** Skill 详情:frontmatter 元信息 + SKILL.md 全文 + 资源文件清单(供管理界面展示) */\n app.get(\"/skills/:name\", (c) => {\n const found = findSkill(c.req.param(\"name\"));\n if (!found) throw new HttpError(404, `skill 不存在:${c.req.param(\"name\")}`);\n const { skill, disabled } = found;\n const loaded = loadSkillContent(skill);\n return c.json(ok({\n name: skill.name,\n description: skill.description,\n scope: skill.scope,\n enabled: !disabled.has(skill.name),\n path: skill.skillFile,\n ...(skill.license ? { license: skill.license } : {}),\n ...(skill.metadata ? { metadata: skill.metadata } : {}),\n content: loaded.content,\n contentTruncated: loaded.contentTruncated,\n resources: loaded.resources,\n }));\n });\n\n /** 读取 skill 目录内的单个资源文件(文档/脚本预览;限 skill 根内、非符号链接、限大小) */\n app.get(\"/skills/:name/file\", (c) => {\n const found = findSkill(c.req.param(\"name\"));\n if (!found) throw new HttpError(404, `skill 不存在:${c.req.param(\"name\")}`);\n const rel = (c.req.query(\"path\") ?? \"\").trim().replaceAll(\"\\\\\", \"/\").replace(/^\\/+/, \"\");\n if (!rel) throw new HttpError(400, \"缺少 path 参数\");\n const root = found.skill.root;\n // 注意不能用 path.join 对比做越界判断(join 同样会归一化 ..),用路径前缀判定\n const target = path.resolve(root, rel);\n if (!target.startsWith(root + path.sep)) {\n throw new HttpError(400, \"路径越界:仅允许 skill 目录内的文件\");\n }\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(target);\n } catch {\n throw new HttpError(404, `文件不存在:${rel}`);\n }\n if (stat.isSymbolicLink() || !stat.isFile()) {\n throw new HttpError(400, \"仅支持读取普通文件\");\n }\n const truncated = stat.size > SKILL_FILE_VIEW_MAX_BYTES;\n const data = Buffer.alloc(Math.min(stat.size, SKILL_FILE_VIEW_MAX_BYTES));\n const fd = fs.openSync(target, \"r\");\n try {\n fs.readSync(fd, data, 0, data.length, 0);\n } finally {\n fs.closeSync(fd);\n }\n return c.json(ok({ path: rel, content: data.toString(\"utf-8\"), truncated }));\n });\n\n app.get(\"/health\", (c) => c.json(ok({ status: \"ok\" })));\n\n return app;\n}\n","/**\n * AGENTS.md 发现与格式化(对齐 https://agents.md/)。\n *\n * 根目录的 AGENTS.override.md 优先于 AGENTS.md;每个嵌套目录同样遵循该\n * 规则。根目录有效文件正文常驻注入,嵌套文件只列出路径供模型按需读取。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/** 嵌套扫描最大深度(相对 workdir);根 AGENTS.md 本身不计入 */\nexport const AGENTS_MD_MAX_DEPTH = 6;\n/** 嵌套扫描最多访问的目录数,防止超大仓库失控 */\nexport const AGENTS_MD_MAX_DIRS = 2_000;\n/** 根 AGENTS.md 注入上限(字节) */\nexport const AGENTS_MD_MAX_BYTES = 32_000;\n/** 格式化后提示词片段的总字节上限 */\nexport const AGENTS_MD_MAX_FORMAT_BYTES = 48_000;\n\nconst SKIP_DIR_NAMES = new Set([\".git\", \"node_modules\"]);\n\ntype AgentsMdName = \"AGENTS.md\" | \"AGENTS.override.md\";\n\nexport interface AgentsMdContext {\n rootPath: string | null;\n rootInstructions: string | null;\n rootTruncated: boolean;\n nestedPaths: string[];\n warnings: string[];\n}\n\nexport interface DiscoverAgentsMdOptions {\n maxDepth?: number;\n maxDirs?: number;\n maxBytes?: number;\n}\n\nexport interface FormatAgentsMdOptions {\n maxBytes?: number;\n}\n\nfunction normalizeText(raw: string): string {\n return raw.replace(/^\\uFEFF/, \"\").replace(/\\r\\n?/g, \"\\n\");\n}\n\nfunction readFilePrefix(file: string, maxBytes: number): { text: string; truncated: boolean } {\n const fd = fs.openSync(file, \"r\");\n try {\n const size = fs.fstatSync(fd).size;\n const length = Math.min(size, Math.max(0, maxBytes) + 4);\n const buffer = Buffer.alloc(length);\n fs.readSync(fd, buffer, 0, length, 0);\n return { text: buffer.toString(\"utf-8\"), truncated: size > length };\n } finally {\n fs.closeSync(fd);\n }\n}\n\nfunction truncateUtf8(text: string, maxBytes: number): string {\n const limit = Math.max(0, maxBytes);\n const data = Buffer.from(text, \"utf-8\");\n if (data.length <= limit) return text;\n let end = limit;\n while (end > 0) {\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(data.subarray(0, end));\n } catch {\n end -= 1;\n }\n }\n return \"\";\n}\n\nfunction fileIfPresent(dir: string, name: AgentsMdName, warnings?: string[]): string | null {\n const candidate = path.join(dir, name);\n try {\n const stat = fs.lstatSync(candidate);\n return !stat.isSymbolicLink() && stat.isFile() ? candidate : null;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n warnings?.push(`访问 ${candidate} 失败:${error instanceof Error ? error.message : String(error)}`);\n }\n return null;\n }\n}\n\nfunction effectiveFile(dir: string, warnings?: string[]): string | null {\n return fileIfPresent(dir, \"AGENTS.override.md\", warnings) ?? fileIfPresent(dir, \"AGENTS.md\", warnings);\n}\n\nexport function discoverAgentsMd(\n workdir: string,\n opts: DiscoverAgentsMdOptions = {},\n): AgentsMdContext {\n const maxDepth = opts.maxDepth ?? AGENTS_MD_MAX_DEPTH;\n const maxDirs = opts.maxDirs ?? AGENTS_MD_MAX_DIRS;\n const maxBytes = opts.maxBytes ?? AGENTS_MD_MAX_BYTES;\n const root = path.resolve(workdir);\n const warnings: string[] = [];\n const nestedPaths: string[] = [];\n let rootInstructions: string | null = null;\n let rootTruncated = false;\n const rootFile = effectiveFile(root, warnings);\n const rootPath = rootFile;\n\n if (rootFile) {\n try {\n const read = readFilePrefix(rootFile, maxBytes);\n const normalized = normalizeText(read.text);\n const data = Buffer.from(normalized, \"utf-8\");\n rootTruncated = read.truncated || data.length > maxBytes;\n rootInstructions = rootTruncated ? truncateUtf8(normalized, maxBytes) : normalized;\n if (rootTruncated) {\n warnings.push(`根 ${path.basename(rootFile)} 超过 ${maxBytes} 字节,已截断注入;完整内容请用 read 工具读取 ${rootFile}`);\n }\n } catch (error) {\n warnings.push(`读取 ${rootFile} 失败:${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n try {\n if (!fs.statSync(root).isDirectory()) return { rootPath, rootInstructions, rootTruncated, nestedPaths, warnings };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n warnings.push(`访问工作目录 ${root} 失败:${error instanceof Error ? error.message : String(error)}`);\n }\n return { rootPath, rootInstructions, rootTruncated, nestedPaths, warnings };\n }\n\n let visited = 0;\n let depthWarned = false;\n let dirsWarned = false;\n const warnDepth = (): void => {\n if (!depthWarned) {\n depthWarned = true;\n warnings.push(`AGENTS.md 嵌套扫描达到深度上限 ${maxDepth},已停止更深目录扫描`);\n }\n };\n const warnDirs = (): void => {\n if (!dirsWarned) {\n dirsWarned = true;\n warnings.push(`AGENTS.md 嵌套扫描达到目录上限 ${maxDirs},已停止`);\n }\n };\n const walk = (dir: string, depth: number): void => {\n if (depth > maxDepth) {\n warnDepth();\n return;\n }\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (error) {\n warnings.push(`遍历目录 ${dir} 失败:${error instanceof Error ? error.message : String(error)}`);\n return;\n }\n for (const entry of entries) {\n if (SKIP_DIR_NAMES.has(entry.name) || entry.isSymbolicLink() || !entry.isDirectory()) continue;\n if (visited >= maxDirs) {\n warnDirs();\n return;\n }\n visited += 1;\n const full = path.join(dir, entry.name);\n const candidate = effectiveFile(full, warnings);\n if (candidate) nestedPaths.push(candidate);\n walk(full, depth + 1);\n }\n };\n walk(root, 1);\n\n nestedPaths.sort((a, b) => a.localeCompare(b));\n return { rootPath, rootInstructions, rootTruncated, nestedPaths, warnings };\n}\n\n/** 将发现结果格式化为系统提示词片段;无内容时返回空串。 */\nexport function formatAgentsMdContext(\n context: AgentsMdContext,\n opts: FormatAgentsMdOptions = {},\n): string {\n if (!context.rootInstructions && context.nestedPaths.length === 0 && context.warnings.length === 0) return \"\";\n const lines = [\n \"# 项目约定 (AGENTS.md)\",\n \"以下是仓库给 coding agent 的项目级指令。用户当轮明确要求覆盖其中冲突项。\",\n \"修改某个子目录中的文件前,若下方列出了更近的嵌套 AGENTS.md,先用 read 读取该路径向上最近的一份;更近者优先。\",\n ];\n if (context.rootInstructions) {\n lines.push(\"\", \"## 根 AGENTS.md\");\n if (context.rootPath) lines.push(`路径:${context.rootPath}`);\n if (context.rootTruncated) lines.push(\"(正文已因体积上限截断;需要全文时请 read 上述路径)\");\n lines.push(normalizeText(context.rootInstructions).trimEnd());\n }\n if (context.nestedPaths.length > 0) {\n lines.push(\"\", \"## 嵌套 AGENTS.md\", \"仅列出路径,不预加载正文:\");\n for (const p of context.nestedPaths) lines.push(`- ${p}`);\n }\n if (context.warnings.length > 0) lines.push(\"\", \"扫描告警:\", ...context.warnings.map((warning) => `- ${warning}`));\n return truncateUtf8(lines.join(\"\\n\"), opts.maxBytes ?? AGENTS_MD_MAX_FORMAT_BYTES);\n}\n","/**\n * 工作区上下文装配:把 AGENTS.md 与 Skills 拼成可注入的提示词片段。\n */\nimport {\n discoverAgentsMd,\n formatAgentsMdContext,\n type AgentsMdContext,\n type DiscoverAgentsMdOptions,\n} from \"./agents-md.js\";\nimport {\n discoverSkills,\n formatSkillsCatalog,\n type DiscoverSkillsOptions,\n type SkillsContext,\n} from \"./skills.js\";\n\nexport * from \"./agents-md.js\";\nexport * from \"./skills.js\";\n\nexport interface WorkspaceContextOptions {\n enableAgentsMd?: boolean;\n enableSkills?: boolean;\n /** 停用的 skill 名称名单:发现后过滤,不注入 catalog(文件保留,便于随时重新启用) */\n disabledSkills?: string[];\n agentsMd?: DiscoverAgentsMdOptions;\n skills?: DiscoverSkillsOptions;\n}\n\nexport interface WorkspaceContext {\n agents: AgentsMdContext | null;\n skills: SkillsContext;\n /** 可直接拼进 system prompt 的非空片段 */\n fragments: string[];\n warnings: string[];\n}\n\nexport function loadWorkspaceContext(\n workdir: string,\n opts: WorkspaceContextOptions = {},\n): WorkspaceContext {\n const enableAgentsMd = opts.enableAgentsMd !== false;\n const enableSkills = opts.enableSkills !== false;\n const warnings: string[] = [];\n const fragments: string[] = [];\n\n let agents: AgentsMdContext | null = null;\n if (enableAgentsMd) {\n agents = discoverAgentsMd(workdir, opts.agentsMd);\n warnings.push(...agents.warnings);\n const fragment = formatAgentsMdContext(agents);\n if (fragment) fragments.push(fragment);\n }\n\n let skills: SkillsContext = enableSkills\n ? discoverSkills(workdir, opts.skills)\n : { skills: [], warnings: [] };\n const disabled = new Set(opts.disabledSkills ?? []);\n if (disabled.size > 0 && skills.skills.length > 0) {\n skills = { ...skills, skills: skills.skills.filter((skill) => !disabled.has(skill.name)) };\n }\n warnings.push(...skills.warnings);\n const catalog = formatSkillsCatalog(skills);\n if (catalog) fragments.push(catalog);\n\n return { agents, skills, fragments, warnings };\n}\n","/**\n * 会话元数据索引(index.json)—— JSONL 文件的查询索引,不是事实源。\n *\n * 设计(移植自 MovieClaw 的「文件是事实源,DB 只是索引」并去 SQLite 化):\n * - 索引随时可由 sessions/ 目录的 JSONL 文件整体重建(rebuild);\n * - 写入顺序固定「先落 JSONL 文件、后更新索引」,两步之间崩溃只会让索引\n * 落后,启动时扫描重建即自愈;\n * - 写盘一律 tmp + rename 原子换入;\n * - 运行状态不持久化静态 status:只记 last_heartbeat 时间戳,进程硬崩后\n * 心跳自然停止,超过超时窗即视为已结束(状态自愈)。\n * - 归档标记 archived_at 与 title 同级:只存索引不进 JSONL,rebuild 时\n * 从旧索引保留;代价是 index.json 整体丢失时归档/标题归零(可接受)。\n *\n * 升级预留:未来 SQLite 化只需用相同方法表面(create/get/touchAfterAppend/\n * rename/setArchived/markRunning/heartbeat/finishRun/isRunning/list/remove/\n * rebuild)替换本类实现,路由层不感知存储介质。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { SessionSummary } from \"../agent/sessions.js\";\nimport { PREVIEW_MAX_CHARS } from \"../agent/sessions.js\";\n\n/** 心跳超时窗(毫秒):超过即视为运行已结束;须大于记录器的心跳间隔 */\nexport const HEARTBEAT_TIMEOUT_MS = 30_000;\n\nexport interface RunningState {\n run_id: string;\n /** 最近一次心跳的 epoch 毫秒 */\n last_heartbeat: number;\n}\n\nexport interface SessionMeta {\n session_id: string;\n created_at: string;\n title: string | null;\n last_prompt: string | null;\n entry_count: number;\n leaf_uuid: string | null;\n last_active: string;\n /** 归档时间(ISO);null = 活跃。归档 = 只读,恢复后才能继续会话 */\n archived_at: string | null;\n running: RunningState | null;\n}\n\nexport class SessionIndex {\n private readonly file: string;\n private readonly metas = new Map<string, SessionMeta>();\n\n constructor(indexFile: string) {\n this.file = indexFile;\n this.load();\n }\n\n /** 启动时加载;文件不存在/损坏则从空开始(rebuild 会补齐) */\n private load(): void {\n try {\n const raw = JSON.parse(fs.readFileSync(this.file, \"utf-8\")) as { sessions?: SessionMeta[] };\n for (const meta of raw.sessions ?? []) this.metas.set(meta.session_id, meta);\n } catch {\n this.metas.clear();\n }\n }\n\n /** 从事实源整体重建(启动自愈):扫描结果单向覆盖索引 */\n rebuild(summaries: SessionSummary[]): void {\n for (const s of summaries) {\n const existing = this.metas.get(s.session_id);\n this.metas.set(s.session_id, {\n session_id: s.session_id,\n created_at: s.created_at,\n // 已有人工标题时保留(文件里不存标题,扫描回填的是首条 user 消息)\n title: existing?.title ?? s.title,\n last_prompt: s.last_prompt,\n entry_count: s.entry_count,\n leaf_uuid: s.leaf_uuid,\n last_active: s.last_timestamp,\n // 归档标记与 title 同级:从旧索引保留,不被扫描回填覆盖\n archived_at: existing?.archived_at ?? null,\n running: null, // 进程刚启动,任何「运行中」都是上一世的残留\n });\n }\n this.persist();\n }\n\n create(sessionId: string): void {\n const now = new Date().toISOString();\n this.metas.set(sessionId, {\n session_id: sessionId,\n created_at: now,\n title: null,\n last_prompt: null,\n entry_count: 0,\n leaf_uuid: null,\n last_active: now,\n archived_at: null,\n running: null,\n });\n this.persist();\n }\n\n get(sessionId: string): SessionMeta | undefined {\n return this.metas.get(sessionId);\n }\n\n /** 每次追加 entry 后刷新链尾/计数/预览;title 仅在传入时更新(首条消息) */\n touchAfterAppend(\n sessionId: string,\n update: { leaf_uuid: string; entry_count: number; last_prompt?: string; title?: string },\n ): void {\n const meta = this.metas.get(sessionId);\n if (!meta) return;\n meta.leaf_uuid = update.leaf_uuid;\n meta.entry_count = update.entry_count;\n meta.last_active = new Date().toISOString();\n if (update.last_prompt !== undefined) {\n meta.last_prompt = update.last_prompt.slice(0, PREVIEW_MAX_CHARS);\n }\n if (update.title !== undefined && meta.title === null) {\n meta.title = update.title.slice(0, PREVIEW_MAX_CHARS);\n }\n this.persist();\n }\n\n rename(sessionId: string, title: string): boolean {\n const meta = this.metas.get(sessionId);\n if (!meta) return false;\n meta.title = title.slice(0, PREVIEW_MAX_CHARS);\n this.persist();\n return true;\n }\n\n /** 归档/恢复(null 表示恢复为活跃);会话不存在返回 false */\n setArchived(sessionId: string, archived: boolean): boolean {\n const meta = this.metas.get(sessionId);\n if (!meta) return false;\n meta.archived_at = archived ? new Date().toISOString() : null;\n this.persist();\n return true;\n }\n\n /** 是否已归档(归档 = 只读) */\n isArchived(sessionId: string): boolean {\n return this.metas.get(sessionId)?.archived_at != null;\n }\n\n markRunning(sessionId: string, runId: string): void {\n const meta = this.metas.get(sessionId);\n if (!meta) return;\n meta.running = { run_id: runId, last_heartbeat: Date.now() };\n this.persist();\n }\n\n heartbeat(sessionId: string): void {\n const meta = this.metas.get(sessionId);\n if (!meta?.running) return;\n meta.running.last_heartbeat = Date.now();\n this.persist();\n }\n\n finishRun(sessionId: string): void {\n const meta = this.metas.get(sessionId);\n if (!meta) return;\n meta.running = null;\n this.persist();\n }\n\n /** 是否有正在进行的消息处理:运行标记存在且心跳未超时 */\n isRunning(sessionId: string): boolean {\n const running = this.metas.get(sessionId)?.running;\n if (!running) return false;\n return Date.now() - running.last_heartbeat < HEARTBEAT_TIMEOUT_MS;\n }\n\n /** 按最后活跃时间倒序分页 */\n list(limit: number, offset: number): SessionMeta[] {\n return [...this.metas.values()]\n .sort((a, b) => b.last_active.localeCompare(a.last_active))\n .slice(offset, offset + limit);\n }\n\n remove(sessionId: string): void {\n this.metas.delete(sessionId);\n this.persist();\n }\n\n private persist(): void {\n const dir = path.dirname(this.file);\n fs.mkdirSync(dir, { recursive: true });\n const tmp = `${this.file}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify({ sessions: [...this.metas.values()] }, null, 2));\n fs.renameSync(tmp, this.file);\n }\n}\n"],"mappings":"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","names":["errMsg","safeParse","ok","import_zod","import_zod","path","os","crypto","fs","import_node_crypto","truncateMiddle","import_node_path","path","crypto","truncateMiddle","import_node_fs","import_node_path","import_node_crypto","import_node_fs","import_node_path","import_zod","import_node_fs","import_node_path","fs","path","fs","path","crypto","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","import_node_crypto","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","crypto","import_node_fs","import_zod","import_node_crypto","session","crypto","truncateMiddle","argsSchema","fs","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","import_node_path","import_node_fs","import_node_os","import_node_path","os","path","parseYaml","fs","path","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","import_node_fs","import_node_path","import_zod","IGNORE_NAMES","argsSchema","fs","globToRegExp","path","import_node_fs","import_node_path","import_node_crypto","import_zod","argsSchema","fs","path","crypto","import_zod","argsSchema","path","fs","import_node_path","import_node_fs","import_node_path","import_zod","path","fs","import_node_fs","import_zod","import_node_crypto","crypto","fs","import_hono","import_node_fs","import_node_path","import_zod","import_node_fs","import_node_path","fs","path","history","runId","path","fs","import_node_fs","import_node_path","fs","path","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/llm/models.ts","../src/llm/errors.ts","../src/llm/credential.ts","../src/llm/http-error.ts","../src/llm/sse.ts","../src/llm/stream-assembler.ts","../src/llm/protocols/messages.ts","../src/llm/protocols/responses.ts","../src/llm/router.ts","../src/llm/validate.ts","../src/agent/events.ts","../src/agent/prompts.ts","../src/agent/retained-context.ts","../src/agent/compaction.ts","../src/agent/sessions.ts","../src/agent/runner.ts","../src/tools/types.ts","../src/agent/escalation.ts","../src/tools/index.ts","../src/tools/apply-patch.ts","../src/tools/workdir.ts","../src/tools/create.ts","../src/tools/edit.ts","../src/tools/exec-command.ts","../src/tools/process-manager.ts","../src/tools/list.ts","../src/tools/load-skill.ts","../src/context/skills.ts","../src/tools/read.ts","../src/tools/search.ts","../src/tools/write.ts","../src/tools/write-stdin.ts","../src/server/index.ts","../src/server/config.ts","../src/server/config-routes.ts","../src/server/run-registry.ts","../src/server/recorder.ts","../src/server/routes.ts","../src/context/agents-md.ts","../src/context/index.ts","../src/server/session-index.ts"],"sourcesContent":["/**\n * xlyra-agent 公共出口。\n *\n * 分层:llm/(怎么调模型)→ agent/(一次任务怎么跑)→ server/(HTTP 服务)。\n * 库用法只 import 本文件即可拿到全部公共 API。\n */\nexport * from \"./llm/index.js\";\nexport * from \"./agent/index.js\";\nexport * from \"./tools/index.js\";\nexport {\n createAgentServer,\n serveFromConfig,\n createAgentRoutes,\n loadConfig,\n saveConfig,\n upsertEndpoint,\n removeEndpoint,\n configExists,\n defaultConfigPath,\n HttpError,\n RunRegistry,\n SessionIndex,\n AgentRunRecorder,\n type AppConfig,\n type ServerConfig,\n type AgentServiceConfig,\n type StoredAgentEvent,\n} from \"./server/index.js\";\n\nexport * from \"./context/index.js\";\n","/**\n * 内部规范模型 —— 协议无关的对话数据表达。\n *\n * 分层定位:llm/protocols/ 下的两个适配器(OpenAI Responses / Anthropic\n * Messages)负责把各自 wire 格式翻译成这里的模型;agent 层(runner/压缩/\n * 工具)永远只面对本文件定义的结构,不感知任何协议细节。\n *\n * 设计要点:\n * - ToolCall 始终保留 raw_arguments 原文(字符串),parse 发生在使用方——\n * 流式分片期间参数是不完整 JSON,只有归并完成后才可能解析成功;\n * - ChatMessage 带 thinking / thinking_signature:Anthropic 多轮工具往返\n * 要求带签名的 thinking block 原样回喂(评审定案透传),无签名的旧消息\n * 回喂时整块省略(API 允许);\n * - tool 角色的 is_error:Anthropic tool_result block 需要显式标注失败。\n */\nimport { z } from \"zod\";\n\nexport const toolCallSchema = z.object({\n id: z.string(),\n name: z.string(),\n /** 参数 JSON 原文(流式归并后的完整串;可能不是合法 JSON,由校验阶段兜底) */\n raw_arguments: z.string(),\n});\nexport type ToolCall = z.infer<typeof toolCallSchema>;\n\nexport const chatMessageSchema = z.object({\n role: z.enum([\"system\", \"user\", \"assistant\", \"tool\"]),\n content: z.string().default(\"\"),\n tool_calls: z.array(toolCallSchema).optional(),\n tool_call_id: z.string().optional(),\n name: z.string().optional(),\n is_error: z.boolean().optional(),\n thinking: z.string().optional(),\n thinking_signature: z.string().optional(),\n});\nexport type ChatMessage = z.infer<typeof chatMessageSchema>;\n\n/** 消息正文文本(当前为纯文本管线,直接返回 content;保留函数形态便于将来多模态扩展) */\nexport function messageText(message: ChatMessage): string {\n return message.content ?? \"\";\n}\n\nexport const tokenUsageSchema = z.object({\n prompt_tokens: z.number().default(0),\n completion_tokens: z.number().default(0),\n total_tokens: z.number().default(0),\n cache_read_tokens: z.number().default(0),\n});\nexport type TokenUsage = z.infer<typeof tokenUsageSchema>;\n\nexport function emptyUsage(): TokenUsage {\n return { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, cache_read_tokens: 0 };\n}\n\nexport function addUsage(total: TokenUsage, step: TokenUsage): TokenUsage {\n return {\n prompt_tokens: total.prompt_tokens + step.prompt_tokens,\n completion_tokens: total.completion_tokens + step.completion_tokens,\n total_tokens: total.total_tokens + step.total_tokens,\n cache_read_tokens: total.cache_read_tokens + step.cache_read_tokens,\n };\n}\n\nexport const modelSettingsSchema = z.object({\n temperature: z.number().optional(),\n max_tokens: z.number().optional(),\n /** 思考强度:映射到 Anthropic thinking budget / OpenAI reasoning effort。\n * max/ultra 是网关侧的更高档位别名,协议层统一归一为 xhigh */\n reasoning_effort: z.enum([\"low\", \"medium\", \"high\", \"xhigh\", \"max\", \"ultra\"]).optional(),\n});\nexport type ModelSettings = z.infer<typeof modelSettingsSchema>;\n\nexport type ReasoningEffort = NonNullable<ModelSettings[\"reasoning_effort\"]>;\n\n/** 归一化思考强度:max/ultra 一律按 xhigh 处理 */\nexport function normalizeEffort(effort: ReasoningEffort): \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n return effort === \"max\" || effort === \"ultra\" ? \"xhigh\" : effort;\n}\n\n/** 暴露给模型的工具声明(parameters 为 JSON Schema object) */\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n}\n\n/** 一次模型调用的定稿响应(done 事件的载荷) */\nexport interface ChatResponse {\n content: string;\n thinking: string | null;\n thinking_signature: string | null;\n tool_calls: ToolCall[];\n usage: TokenUsage;\n finish_reason: string | null;\n model: string;\n provider: string;\n}\n\n/** 定稿响应 → 入对话历史的 assistant 消息(思考链与签名随消息保存,供历史回喂) */\nexport function responseToMessage(response: ChatResponse): ChatMessage {\n const message: ChatMessage = { role: \"assistant\", content: response.content };\n if (response.tool_calls.length > 0) message.tool_calls = response.tool_calls;\n if (response.thinking) message.thinking = response.thinking;\n if (response.thinking_signature) message.thinking_signature = response.thinking_signature;\n return message;\n}\n","/**\n * LLM 层错误:路由解析失败(没配端点/模型不存在)等**调用前**错误抛出;\n * 调用中的流错误一律走 StreamEvent error 事件,不抛异常。\n */\nexport class LlmError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LlmError\";\n }\n}\n","/**\n * 统一凭证解析:direct 与 remote-xlyra 都经此得到「凭证类型 + HTTP header」,\n * 协议实现不自行判断配置字段,也不把所有凭证当作同一种认证方式。\n *\n * 认证规则(docs 第 6 章定稿):\n * - direct + openai-responses → Authorization: Bearer <api_key>\n * - direct + anthropic-messages → x-api-key: <api_key>\n * - remote-xlyra(两种协议) → Authorization: Bearer <temporary-token>\n *\n * 纪律:token/api_key 只存在于 ResolvedCredential.headerValue 与 provider 内部,\n * 不得写入日志、事件、transcript 或错误信息。\n */\nimport { LlmError } from \"./errors.js\";\nimport type { AgentRunContext, EndpointConfig } from \"./router.js\";\n\nexport interface ResolvedCredential {\n kind: \"api-key\" | \"temporary-bearer\";\n headerName: \"authorization\" | \"x-api-key\";\n headerValue: string;\n}\n\nexport interface CredentialProvider {\n getCredential(): Promise<ResolvedCredential>;\n}\n\n/** 静态凭证:direct api_key 或 remote-xlyra 固定 token,一经构造不变 */\nexport class StaticCredentialProvider implements CredentialProvider {\n constructor(private readonly credential: ResolvedCredential) {}\n\n getCredential(): Promise<ResolvedCredential> {\n return Promise.resolve(this.credential);\n }\n}\n\n/**\n * xlyra-callback 凭证 provider:首次缺 token 走 callback 初始签发;之后按\n * expires_at 提前主动续期(持旧 token 调 /credential/renew 换新 token)。\n * token 只保存在进程内存。\n *\n * 续期纪律(docs §8 定稿):\n * - 续期由 runner 主动发起,绝不由 LLM 入口的 401 触发——401 只表示凭证\n * 已被吊销或 run 已结束,此时不得换票,应终止当前 run;\n * - renew 是持票认证:请求携带当前 token 做 Bearer,过期/被顶替的凭证\n * 无法换新;\n * - token 按 runId 隔离存储,并发 run 各自持有独立 token,互不作废\n * (xLyra 按 run_id 校验,串 run 用 token 会 401);\n * - 并发首次取 token / 续期各自合并为一次 in-flight 请求,避免重复签发。\n */\n\n/** 主动续期阈值:剩余 TTL 低于该值时,下次取凭证先换票 */\nconst DEFAULT_RENEW_THRESHOLD_MS = 5 * 60_000;\n/** 响应缺少合法 expires_at 时的保守兜底有效期 */\nconst FALLBACK_TOKEN_TTL_MS = 15 * 60_000;\nconst INITIAL_ISSUE_ATTEMPTS = 6;\nconst INITIAL_ISSUE_RETRY_DELAY_MS = 500;\n\ninterface CachedCredential {\n credential: ResolvedCredential;\n /** epoch 毫秒 */\n expiresAt: number;\n}\n\nexport class XlyraCallbackCredentialProvider implements CredentialProvider {\n private context: AgentRunContext | null = null;\n /** runId → 当前有效 token 及其过期时刻 */\n private readonly tokensByRun = new Map<string, CachedCredential>();\n /** runId → 进行中的签发/续期(并发去重) */\n private readonly inflight = new Map<string, Promise<CachedCredential | null>>();\n private readonly fetchImpl: typeof fetch;\n private readonly renewThresholdMs: number;\n private readonly sleep: (ms: number) => Promise<void>;\n private readonly now: () => number;\n\n constructor(\n private readonly url: string,\n opts?: {\n fetchImpl?: typeof fetch;\n renewThresholdMs?: number;\n sleep?: (ms: number) => Promise<void>;\n now?: () => number;\n },\n ) {\n this.fetchImpl = opts?.fetchImpl ?? fetch;\n this.renewThresholdMs = opts?.renewThresholdMs ?? DEFAULT_RENEW_THRESHOLD_MS;\n this.sleep = opts?.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n this.now = opts?.now ?? Date.now;\n }\n\n /** 更新当前 run 上下文。token 按 runId 隔离,切换 run 不影响其他 run 的 token */\n setRunContext(context: AgentRunContext): void {\n this.context = context;\n }\n\n async getCredential(): Promise<ResolvedCredential> {\n return this.getCredentialFor(this.requireContext().runId);\n }\n\n /**\n * 按 run 取凭证(并发安全):chatStream 在请求开始时调用一次并全程使用\n * 返回值——并发 run 各自的 token 互不干扰(setRunContext 只影响下一次\n * 请求开始时的解析)。缓存 token 临近过期时先主动续期再返回。\n */\n async getCredentialFor(runId: string): Promise<ResolvedCredential> {\n const cached = this.tokensByRun.get(runId);\n if (cached) {\n const remaining = cached.expiresAt - this.now();\n if (remaining > this.renewThresholdMs) return cached.credential;\n const renewed = await this.renewCredentialFor(runId);\n if (renewed) return renewed;\n if (remaining > 0) return cached.credential; // 续期失败但旧 token 仍有效:沿用\n throw new LlmError(\"xLyra LLM 调用凭证不可用:token 已过期且续期失败\");\n }\n const issued = await this.issueInitial(runId);\n if (!issued) {\n throw new LlmError(\"xLyra LLM 调用凭证不可用:run 已结束或 callback 未签发 token\");\n }\n return issued;\n }\n\n /**\n * 401 重试专用:仅当本地凭证自 used 之后已被轮换(主动续期换上了新\n * token)时返回新凭证,否则返回 null——401 本身不触发换票。\n */\n rotatedCredentialFor(runId: string, used: ResolvedCredential): ResolvedCredential | null {\n const cached = this.tokensByRun.get(runId);\n if (!cached || cached.credential === used) return null;\n return cached.credential;\n }\n\n /**\n * 持票续期(并发去重):携带当前 token 调 renew 端点换新 token。\n * 返回 null:无缓存、上下文已换 run、renew 被拒(token 失效/run 结束)\n * 或网络失败——调用方按语义自行决定是否沿用旧 token 或终止 run。\n */\n renewCredentialFor(runId: string): Promise<ResolvedCredential | null> {\n const context = this.requireContext();\n if (context.runId !== runId) return Promise.resolve(null); // 上下文已换 run,拒签\n const cached = this.tokensByRun.get(runId);\n if (!cached) return Promise.resolve(null);\n return this.dedup(runId, () => this.doRenew(context, cached));\n }\n\n /** 首次签发(并发去重):run 还没有 token 时调 credential callback */\n private issueInitial(runId: string): Promise<ResolvedCredential | null> {\n const context = this.requireContext();\n if (context.runId !== runId) return Promise.resolve(null);\n return this.dedup(runId, () => this.doIssueInitial(context));\n }\n\n private dedup(runId: string, task: () => Promise<CachedCredential | null>): Promise<ResolvedCredential | null> {\n const pending = this.inflight.get(runId);\n if (pending) return pending.then((cached) => cached?.credential ?? null);\n const promise = task().finally(() => {\n this.inflight.delete(runId);\n });\n this.inflight.set(runId, promise);\n return promise.then((cached) => cached?.credential ?? null);\n }\n\n private requireContext(): AgentRunContext {\n if (!this.context) {\n throw new LlmError(\"xLyra LLM 凭证缺少 run 上下文(agent_instance_id/session_id/run_id)\");\n }\n return this.context;\n }\n\n private async doIssueInitial(context: AgentRunContext): Promise<CachedCredential | null> {\n for (let attempt = 0; attempt < INITIAL_ISSUE_ATTEMPTS; attempt += 1) {\n if (attempt > 0) await this.sleep(INITIAL_ISSUE_RETRY_DELAY_MS);\n let res: Response;\n try {\n res = await this.fetchImpl(this.url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n agent_instance_id: context.agentInstanceId,\n session_id: context.sessionId,\n run_id: context.runId,\n model: context.model,\n reason: \"initial\",\n }),\n });\n } catch {\n continue;\n }\n const cached = await this.storeFromResponse(context.runId, res);\n if (cached) return cached;\n }\n return null;\n }\n\n private async doRenew(context: AgentRunContext, cached: CachedCredential): Promise<CachedCredential | null> {\n let res: Response;\n try {\n res = await this.fetchImpl(`${this.url}/renew`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n // 持票认证:token 只出现在 Authorization header,不进日志与错误\n authorization: cached.credential.headerValue,\n },\n });\n } catch {\n return null;\n }\n return this.storeFromResponse(context.runId, res);\n }\n\n private async storeFromResponse(runId: string, res: Response): Promise<CachedCredential | null> {\n if (!res.ok) return null;\n let payload: { active?: unknown; token?: unknown; expires_at?: unknown };\n try {\n payload = (await res.json()) as typeof payload;\n } catch {\n return null;\n }\n if (payload.active !== true || typeof payload.token !== \"string\" || !payload.token) {\n return null;\n }\n const parsedExpiry = typeof payload.expires_at === \"string\" ? Date.parse(payload.expires_at) : Number.NaN;\n const cached: CachedCredential = {\n credential: {\n kind: \"temporary-bearer\",\n headerName: \"authorization\",\n headerValue: `Bearer ${payload.token}`,\n },\n expiresAt: Number.isNaN(parsedExpiry) ? this.now() + FALLBACK_TOKEN_TTL_MS : parsedExpiry,\n };\n this.tokensByRun.set(runId, cached);\n // 只保留最近若干个 run 的 token(长时间运行进程的内存卫生)\n if (this.tokensByRun.size > 64) {\n const oldest = this.tokensByRun.keys().next().value;\n if (oldest !== undefined) this.tokensByRun.delete(oldest);\n }\n return cached;\n }\n}\n\n/** 按 endpoint 配置构造凭证 provider;配置非法在启动期就已被 schema 拦截,这里兜底 */\nexport function resolveCredentialProvider(endpoint: EndpointConfig): CredentialProvider {\n if (endpoint.mode === \"remote-xlyra\") {\n if (endpoint.credential?.type === \"xlyra-callback\") {\n return new XlyraCallbackCredentialProvider(endpoint.credential.url);\n }\n const token = endpoint.credential?.token;\n if (!token) throw new LlmError(`端点 ${endpoint.name} 未配置临时 LLM 凭证`);\n return new StaticCredentialProvider({\n kind: \"temporary-bearer\",\n headerName: \"authorization\",\n headerValue: `Bearer ${token}`,\n });\n }\n\n if (!endpoint.api_key) {\n throw new LlmError(`端点 ${endpoint.name} 未配置 api_key`);\n }\n\n return new StaticCredentialProvider(\n endpoint.protocol === \"anthropic-messages\"\n ? { kind: \"api-key\", headerName: \"x-api-key\", headerValue: endpoint.api_key }\n : {\n kind: \"api-key\",\n headerName: \"authorization\",\n headerValue: `Bearer ${endpoint.api_key}`,\n },\n );\n}\n\n/** 判断 provider 是否支持 callback 轮换(协议层 401 重试用) */\nexport function isRefreshable(provider: CredentialProvider): provider is XlyraCallbackCredentialProvider {\n return provider instanceof XlyraCallbackCredentialProvider;\n}\n","/**\n * 上游 HTTP 错误的脱敏摘要(docs §8.3/§12.1):\n * - 不回传完整响应体:只提取常见 JSON 形态里的 message 字段,截断到 200 字符;\n * - 已知秘密(token/api_key 等)若出现在消息里,一律替换为 ***;\n * - 非 JSON 响应体只回状态文本,不回原文。\n */\nimport type { ResolvedCredential } from \"./credential.js\";\n\nexport async function httpErrorSummary(res: Response, secrets: string[] = []): Promise<string> {\n const raw = await res.text().catch(() => \"\");\n let msg = \"\";\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n const j = parsed as { error?: { message?: unknown }; message?: unknown };\n const candidate = j.error?.message ?? j.message;\n if (typeof candidate === \"string\") msg = candidate;\n }\n } catch {\n // 非 JSON:不回传响应体原文\n }\n msg = msg.slice(0, 200);\n for (const secret of secrets) {\n if (secret) msg = msg.split(secret).join(\"***\");\n }\n return `请求失败(HTTP ${res.status}):${msg || res.statusText}`;\n}\n\n/**\n * 从凭证推导脱敏秘密集合:同时覆盖完整 headerValue(\"Bearer xxx\")与\n * 裸 token(上游错误消息通常不带 Bearer 前缀)。\n */\nexport function credentialSecrets(cred: ResolvedCredential): string[] {\n const bare = cred.headerValue.startsWith(\"Bearer \")\n ? cred.headerValue.slice(\"Bearer \".length)\n : cred.headerValue;\n return bare === cred.headerValue ? [cred.headerValue] : [cred.headerValue, bare];\n}\n","/**\n * 极简 SSE 解析器 —— 两套协议适配器共用。\n *\n * 覆盖 SSE 规范的常用子集:`event:` / 多行 `data:` 拼接 / `: comment`\n * 心跳行 / \\r\\n 与 \\n 换行 / OpenAI 的 `data: [DONE]` 哨兵。\n * 不依赖任何第三方库;输入是 fetch 响应的 body 流。\n */\n\nexport interface SseEvent {\n /** event 字段值;缺省为空串(OpenAI 系协议通常不写 event,靠 data 里的 type) */\n event: string;\n /** 多行 data 已按规范以 \\n 拼接 */\n data: string;\n}\n\nexport async function* parseSse(body: ReadableStream<Uint8Array>): AsyncGenerator<SseEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventName = \"\";\n let dataLines: string[] = [];\n\n const flush = (): SseEvent | null => {\n if (dataLines.length === 0) {\n eventName = \"\";\n return null;\n }\n const evt: SseEvent = { event: eventName, data: dataLines.join(\"\\n\") };\n eventName = \"\";\n dataLines = [];\n return evt;\n };\n\n const handleLine = function* (line: string): Generator<SseEvent> {\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1);\n if (line === \"\") {\n const evt = flush();\n if (evt) yield evt;\n return;\n }\n if (line.startsWith(\":\")) return; // 心跳/注释行\n const colon = line.indexOf(\":\");\n const field = colon === -1 ? line : line.slice(0, colon);\n // 规范:冒号后的一个前导空格要剥掉\n let value = colon === -1 ? \"\" : line.slice(colon + 1);\n if (value.startsWith(\" \")) value = value.slice(1);\n if (field === \"event\") eventName = value;\n else if (field === \"data\") dataLines.push(value);\n // id:/retry: 等字段当前协议均不需要,忽略\n };\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) !== -1) {\n const line = buffer.slice(0, nl);\n buffer = buffer.slice(nl + 1);\n yield* handleLine(line);\n }\n }\n // 流末尾可能残留未以空行收尾的事件\n if (buffer.length > 0) yield* handleLine(buffer);\n const tail = flush();\n if (tail) yield tail;\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * 流式 tool_call 归并器 —— 两个协议适配器共用。\n *\n * 两套协议的参数都是逐片增量(Responses 的 function_call_arguments.delta /\n * Anthropic 的 input_json_delta),适配器以各自的归并键(item_id / block\n * index)调用本类累积,end 时得到 raw_arguments 全量。\n *\n * 刻意不在增量阶段做 partial parse(避免 O(n²) 重复解析);end 时的\n * JSON.parse 失败也不报错——raw_arguments 保留原文,由 runner 的参数\n * 校验阶段统一报错回喂模型。\n */\nimport type { ToolCall } from \"./models.js\";\n\ninterface BufferEntry {\n id: string;\n name: string;\n raw: string;\n}\n\nexport class ToolCallBuffer {\n private readonly buffers = new Map<string, BufferEntry>();\n\n /** 名称确定的第一刻登记;返回仅含 id/name 的 ToolCall(供 toolcall_start 事件) */\n start(key: string, id: string, name: string): ToolCall {\n this.buffers.set(key, { id, name, raw: \"\" });\n return { id, name, raw_arguments: \"\" };\n }\n\n /** 追加参数分片;返回当前快照(供 toolcall_delta 事件携带归属信息) */\n append(key: string, delta: string): ToolCall | null {\n const entry = this.buffers.get(key);\n if (!entry) return null;\n entry.raw += delta;\n return { id: entry.id, name: entry.name, raw_arguments: entry.raw };\n }\n\n /** 结束归并;fullRaw 提供时以全量为准(Responses 的 .done 事件自带全量串) */\n finish(key: string, fullRaw?: string): ToolCall | null {\n const entry = this.buffers.get(key);\n if (!entry) return null;\n this.buffers.delete(key);\n return { id: entry.id, name: entry.name, raw_arguments: fullRaw ?? entry.raw };\n }\n\n /** 流异常终止时丢弃全部未完成归并 */\n clear(): void {\n this.buffers.clear();\n }\n\n get pendingCount(): number {\n return this.buffers.size;\n }\n}\n","/**\n * Anthropic Messages API 适配器。\n *\n * 按官方文档实现(https://docs.claude.com/en/api/messages-streaming):\n * - 请求:POST {base_url}/v1/messages,system 是顶层字段;assistant 的\n * tool_calls → tool_use content blocks;tool 结果并入 user 消息的\n * tool_result blocks;max_tokens 必填;\n * - 流式:content_block 状态机按 block index 归并;input_json_delta\n * 累积到 content_block_stop 才 parse(避免每片 partial parse 的 O(n²));\n * signature_delta 必须采集——评审定案 thinking 签名透传进历史,\n * 多轮工具往返要求带签名的 thinking block 原样回喂。\n *\n * 实现纪律(来自公开 issue 的已知坑):\n * - delta 类型与当前 block 类型不符 → 按流损坏处理,error 事件收尾,不猜;\n * - tool_result 必须与此前 assistant 的 tool_use 严格配对(runner 保证),\n * 否则 API 400。\n */\nimport { LlmError } from \"../errors.js\";\nimport { httpErrorSummary, credentialSecrets } from \"../http-error.js\";\nimport {\n isRefreshable,\n StaticCredentialProvider,\n type CredentialProvider,\n type ResolvedCredential,\n} from \"../credential.js\";\nimport { normalizeEffort, type ChatMessage, type ChatResponse, type ToolDefinition } from \"../models.js\";\nimport type { ChatRequest, LlmProtocol, StreamEvent } from \"../protocol.js\";\nimport type { AgentRunContext } from \"../router.js\";\nimport { parseSse } from \"../sse.js\";\nimport { ToolCallBuffer } from \"../stream-assembler.js\";\n\nexport interface MessagesEndpointOptions {\n baseUrl: string;\n /**\n * 统一凭证来源(推荐)。apiKey 是 direct 模式的简写,\n * 等价于 x-api-key: <apiKey> 的静态凭证。\n */\n credential?: CredentialProvider;\n apiKey?: string;\n providerName?: string;\n /** anthropic-version 头;默认官方当前版本 */\n apiVersion?: string;\n /** 测试注入用;默认全局 fetch */\n fetchImpl?: typeof fetch;\n}\n\ntype Json = Record<string, unknown>;\n\nconst DEFAULT_MAX_TOKENS = 8192;\n\n/** reasoning_effort → thinking budget(官方建议 budget ≥ 1024 且 < max_tokens) */\nconst THINKING_BUDGET = { low: 2048, medium: 8192, high: 24576, xhigh: 49152 } as const;\n\n/** 内部消息 → Anthropic messages 数组 + 顶层 system */\nexport function toAnthropicMessages(messages: ChatMessage[]): {\n system: string | undefined;\n messages: Json[];\n} {\n const systemParts: string[] = [];\n const out: Json[] = [];\n\n const flushToolResults = (pending: Json[]): void => {\n if (pending.length > 0) {\n // 连续的 tool 结果合并进同一条 user 消息(多个 tool_result block)\n out.push({ role: \"user\", content: pending.splice(0, pending.length) });\n }\n };\n\n const pendingToolResults: Json[] = [];\n for (const m of messages) {\n if (m.role === \"system\") {\n if (m.content) systemParts.push(m.content);\n continue;\n }\n if (m.role === \"tool\") {\n const block: Json = {\n type: \"tool_result\",\n tool_use_id: m.tool_call_id ?? \"\",\n content: m.content,\n };\n if (m.is_error) block.is_error = true;\n pendingToolResults.push(block);\n continue;\n }\n flushToolResults(pendingToolResults);\n if (m.role === \"user\") {\n out.push({ role: \"user\", content: m.content });\n continue;\n }\n // assistant:thinking(有签名才回喂)→ text → tool_use blocks\n const blocks: Json[] = [];\n if (m.thinking && m.thinking_signature) {\n blocks.push({ type: \"thinking\", thinking: m.thinking, signature: m.thinking_signature });\n }\n if (m.content) blocks.push({ type: \"text\", text: m.content });\n for (const tc of m.tool_calls ?? []) {\n blocks.push({ type: \"tool_use\", id: tc.id, name: tc.name, input: parseArgs(tc.raw_arguments) });\n }\n out.push({ role: \"assistant\", content: blocks.length ? blocks : [{ type: \"text\", text: \"\" }] });\n }\n flushToolResults(pendingToolResults);\n return { system: systemParts.length ? systemParts.join(\"\\n\\n\") : undefined, messages: out };\n}\n\nfunction parseArgs(raw: string): Json {\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as Json) : {};\n } catch {\n return {}; // 参数原文非法时给空对象:模型会在工具结果里收到校验错误并自行修正\n }\n}\n\nfunction toAnthropicTools(tools: ToolDefinition[]): Json[] {\n return tools.map((t) => ({ name: t.name, description: t.description, input_schema: t.parameters }));\n}\n\ntype BlockKind = \"text\" | \"thinking\" | \"tool_use\";\n\nexport class AnthropicMessagesProtocol implements LlmProtocol {\n readonly name = \"anthropic-messages\";\n private readonly baseUrl: string;\n private readonly credential: CredentialProvider;\n private readonly provider: string;\n private readonly apiVersion: string;\n private readonly fetchImpl: typeof fetch;\n private runContext: AgentRunContext | null = null;\n\n constructor(opts: MessagesEndpointOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n if (opts.credential) {\n this.credential = opts.credential;\n } else if (opts.apiKey) {\n this.credential = new StaticCredentialProvider({\n kind: \"api-key\",\n headerName: \"x-api-key\",\n headerValue: opts.apiKey,\n });\n } else {\n throw new LlmError(\"AnthropicMessagesProtocol 缺少凭证(credential 或 apiKey)\");\n }\n this.provider = opts.providerName ?? \"anthropic\";\n this.apiVersion = opts.apiVersion ?? \"2023-06-01\";\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n /** 更新 run 上下文:仅 xlyra-callback 凭证消费;静态凭证为 no-op */\n setRunContext(context: AgentRunContext): void {\n this.runContext = context;\n if (isRefreshable(this.credential)) this.credential.setRunContext(context);\n }\n\n /**\n * 请求开始时解析本次 run 的凭证:xlyra-callback 按 runId 定向取\n * (并发 run 各自独立),静态凭证直接返回。\n */\n private resolveRequestCredential(): Promise<ResolvedCredential> {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.getCredentialFor(this.runContext.runId);\n }\n return this.credential.getCredential();\n }\n\n /** 401 后仅当本地凭证已被主动续期轮换时返回新 token;401 本身不触发换票 */\n private rotatedRequestCredential(used: ResolvedCredential): ResolvedCredential | null {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.rotatedCredentialFor(this.runContext.runId, used);\n }\n return null;\n }\n\n async *chatStream(req: ChatRequest): AsyncIterable<StreamEvent> {\n const { system, messages } = toAnthropicMessages(req.messages);\n const maxTokens = req.settings.max_tokens ?? DEFAULT_MAX_TOKENS;\n const body: Json = { model: req.model, max_tokens: maxTokens, messages, stream: true };\n if (system) body.system = system;\n if (req.tools?.length) body.tools = toAnthropicTools(req.tools);\n if (req.settings.temperature !== undefined) body.temperature = req.settings.temperature;\n if (req.settings.reasoning_effort) {\n const budget = Math.min(THINKING_BUDGET[normalizeEffort(req.settings.reasoning_effort)], maxTokens - 1);\n if (budget >= 1024) body.thinking = { type: \"enabled\", budget_tokens: budget };\n }\n\n let cred;\n try {\n cred = await this.resolveRequestCredential();\n } catch (err) {\n // 凭证获取失败(如 callback 未签发):原文上抛语义,不归类为网络错误\n yield { type: \"error\", error: errMsg(err) };\n return;\n }\n\n const doFetch = (c: ResolvedCredential): Promise<Response> =>\n this.fetchImpl(`${this.baseUrl}/v1/messages`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n [c.headerName]: c.headerValue,\n \"anthropic-version\": this.apiVersion,\n },\n body: JSON.stringify(body),\n signal: req.signal ?? null,\n });\n\n let res: Response;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return; // 取消:静默结束,终态事件由编排层负责\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n\n // 401 有限重试(docs §8.2):仅当请求在途期间凭证已被主动续期轮换\n // (本地已有新 token)时用新 token 重试一次;401 本身不触发换票——\n // 无新 token 说明凭证被吊销或 run 已结束,直接终止当前 run\n if (res.status === 401 && isRefreshable(this.credential)) {\n await res.body?.cancel().catch(() => {}); // 释放连接再重试\n const rotated = this.rotatedRequestCredential(cred);\n if (!rotated) {\n yield {\n type: \"error\",\n error: \"xLyra LLM 调用凭证已被拒绝(token 已吊销或 run 已结束)(HTTP 401)\",\n };\n return;\n }\n cred = rotated;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n }\n\n if (!res.ok || !res.body) {\n yield { type: \"error\", error: await httpErrorSummary(res, credentialSecrets(cred)) };\n return;\n }\n\n // content_block 状态机:index → 当前 block 类别\n const blockKinds = new Map<number, BlockKind>();\n const calls = new ToolCallBuffer();\n const finishedCalls: import(\"../models.js\").ToolCall[] = [];\n let text = \"\";\n let thinking = \"\";\n let thinkingSignature: string | null = null;\n let stopReason: string | null = null;\n const usage = { input: 0, output: 0, cacheRead: 0 };\n let model = \"\";\n let sawTerminal = false;\n\n try {\n for await (const sse of parseSse(res.body)) {\n const evt = safeParse(sse.data);\n if (!evt) continue;\n const type = String(evt.type ?? \"\");\n\n if (type === \"message_start\") {\n const msg = (evt.message as Json) ?? {};\n model = String(msg.model ?? \"\");\n const u = (msg.usage as Json) ?? {};\n usage.input = Number(u.input_tokens ?? 0);\n usage.cacheRead = Number(u.cache_read_input_tokens ?? 0);\n } else if (type === \"content_block_start\") {\n const index = Number(evt.index ?? 0);\n const block = (evt.content_block as Json) ?? {};\n const kind = String(block.type ?? \"\") as BlockKind;\n blockKinds.set(index, kind);\n if (kind === \"tool_use\") {\n const tc = calls.start(String(index), String(block.id ?? \"\"), String(block.name ?? \"\"));\n yield { type: \"toolcall_start\", tool_call: tc };\n }\n } else if (type === \"content_block_delta\") {\n const index = Number(evt.index ?? 0);\n const delta = (evt.delta as Json) ?? {};\n const kind = blockKinds.get(index);\n const deltaType = String(delta.type ?? \"\");\n if (deltaType === \"text_delta\" && kind === \"text\") {\n const d = String(delta.text ?? \"\");\n text += d;\n yield { type: \"text_delta\", delta: d };\n } else if (deltaType === \"thinking_delta\" && kind === \"thinking\") {\n const d = String(delta.thinking ?? \"\");\n thinking += d;\n yield { type: \"thinking_delta\", delta: d };\n } else if (deltaType === \"signature_delta\" && kind === \"thinking\") {\n thinkingSignature = String(delta.signature ?? \"\") || thinkingSignature;\n } else if (deltaType === \"input_json_delta\" && kind === \"tool_use\") {\n const d = String(delta.partial_json ?? \"\");\n const tc = calls.append(String(index), d);\n if (tc) yield { type: \"toolcall_delta\", tool_call: tc, delta: d };\n } else if (deltaType) {\n // delta 类型与 block 类型不符 → 流损坏,不猜\n yield { type: \"error\", error: `流损坏:block ${index}(${kind})收到 ${deltaType}` };\n return;\n }\n } else if (type === \"content_block_stop\") {\n const index = Number(evt.index ?? 0);\n if (blockKinds.get(index) === \"tool_use\") {\n const tc = calls.finish(String(index));\n if (tc) {\n finishedCalls.push(tc);\n yield { type: \"toolcall_end\", tool_call: tc };\n }\n }\n blockKinds.delete(index);\n } else if (type === \"message_delta\") {\n stopReason = String((evt.delta as Json)?.stop_reason ?? \"\") || stopReason;\n usage.output = Number((evt.usage as Json)?.output_tokens ?? usage.output);\n } else if (type === \"message_stop\") {\n sawTerminal = true;\n yield {\n type: \"done\",\n response: {\n content: text,\n thinking: thinking || null,\n thinking_signature: thinkingSignature,\n tool_calls: finishedCalls,\n usage: {\n prompt_tokens: usage.input,\n completion_tokens: usage.output,\n total_tokens: usage.input + usage.output,\n cache_read_tokens: usage.cacheRead,\n },\n finish_reason: stopReason,\n model,\n provider: this.provider,\n },\n };\n return;\n } else if (type === \"error\") {\n const err = (evt.error as Json)?.message;\n yield { type: \"error\", error: `模型调用失败:${String(err ?? \"原因未知\")}` };\n return;\n }\n // ping 等其他事件忽略\n }\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `流读取失败:${errMsg(err)}` };\n return;\n }\n if (!sawTerminal) yield { type: \"error\", error: \"模型流异常终止,未返回结果\" };\n }\n}\n\nfunction safeParse(data: string): Json | null {\n try {\n return JSON.parse(data) as Json;\n } catch {\n return null;\n }\n}\n\nfunction errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","/**\n * OpenAI Responses API 适配器。\n *\n * 按官方文档实现(https://platform.openai.com/docs/api-reference/responses-streaming):\n * - 请求:POST {base_url}/responses,system → instructions,历史 → input items\n * (message / function_call / function_call_output),stream: true;\n * - 流式:tool_call 以 output_item.added(function_call) 确定 id/name,\n * function_call_arguments.delta 逐片累积、.done 给全量;\n * response.completed / failed / incomplete 为终态。\n *\n * 终态怪癖处理(继承 MovieClaw 兼容层经验):\n * - response.incomplete:已累积出完整 tool_calls 时按 done 处理(让循环继续),\n * 否则报 error;\n * - 流中途断开(无终态事件)→ error,不静默。\n */\nimport { LlmError } from \"../errors.js\";\nimport { httpErrorSummary, credentialSecrets } from \"../http-error.js\";\nimport {\n isRefreshable,\n StaticCredentialProvider,\n type CredentialProvider,\n type ResolvedCredential,\n} from \"../credential.js\";\nimport { normalizeEffort, type ChatMessage, type ChatResponse, type ToolDefinition } from \"../models.js\";\nimport { emptyUsage } from \"../models.js\";\nimport type { ChatRequest, LlmProtocol, StreamEvent } from \"../protocol.js\";\nimport type { AgentRunContext } from \"../router.js\";\nimport { parseSse } from \"../sse.js\";\nimport { ToolCallBuffer } from \"../stream-assembler.js\";\n\nexport interface ResponsesEndpointOptions {\n baseUrl: string;\n /**\n * 统一凭证来源(推荐)。apiKey 是 direct 模式的简写,\n * 等价于 Authorization: Bearer <apiKey> 的静态凭证。\n */\n credential?: CredentialProvider;\n apiKey?: string;\n /** 展示与日志用的端点名 */\n providerName?: string;\n /** 测试注入用;默认全局 fetch */\n fetchImpl?: typeof fetch;\n}\n\ntype Json = Record<string, unknown>;\n\n/** 内部消息 → Responses input items(一条内部消息可能展开成多个 item) */\nexport function toResponsesInput(messages: ChatMessage[]): {\n instructions: string | undefined;\n input: Json[];\n} {\n const instructions: string[] = [];\n const input: Json[] = [];\n for (const m of messages) {\n if (m.role === \"system\") {\n if (m.content) instructions.push(m.content);\n continue;\n }\n if (m.role === \"user\") {\n input.push({ type: \"message\", role: \"user\", content: [{ type: \"input_text\", text: m.content }] });\n continue;\n }\n if (m.role === \"assistant\") {\n if (m.content) {\n input.push({ type: \"message\", role: \"assistant\", content: [{ type: \"output_text\", text: m.content }] });\n }\n for (const tc of m.tool_calls ?? []) {\n input.push({ type: \"function_call\", call_id: tc.id, name: tc.name, arguments: tc.raw_arguments });\n }\n continue;\n }\n // tool 结果 → function_call_output\n input.push({ type: \"function_call_output\", call_id: m.tool_call_id ?? \"\", output: m.content });\n }\n return { instructions: instructions.length ? instructions.join(\"\\n\\n\") : undefined, input };\n}\n\nfunction toResponsesTools(tools: ToolDefinition[]): Json[] {\n return tools.map((t) => ({\n type: \"function\",\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n }));\n}\n\n/** 从 response.completed 的完整响应体提取定稿 ChatResponse */\nfunction responseFromCompleted(response: Json, provider: string): ChatResponse {\n let content = \"\";\n let thinking = \"\";\n const toolCalls: ChatResponse[\"tool_calls\"] = [];\n for (const item of (response.output as Json[] | undefined) ?? []) {\n if (item.type === \"message\") {\n for (const part of (item.content as Json[] | undefined) ?? []) {\n if (part.type === \"output_text\" && typeof part.text === \"string\") content += part.text;\n }\n } else if (item.type === \"reasoning\") {\n for (const part of (item.summary as Json[] | undefined) ?? []) {\n if (part.type === \"summary_text\" && typeof part.text === \"string\") {\n thinking += (thinking ? \"\\n\" : \"\") + part.text;\n }\n }\n } else if (item.type === \"function_call\") {\n toolCalls.push({\n id: String(item.call_id ?? item.id ?? \"\"),\n name: String(item.name ?? \"\"),\n raw_arguments: String(item.arguments ?? \"\"),\n });\n }\n }\n const usage = (response.usage as Json | undefined) ?? {};\n const cached = (usage.input_tokens_details as Json | undefined)?.cached_tokens;\n return {\n content,\n thinking: thinking || null,\n thinking_signature: null, // Responses 的思考摘要无签名概念\n tool_calls: toolCalls,\n usage: {\n prompt_tokens: Number(usage.input_tokens ?? 0),\n completion_tokens: Number(usage.output_tokens ?? 0),\n total_tokens: Number(usage.total_tokens ?? 0),\n cache_read_tokens: Number(cached ?? 0),\n },\n finish_reason: (response.status as string | undefined) ?? \"completed\",\n model: String(response.model ?? \"\"),\n provider,\n };\n}\n\nexport class OpenAIResponsesProtocol implements LlmProtocol {\n readonly name = \"openai-responses\";\n private readonly baseUrl: string;\n private readonly credential: CredentialProvider;\n private readonly provider: string;\n private readonly fetchImpl: typeof fetch;\n private runContext: AgentRunContext | null = null;\n\n constructor(opts: ResponsesEndpointOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n if (opts.credential) {\n this.credential = opts.credential;\n } else if (opts.apiKey) {\n this.credential = new StaticCredentialProvider({\n kind: \"api-key\",\n headerName: \"authorization\",\n headerValue: `Bearer ${opts.apiKey}`,\n });\n } else {\n throw new LlmError(\"OpenAIResponsesProtocol 缺少凭证(credential 或 apiKey)\");\n }\n this.provider = opts.providerName ?? \"openai\";\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n /** 更新 run 上下文:仅 xlyra-callback 凭证消费;静态凭证为 no-op */\n setRunContext(context: AgentRunContext): void {\n this.runContext = context;\n if (isRefreshable(this.credential)) this.credential.setRunContext(context);\n }\n\n /**\n * 请求开始时解析本次 run 的凭证:xlyra-callback 按 runId 定向取\n * (并发 run 各自独立),静态凭证直接返回。\n */\n private resolveRequestCredential(): Promise<ResolvedCredential> {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.getCredentialFor(this.runContext.runId);\n }\n return this.credential.getCredential();\n }\n\n /** 401 后仅当本地凭证已被主动续期轮换时返回新 token;401 本身不触发换票 */\n private rotatedRequestCredential(used: ResolvedCredential): ResolvedCredential | null {\n if (isRefreshable(this.credential) && this.runContext) {\n return this.credential.rotatedCredentialFor(this.runContext.runId, used);\n }\n return null;\n }\n\n async *chatStream(req: ChatRequest): AsyncIterable<StreamEvent> {\n const { instructions, input } = toResponsesInput(req.messages);\n const body: Json = { model: req.model, input, stream: true };\n if (instructions) body.instructions = instructions;\n if (req.tools?.length) body.tools = toResponsesTools(req.tools);\n if (req.settings.max_tokens) body.max_output_tokens = req.settings.max_tokens;\n if (req.settings.temperature !== undefined) body.temperature = req.settings.temperature;\n if (req.settings.reasoning_effort) {\n body.reasoning = { effort: normalizeEffort(req.settings.reasoning_effort), summary: \"auto\" };\n body.include = [\"reasoning.encrypted_content\"];\n }\n\n let cred;\n try {\n cred = await this.resolveRequestCredential();\n } catch (err) {\n // 凭证获取失败(如 callback 未签发):原文上抛语义,不归类为网络错误\n yield { type: \"error\", error: errMsg(err) };\n return;\n }\n\n const doFetch = (c: ResolvedCredential): Promise<Response> =>\n this.fetchImpl(`${this.baseUrl}/responses`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n [c.headerName]: c.headerValue,\n },\n body: JSON.stringify(body),\n signal: req.signal ?? null,\n });\n\n let res: Response;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return; // 取消:静默结束,终态事件由编排层负责\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n\n // 401 有限重试(docs §8.2):仅当请求在途期间凭证已被主动续期轮换\n // (本地已有新 token)时用新 token 重试一次;401 本身不触发换票——\n // 无新 token 说明凭证被吊销或 run 已结束,直接终止当前 run\n if (res.status === 401 && isRefreshable(this.credential)) {\n await res.body?.cancel().catch(() => {}); // 释放连接再重试\n const rotated = this.rotatedRequestCredential(cred);\n if (!rotated) {\n yield {\n type: \"error\",\n error: \"xLyra LLM 调用凭证已被拒绝(token 已吊销或 run 已结束)(HTTP 401)\",\n };\n return;\n }\n cred = rotated;\n try {\n res = await doFetch(cred);\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `请求失败(网络错误):${errMsg(err)}` };\n return;\n }\n }\n\n if (!res.ok || !res.body) {\n yield { type: \"error\", error: await httpErrorSummary(res, credentialSecrets(cred)) };\n return;\n }\n\n const calls = new ToolCallBuffer();\n // item_id → call_id:delta 事件只带 item_id,事件里的 ToolCall.id 用 call_id\n // (function_call_output 回喂以 call_id 关联)\n const callIdByItem = new Map<string, string>();\n let streamedText = \"\";\n let streamedThinking = \"\";\n let doneCalls: ChatResponse[\"tool_calls\"] = [];\n\n try {\n for await (const sse of parseSse(res.body)) {\n if (sse.data === \"[DONE]\") break;\n const evt = safeParse(sse.data);\n if (!evt) continue;\n const type = String(evt.type ?? \"\");\n\n if (type === \"response.output_item.added\") {\n const item = evt.item as Json | undefined;\n if (item?.type === \"function_call\") {\n const itemId = String(item.id ?? \"\");\n const callId = String(item.call_id ?? itemId);\n callIdByItem.set(itemId, callId);\n const tc = calls.start(itemId, callId, String(item.name ?? \"\"));\n yield { type: \"toolcall_start\", tool_call: tc };\n }\n } else if (type === \"response.function_call_arguments.delta\") {\n const itemId = String(evt.item_id ?? \"\");\n const tc = calls.append(itemId, String(evt.delta ?? \"\"));\n if (tc) yield { type: \"toolcall_delta\", tool_call: tc, delta: String(evt.delta ?? \"\") };\n } else if (type === \"response.function_call_arguments.done\") {\n const itemId = String(evt.item_id ?? \"\");\n const tc = calls.finish(itemId, String(evt.arguments ?? \"\"));\n if (tc) {\n doneCalls.push(tc);\n yield { type: \"toolcall_end\", tool_call: tc };\n }\n } else if (type === \"response.output_item.done\") {\n // 兜底:arguments.done 缺失时,function_call item 完结也带全量 arguments\n const item = evt.item as Json | undefined;\n const itemId = String(item?.id ?? \"\");\n if (item?.type === \"function_call\" && itemId && callIdByItem.has(itemId)) {\n const tc = calls.finish(itemId, String(item.arguments ?? \"\"));\n if (tc) {\n doneCalls.push(tc);\n yield { type: \"toolcall_end\", tool_call: tc };\n }\n }\n } else if (type === \"response.output_text.delta\") {\n const delta = String(evt.delta ?? \"\");\n streamedText += delta;\n yield { type: \"text_delta\", delta };\n } else if (type === \"response.reasoning_summary_text.delta\") {\n const delta = String(evt.delta ?? \"\");\n streamedThinking += delta;\n yield { type: \"thinking_delta\", delta };\n } else if (type === \"response.completed\") {\n const response = responseFromCompleted((evt.response as Json) ?? {}, this.provider);\n // 部分网关(含 xLyra 代理链)的 completed 事件只带元数据不带完整 output:\n // 正文/思考/工具调用回落到流式累积值,否则定稿消息会空 content 落盘\n yield {\n type: \"done\",\n response: {\n ...response,\n content: response.content || streamedText,\n thinking: response.thinking ?? (streamedThinking || null),\n tool_calls: response.tool_calls.length > 0 ? response.tool_calls : doneCalls,\n },\n };\n return;\n } else if (type === \"response.incomplete\") {\n // 已累积出完整 tool_calls → 按 done 处理让循环继续;否则报错\n if (doneCalls.length > 0) {\n const response = responseFromCompleted((evt.response as Json) ?? {}, this.provider);\n yield {\n type: \"done\",\n response: {\n ...response,\n content: response.content || streamedText,\n thinking: response.thinking ?? (streamedThinking || null),\n tool_calls: doneCalls,\n },\n };\n } else {\n const detail = ((evt.response as Json)?.incomplete_details as Json)?.reason;\n yield { type: \"error\", error: `响应不完整${detail ? `(${String(detail)})` : \"\"},请重试` };\n }\n return;\n } else if (type === \"response.failed\") {\n const err = ((evt.response as Json)?.error as Json)?.message;\n yield { type: \"error\", error: `模型调用失败:${String(err ?? \"原因未知\")}` };\n return;\n } else if (type === \"error\") {\n yield { type: \"error\", error: `模型调用失败:${String(evt.message ?? \"原因未知\")}` };\n return;\n }\n // 其余事件(created / in_progress / output_text.done / ping 等)忽略\n }\n } catch (err) {\n if (req.signal?.aborted) return;\n yield { type: \"error\", error: `流读取失败:${errMsg(err)}` };\n return;\n }\n // 流结束但没有任何终态事件——视为异常断流\n yield { type: \"error\", error: \"模型流异常终止,未返回结果\" };\n }\n}\n\nfunction safeParse(data: string): Json | null {\n try {\n return JSON.parse(data) as Json;\n } catch {\n return null;\n }\n}\n\nfunction errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nexport { LlmError };\n","/**\n * 端点配置与模型解析 —— 刻意简化的路由层(不做多供应商目录体系)。\n *\n * 模型引用写法:\n * - \"端点名/模型id\":显式指定端点(如 \"anthropic/claude-sonnet-4-5\");\n * - 裸 \"模型id\":在全部端点中查找,唯一命中即用,多命中报错;\n * - 空串:第一个端点的 default_model。\n *\n * context_window 优先取端点配置;未配置时回落内置常识表;都未命中返回\n * undefined——自动压缩随之停用(宁放行到供应商报错,不瞎猜预算)。\n */\nimport { LlmError } from \"./errors.js\";\nimport { resolveCredentialProvider } from \"./credential.js\";\nimport type { LlmProtocol } from \"./protocol.js\";\nimport { AnthropicMessagesProtocol } from \"./protocols/messages.js\";\nimport { OpenAIResponsesProtocol } from \"./protocols/responses.js\";\n\n/**\n * 端点凭证模式:\n * - direct:原有 base_url + api_key 直连 provider;\n * - remote-xlyra:调用 xLyra 内部 LLM 网关,使用临时凭证。\n * 配置输入可省略 mode,schema 解析后自动补为 \"direct\"(见 server/config.ts)。\n */\nexport type EndpointMode = \"direct\" | \"remote-xlyra\";\n\n/** 固定临时 token(Bearer) */\nexport interface TemporaryBearerCredential {\n type: \"temporary-bearer\";\n token: string;\n}\n\n/** xLyra credential callback:按需签发/轮换短期 token(见 docs 第 8、9 章) */\nexport interface XlyraCallbackCredential {\n type: \"xlyra-callback\";\n url: string;\n}\n\nexport type EndpointCredential = TemporaryBearerCredential | XlyraCallbackCredential;\n\nexport interface EndpointConfig {\n name: string;\n protocol: \"openai-responses\" | \"anthropic-messages\";\n mode: EndpointMode;\n base_url: string;\n api_key?: string;\n credential?: EndpointCredential;\n /** 可用模型表:key 为模型 id;context_window 可选 */\n models?: Record<string, { context_window?: number }>;\n default_model?: string;\n}\n\n/**\n * 一次 Agent run 的标识上下文:credential callback 所需。\n * sessionId/runId 由 agent 自身生成(事实源在 agent),agentInstanceId 由\n * 部署方/runner 在启动 run 时注入;只携带标识 ID,不携带会话内容。\n */\nexport interface AgentRunContext {\n agentInstanceId: string;\n sessionId: string;\n runId: string;\n model?: string;\n}\n\nexport interface ResolvedModel {\n endpoint: EndpointConfig;\n protocol: LlmProtocol;\n /** 端点内的模型 id(已剥离端点前缀) */\n modelId: string;\n contextWindow: number | undefined;\n}\n\n/** 内置 context window 常识表(前缀匹配,先到先得;保守取值,可被配置覆盖) */\nconst BUILTIN_CONTEXT_WINDOWS: Array<[prefix: string, window: number]> = [\n [\"claude-\", 200_000],\n [\"gpt-4o\", 128_000],\n [\"gpt-4.1\", 1_047_576],\n [\"gpt-5\", 400_000],\n [\"o1\", 200_000],\n [\"o3\", 200_000],\n [\"o4\", 200_000],\n];\n\nexport function builtinContextWindow(modelId: string): number | undefined {\n for (const [prefix, win] of BUILTIN_CONTEXT_WINDOWS) {\n if (modelId.startsWith(prefix)) return win;\n }\n return undefined;\n}\n\nexport class EndpointResolver {\n private readonly endpoints: EndpointConfig[];\n private readonly protocols = new Map<string, LlmProtocol>();\n\n constructor(endpoints: EndpointConfig[]) {\n if (endpoints.length === 0) throw new LlmError(\"未配置任何模型端点\");\n this.endpoints = endpoints;\n }\n\n resolve(model: string): ResolvedModel {\n let endpoint: EndpointConfig | undefined;\n let modelId: string;\n\n if (!model) {\n // 构造函数已保证 endpoints 非空\n endpoint = this.endpoints[0]!;\n modelId = endpoint.default_model ?? \"\";\n if (!modelId) throw new LlmError(`端点 ${endpoint.name} 未配置默认模型`);\n } else if (model.includes(\"/\")) {\n const [name, ...rest] = model.split(\"/\");\n endpoint = this.endpoints.find((e) => e.name === name);\n if (endpoint) {\n modelId = rest.join(\"/\");\n } else {\n modelId = model;\n const hits = this.endpoints.filter((e) => e.models && model in e.models);\n if (hits.length > 1) {\n throw new LlmError(`模型 ${model} 在多个端点中均有配置,请用「端点名/模型id」显式指定`);\n }\n endpoint = hits[0] ?? this.endpoints[0]!;\n }\n } else {\n modelId = model;\n const hits = this.endpoints.filter((e) => e.models && model in e.models);\n if (hits.length > 1) {\n throw new LlmError(`模型 ${model} 在多个端点中均有配置,请用「端点名/模型id」显式指定`);\n }\n // 裸模型 id 且无端点声明:回落到第一个端点(兼容官方端点的自由模型名)\n endpoint = hits[0] ?? this.endpoints[0]!;\n }\n\n return {\n endpoint,\n protocol: this.protocolFor(endpoint),\n modelId,\n contextWindow: endpoint.models?.[modelId]?.context_window ?? builtinContextWindow(modelId),\n };\n }\n\n private protocolFor(endpoint: EndpointConfig): LlmProtocol {\n let protocol = this.protocols.get(endpoint.name);\n if (!protocol) {\n const opts = {\n baseUrl: endpoint.base_url,\n credential: resolveCredentialProvider(endpoint),\n providerName: endpoint.name,\n };\n protocol =\n endpoint.protocol === \"anthropic-messages\"\n ? new AnthropicMessagesProtocol(opts)\n : new OpenAIResponsesProtocol(opts);\n this.protocols.set(endpoint.name, protocol);\n }\n return protocol;\n }\n}\n","/**\n * 工具参数校验 —— 调用前对 raw_arguments 做 JSON Schema 校验。\n *\n * 覆盖我们工具声明用到的 JSON Schema 子集(object / properties / required /\n * string / number / integer / boolean / array / enum / default),不引 ajv:\n * 我们的 schema 全部来自自家工具的 Zod 定义,结构可控。将来支持外部工具\n * 声明时,可在此替换为完整 JSON Schema 校验器,接口不变。\n *\n * 校验失败返回中文错误文本(喂回模型自行修正),不抛异常。\n */\nimport type { ToolDefinition } from \"./models.js\";\nimport type { ToolCall } from \"./models.js\";\n\nexport interface ValidatedArgs {\n args: Record<string, unknown> | null;\n error: string | null;\n}\n\nexport function validateToolCall(\n definitions: ToolDefinition[],\n call: ToolCall,\n): ValidatedArgs {\n const def = definitions.find((d) => d.name === call.name);\n if (!def) {\n return { args: null, error: `工具不存在:${call.name};可用工具:${definitions.map((d) => d.name).join(\"、\")}` };\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(call.raw_arguments || \"{}\");\n } catch {\n return {\n args: null,\n error: `工具 ${call.name} 的参数不是合法 JSON,请修正后重试。原文:${call.raw_arguments.slice(0, 200)}`,\n };\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { args: null, error: `工具 ${call.name} 的参数必须是 JSON object` };\n }\n const err = validateAgainstSchema(parsed as Record<string, unknown>, def.parameters);\n if (err) return { args: null, error: `工具 ${call.name} 参数校验失败:${err}` };\n return { args: parsed as Record<string, unknown>, error: null };\n}\n\nfunction validateAgainstSchema(\n args: Record<string, unknown>,\n schema: Record<string, unknown>,\n): string | null {\n // required 语义修正:Zod 的 .default() 字段会被 z.toJSONSchema 同时列入\n // required 与 properties[x].default——带默认值的参数模型省略是合法的,\n // 官方 API 也不要求它出现。这里以「required 且无 default」为真正必填。\n const properties = (schema.properties as Record<string, Record<string, unknown>> | undefined) ?? {};\n const required = ((schema.required as string[] | undefined) ?? []).filter(\n (key) => properties[key]?.default === undefined,\n );\n for (const key of required) {\n if (!(key in args) || args[key] === undefined || args[key] === null) {\n return `缺少必填参数 ${key}`;\n }\n }\n for (const [key, value] of Object.entries(args)) {\n const prop = properties[key];\n if (!prop) continue; // additionalProperties 放行\n const expected = prop.type as string | undefined;\n if (value === undefined || !expected) continue;\n const ok =\n (expected === \"string\" && typeof value === \"string\") ||\n (expected === \"number\" && typeof value === \"number\") ||\n (expected === \"integer\" && typeof value === \"number\" && Number.isInteger(value)) ||\n (expected === \"boolean\" && typeof value === \"boolean\") ||\n (expected === \"array\" && Array.isArray(value)) ||\n (expected === \"object\" && typeof value === \"object\" && !Array.isArray(value));\n if (!ok) return `参数 ${key} 类型应为 ${expected}`;\n const enumValues = prop.enum as unknown[] | undefined;\n if (enumValues && !enumValues.includes(value)) {\n return `参数 ${key} 取值须为 ${enumValues.join(\" / \")}`;\n }\n }\n return null;\n}\n","/**\n * Agent 执行过程的事件协议 —— 前后端之间的「执行进度语言」。\n *\n * 设计原则(移植自 MovieClaw,对齐 pi 的 agent 事件思路):\n * 1. 事件类型面向「渲染语义」而非模型协议:调用方拿到事件就知道往哪个区域\n * 画什么,不需要理解底层 LLM 流的细节;\n * 2. 增量事件(*_delta)负责打字机效果,结束事件(agent_done)带完整结果,\n * 断线重连/中途加入也能靠终态恢复;\n * 3. 工具调用三段式:名称确定即发 tool_call_start,参数逐片发 tool_call_delta,\n * 参数完整后发 tool_call——调用方从名称确定的一刻起就能展示进度。\n *\n * 事件序列(每一步 = 一次模型调用):\n * agent_start → [ (thinking_delta|text_delta)*\n * → (tool_call_start → tool_call_delta* → tool_call)*\n * → tool_result* ]×N\n * → agent_done | agent_error | agent_cancelled\n * (任意安全点可插 context_compacted)\n */\nimport { z } from \"zod\";\nimport {\n chatMessageSchema,\n modelSettingsSchema,\n tokenUsageSchema,\n toolCallSchema,\n} from \"../llm/models.js\";\n\nexport const agentStartParamsSchema = z.object({\n /** 用户的任务描述(作为本轮 user 消息) */\n input: z.string(),\n /** 是否把 input 追加为新的 user 消息;提权续跑沿用 history 中的原始输入 */\n include_input: z.boolean().default(true),\n /** 多轮历史(可选):追加在 system 之后、本轮 input 之前 */\n history: z.array(chatMessageSchema).default([]),\n /** 模型引用(\"端点名/模型id\" 或裸模型 id);空串 = 第一个端点的默认模型 */\n model: z.string().default(\"\"),\n /** 覆盖默认系统提示词(缺省用 prompts.buildSystemPrompt()) */\n system_prompt: z.string().nullish(),\n settings: modelSettingsSchema.default({}),\n});\nexport type AgentStartParams = z.input<typeof agentStartParamsSchema>;\n\nexport const agentToolResultSchema = z.object({\n tool_call_id: z.string(),\n name: z.string(),\n /** 喂回模型的文本(事件里截断到 2000 字符,完整版进对话上下文) */\n output: z.string(),\n is_error: z.boolean().default(false),\n elapsed_ms: z.number().default(0),\n});\nexport type AgentToolResult = z.infer<typeof agentToolResultSchema>;\n\nexport const agentCompactionSchema = z.object({\n summary: z.string(),\n tokens_before: z.number(),\n tokens_after: z.number(),\n});\nexport type AgentCompaction = z.infer<typeof agentCompactionSchema>;\n\n/** 提权请求(escalation_request 事件载荷):工具访问越界路径时发起,\n * 前端展示并等待用户确认;确认后服务端登记授权并重发消息续跑 */\nexport const agentEscalationSchema = z.object({\n /** 本次提权请求的唯一 id(确认接口的定位参数) */\n escalation_id: z.string(),\n /** 用户/模型给出的原始路径(展示用) */\n requested_path: z.string(),\n /** 沙箱解析后的绝对路径(确认后登记的授权键) */\n resolved_path: z.string(),\n /** 触发提权的工具名(如 list/read) */\n tool_name: z.string(),\n resource_type: z.enum([\"path\", \"command\"]).default(\"path\"),\n requested_command: z.array(z.string()).nullish(),\n /** 当前工作区根(展示给用户看边界在哪) */\n workdir: z.string(),\n});\nexport type AgentEscalation = z.infer<typeof agentEscalationSchema>;\n\nexport const agentDoneSchema = z.object({\n /** 最后一步的产出(loop 的最终答复) */\n text: z.string().nullish(),\n thinking: z.string().nullish(),\n finish_reason: z.string().nullish(),\n /** 全部步骤的累计用量 */\n usage: tokenUsageSchema.default({ prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, cache_read_tokens: 0 }),\n /** 模型调用次数 */\n steps: z.number().default(1),\n model: z.string().default(\"\"),\n provider: z.string().default(\"\"),\n elapsed_ms: z.number().default(0),\n});\nexport type AgentDone = z.infer<typeof agentDoneSchema>;\n\n/** Agent 事件:type 决定哪些字段有值;作为 SSE 载荷时 type 同时用作 SSE 的 event 名 */\nexport const agentEventSchema = z.object({\n type: z.enum([\n \"agent_start\",\n \"thinking_delta\",\n \"text_delta\",\n \"tool_call_start\",\n \"tool_call_delta\",\n \"tool_call\",\n \"tool_result\",\n \"context_compacted\",\n \"escalation_request\",\n \"agent_done\",\n \"agent_error\",\n \"agent_cancelled\",\n ]),\n /** 本次运行的唯一 id,一次 start 产生的所有事件共享同一个值 */\n run_id: z.string(),\n delta: z.string().nullish(),\n tool_call: toolCallSchema.nullish(),\n tool_call_id: z.string().nullish(),\n tool_result: agentToolResultSchema.nullish(),\n compaction: agentCompactionSchema.nullish(),\n /** escalation_request 事件:路径提权请求 */\n escalation: agentEscalationSchema.nullish(),\n /** agent_start:实际路由到的端点名与模型 id */\n provider: z.string().nullish(),\n model: z.string().nullish(),\n /** agent_done 的终态载荷 */\n result: agentDoneSchema.nullish(),\n /** agent_error 的中文错误说明 */\n error: z.string().nullish(),\n /** agent_cancelled 的取消原因:escalation 表示提权协商暂停(等待用户确认),\n * 空/其它值表示用户主动停止或异常中断 */\n reason: z.string().nullish(),\n});\nexport type AgentEvent = z.infer<typeof agentEventSchema>;\n\nexport type AgentEventType = AgentEvent[\"type\"];\n\nexport const TERMINAL_EVENT_TYPES: ReadonlySet<AgentEventType> = new Set([\n \"agent_done\",\n \"agent_error\",\n \"agent_cancelled\",\n]);\n","/**\n * Agent 系统提示词。\n *\n * 设计原则(移植自 MovieClaw,对齐 Claude Code 的提示词架构):\n * - 正文只写通用行为准则(运行方式 / 并行调用 / 工作循环 / 回复风格),\n * 不含任何领域词汇——领域语义由各工具的 description 和运行时环境段承载;\n * - 环境事实(日期等)随时会变,由 buildSystemPrompt 在每次运行时拼接,\n * 绝不写死在正文里。\n */\n\n/** 压缩摘要消息的固定前缀——重建历史时靠它识别「这条 user 消息是压缩摘要」,\n * 再次压缩时旧摘要不会被当成用户原话保留(codex SUMMARY_PREFIX 同款机制) */\nexport const SUMMARY_PREFIX = \"【上下文压缩摘要】此前的对话已被压缩,以下是交接摘要:\";\n\n/** 交接摘要指令(codex SUMMARIZATION_PROMPT 的中文对齐版)。作为一条普通\n * user 消息追加到全量历史末尾发起压缩请求,不是系统提示词。 */\nexport const COMPACT_PROMPT = `\\\n你正在执行一次上下文压缩。请为将要接手这段对话的另一个 LLM 写一份交接摘要。\n\n摘要必须包含:\n- 任务目标与当前进度、已做出的关键决定\n- 用户提出的约束、偏好和重要背景\n- 尚未完成的事项(明确的下一步)\n- 继续工作必须保留的关键数据(路径、ID、编号、查询结果要点等)\n\n保持简洁、结构化,以帮助下一个 LLM 无缝接续工作为唯一目标。只输出摘要正文。\n`;\n\nconst SYSTEM_PROMPT_TEMPLATE = `\\\n你是 {agentName},一个友好的智能助理。{persona}\n\n# 运行方式\n- 你的文字输出以 Markdown 渲染在会话页,工具调用过程用户全程可见。执行中不要旁白「我现在要去做什么」——工具调用本身就是过程展示。\n- 需要事实时永远先调用工具查证,一律以工具返回为准,绝不凭印象臆断。\n- 文件与工作状态都具有时效性;每次用户询问此类信息时,必须在当前轮次重新调用工具查询最新数据,不要相信或复用历史对话中已经获取的结果。\n- 工具报错或被拒绝,不要原样重发:读懂原因,修正参数或换一条路。\n\n# 工具使用规则\n- 工具列表会随当前会话配置动态注入;只能调用列表中实际存在的工具,不要臆造工具名或参数。\n- 先用 search 定位代码或文本,再用 read 查看必要上下文;不要为寻找内容递归读取大量文件。\n- 修改已有文件优先使用 edit;需要同时修改多个文件时使用 apply_patch;只有明确需要整体替换时才使用 write。\n- 修改后如果当前会话提供 exec_command,应运行最相关的格式化、类型检查或测试,并根据结果继续修正。\n- exec_command 使用 argv 数组而不是 shell 字符串;命令会话返回 session_id 时,用 write_stdin 继续读取,不要重复启动同一个命令。\n- exec_command 与 write_stdin 即使需要授权也会出现在工具目录中;调用后若收到提权请求,应等待用户确认,不要声称当前没有命令工具。\n- 任何工具被拒绝、越界或取消时,先理解返回原因;不要通过换写法绕过权限边界。\n\n# 并行工具调用\n需要多项互不依赖的信息时,在同一轮里一次性发起全部调用,而不是一轮一个。独立的检索、查询、状态读取都应合并到同一次回复中——运行时会安全并发执行连续的只读调用并按原顺序返回结果,合并调用避免了每多一轮就把整个对话重新发送一遍的开销。\n只有当后一个调用确实依赖前一个的结果时才分轮串行。拿不准且调用之间相互独立时,一律合并。\n\n# 工作循环\n以「思考 → 行动 → 观察」持续循环,直到任务完成:\n- 每次观察结果后重新评估:推进了就走下一步;没推进就换一种方式再试,而不是原样重试。\n- 坚持到底,不把做了一半的任务交回用户。同一障碍连续两次绕不过去,才停下向用户说明卡点。\n- 允许停下提问的只有两种情况:缺少只有用户能做的决定,或动作超出了本次的明确授权。\n\n# 回复风格\n- 全程中文。最终答复先结论、后关键依据,不复述执行过程。\n- 找不到就说找不到,绝不虚构任何数据。\n- 简短优先:一句能说清的不用三句。\n- 友好、有温度:像一个长期陪伴用户的真人伙伴那样交流,在恰当的时候给用户情绪价值。可以适度使用表情符号,但别泛滥。\n`;\n\nexport interface SystemPromptOptions {\n /** 助理名称,默认 \"xlyra 助理\" */\n agentName?: string;\n /** 一句话人设(拼在首段),默认空 */\n persona?: string;\n /** 运行时环境段(每行一个事实,拼在「# 环境」下) */\n extraEnvironment?: string;\n /** 当前会话实际暴露给模型的工具;由 Runner 动态注入,避免静态提示漂移。 */\n availableTools?: Array<Pick<import(\"../llm/models.js\").ToolDefinition, \"name\" | \"description\">>;\n contextFragments?: string[];\n}\n\nexport function buildAvailableToolsPrompt(\n availableTools: Array<Pick<import(\"../llm/models.js\").ToolDefinition, \"name\" | \"description\">>,\n): string {\n if (availableTools.length === 0) {\n return \"# 当前会话可用工具\\n- 当前会话没有可用工具;不要尝试调用工具。\";\n }\n return [\n \"# 当前会话可用工具\",\n ...availableTools.map((tool) => `- ${tool.name}:${tool.description.replace(/\\s+/g, \" \").trim()}`),\n ].join(\"\\n\");\n}\n\nexport function buildSystemPrompt(opts: SystemPromptOptions = {}): string {\n const body = SYSTEM_PROMPT_TEMPLATE.replace(\"{agentName}\", opts.agentName ?? \"xlyra 助理\").replace(\n \"{persona}\",\n opts.persona ? ` ${opts.persona}` : \"\",\n );\n const lines = [body, \"# 环境\", `- 当前日期:${new Date().toISOString().slice(0, 10)}`];\n if (opts.extraEnvironment) lines.push(opts.extraEnvironment);\n for (const fragment of opts.contextFragments ?? []) {\n if (fragment.trim()) lines.push(fragment);\n }\n lines.push(buildAvailableToolsPrompt(opts.availableTools ?? []));\n return lines.join(\"\\n\");\n}\n","/**\n * 可在上下文压缩后保留的耐久上下文块。\n *\n * 工具可通过 ToolHandlerResult.metadata.retainedContext 声明;同时建议在\n * content 中写入 START/END 标记,以便跨 run 重建历史时仅凭消息正文识别\n * (JSONL 不持久化 metadata)。\n */\nimport type { ChatMessage } from \"../llm/models.js\";\n\nexport const RETAINED_CONTEXT_START = \"【保留上下文开始】\";\nexport const RETAINED_CONTEXT_END = \"【保留上下文结束】\";\n/** 压缩后重新注入的耐久上下文总预算,独立于用户原话预算。 */\nexport const RETAINED_CONTEXT_TOKEN_BUDGET = 20_000;\n\nconst SKILL_CONTEXT_KEY = /^skill:([a-z0-9]+(?:-[a-z0-9]+)*)$/;\n\nexport interface RetainedContextBlock {\n /** 去重键,例如 skill:code-review */\n key: string;\n /** 压缩后重新注入的完整文本(通常已含标记) */\n content: string;\n}\n\nexport function isRetainedContextBlock(value: unknown): value is RetainedContextBlock {\n if (!value || typeof value !== \"object\") return false;\n const block = value as Record<string, unknown>;\n return typeof block.key === \"string\" && block.key.length > 0\n && typeof block.content === \"string\" && block.content.length > 0;\n}\n\nfunction isSkillRetainedContextBlock(block: RetainedContextBlock): boolean {\n if (!SKILL_CONTEXT_KEY.test(block.key)) return false;\n const skillName = block.key.slice(\"skill:\".length);\n return block.content.includes(`<skill_content name=\"${skillName}\">`)\n && block.content.includes(\"</skill_content>\");\n}\n\nexport function extractRetainedContextFromMetadata(\n metadata: Record<string, unknown> | undefined,\n): RetainedContextBlock | null {\n if (!metadata) return null;\n return isRetainedContextBlock(metadata.retainedContext) ? metadata.retainedContext : null;\n}\n\n/**\n * 从已持久化消息正文中提取 load_skill 生成的保留块。\n * 只接受 skill:<name> + 完整 skill_content 结构,普通用户文本不能凭前缀被永久保留。\n */\nexport function extractRetainedContextsFromMessages(\n messages: ChatMessage[],\n): RetainedContextBlock[] {\n const found = new Map<string, RetainedContextBlock>();\n const pattern = new RegExp(\n `${escapeRegExp(RETAINED_CONTEXT_START)}\\\\s+(skill:[a-z0-9]+(?:-[a-z0-9]+)*)\\\\r?\\\\n([\\\\s\\\\S]*?)\\\\r?\\\\n${escapeRegExp(RETAINED_CONTEXT_END)}`,\n \"g\",\n );\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i]!;\n // retained 块在持久化里是 tool 结果(load_skill 回执),压缩重建时作为\n // system 注入(见 retainedContextsAsMessages),两种角色都要识别\n if (message.role !== \"tool\" && message.role !== \"user\" && message.role !== \"system\") continue;\n for (const match of (message.content ?? \"\").matchAll(pattern)) {\n const key = match[1]!;\n const body = match[0]!;\n const block = { key, content: body };\n if (!found.has(key) && isRetainedContextBlock(block) && isSkillRetainedContextBlock(block)) {\n found.set(key, block);\n }\n }\n }\n return [...found.values()].reverse();\n}\n\nexport function mergeRetainedContexts(\n ...groups: Array<Iterable<RetainedContextBlock>>\n): RetainedContextBlock[] {\n const map = new Map<string, RetainedContextBlock>();\n for (const group of groups) {\n for (const block of group) {\n if (\n isRetainedContextBlock(block)\n && (!block.key.startsWith(\"skill:\") || isSkillRetainedContextBlock(block))\n && !map.has(block.key)\n ) {\n map.set(block.key, block);\n }\n }\n }\n return [...map.values()];\n}\n\nfunction approximateTokens(block: RetainedContextBlock): number {\n return Math.max(1, Math.ceil(Buffer.byteLength(block.content, \"utf-8\") / 4));\n}\n\n/** 把保留块作为独立 system 消息插入历史,并限制总量;优先保留最近激活的 skill。\n * 用 system 而非 user:skill 是系统能力指令,不应与用户原话同角色——两个协议\n * 适配器(responses → instructions、messages → 顶层 system)都会把 system\n * 聚合到最前,与主 system prompt 合并,不存在位置约束问题。 */\nexport function retainedContextsAsMessages(\n blocks: RetainedContextBlock[],\n maxTokens = RETAINED_CONTEXT_TOKEN_BUDGET,\n): ChatMessage[] {\n const selected: RetainedContextBlock[] = [];\n let remaining = Math.max(0, maxTokens);\n for (let i = blocks.length - 1; i >= 0; i -= 1) {\n const block = blocks[i]!;\n const tokens = approximateTokens(block);\n if (tokens > remaining) continue;\n selected.push(block);\n remaining -= tokens;\n }\n selected.reverse();\n return selected.map((block) => ({\n role: \"system\" as const,\n content: block.content.startsWith(RETAINED_CONTEXT_START)\n ? block.content\n : `${RETAINED_CONTEXT_START} ${block.key}\\n${block.content}\\n${RETAINED_CONTEXT_END}`,\n }));\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","/**\n * 上下文压缩 —— codex 本地压缩策略的移植(经 MovieClaw 验证的取舍)。\n *\n * 核心思路:\n * 1. 触发以服务端上报的 usage 为准:每步响应带回真实 prompt_tokens,无需引入\n * tokenizer;仅在没有服务端数据的场合(续聊冷启动、尚未发送的工具结果)用\n * 「UTF-8 字节数 ≈ 4 字节/token」的启发式补估;\n * 2. 压缩就是一次普通模型调用:把交接摘要指令作为 user 消息追加到全量历史\n * 末尾,不带任何工具定义——模型只能输出文本,天然保证这一轮只写摘要;\n * 3. 重建历史「宽进严出」:生成摘要时模型看得到全部现场;压缩落地后只保留\n * 「预算内最近的用户原话 + 摘要」,工具轨迹全部丢弃——用户原话永不经过\n * 有损摘要,防多次压缩后忘记原始意图;\n * 4. 失败一律降级:压缩失败只记日志、返回 null,绝不中断正在进行的运行。\n */\nimport type { ChatMessage, ModelSettings } from \"../llm/models.js\";\nimport type { LlmProtocol } from \"../llm/protocol.js\";\nimport { COMPACT_PROMPT, SUMMARY_PREFIX } from \"./prompts.js\";\nimport {\n extractRetainedContextsFromMessages,\n retainedContextsAsMessages,\n} from \"./retained-context.js\";\n\n/** 自动压缩水位线:上下文占用 ≥ 窗口的 90% 时触发(codex 同款比例) */\nexport const COMPACT_TRIGGER_RATIO = 0.9;\n\n/** 重建历史时保留近期用户消息的 token 预算(codex 同款 20k) */\nexport const RETAINED_USER_TOKEN_BUDGET = 20_000;\n\n/** 无 tokenizer 时的估算系数:约 4 字节(UTF-8)≈ 1 token。对中文同样适用——\n * 一个汉字 3 字节 ≈ 0.75 token,与主流 tokenizer 的量级一致,偏保守即可 */\nexport const APPROX_BYTES_PER_TOKEN = 4;\n\nexport interface CompactionResult {\n /** 交接摘要文本 */\n summary: string;\n /** 重建后的历史(不含 system,system 每次运行重拼) */\n replacement_history: ChatMessage[];\n /** 压缩前后的估算 token 数(bytes/4 启发式,展示与观测用,非精确值) */\n tokens_before: number;\n tokens_after: number;\n}\n\nexport function estimateTokens(target: ChatMessage[] | ChatMessage | string): number {\n if (typeof target === \"string\") {\n return Math.floor(Buffer.byteLength(target, \"utf-8\") / APPROX_BYTES_PER_TOKEN);\n }\n if (Array.isArray(target)) {\n return target.reduce((sum, m) => sum + estimateTokens(m), 0);\n }\n let total = Buffer.byteLength(target.content ?? \"\", \"utf-8\");\n for (const tc of target.tool_calls ?? []) {\n total += Buffer.byteLength(tc.name, \"utf-8\");\n total += Buffer.byteLength(tc.raw_arguments, \"utf-8\");\n }\n return Math.floor(total / APPROX_BYTES_PER_TOKEN);\n}\n\n/** 是否达到自动压缩水位线;模型未声明窗口时永不自动压缩(调用方负责日志) */\nexport function shouldCompact(contextTokens: number, contextWindow: number | undefined): boolean {\n if (!contextWindow) return false;\n return contextTokens >= Math.floor(contextWindow * COMPACT_TRIGGER_RATIO);\n}\n\n/** 识别历史里由压缩产生的摘要消息(user 角色 + 固定前缀) */\nexport function isSummaryMessage(message: ChatMessage): boolean {\n return message.role === \"user\" && (message.content ?? \"\").startsWith(SUMMARY_PREFIX);\n}\n\n/** 识别压缩后重新注入的合法保留上下文块(不是用户原话);system 角色注入 */\nexport function isRetainedContextMessage(message: ChatMessage): boolean {\n return (message.role === \"user\" || message.role === \"system\")\n && extractRetainedContextsFromMessages([message]).length > 0;\n}\n\n/** 中部截断:头尾各留一半预算,中间以标记替代(用户消息开头是诉求、结尾是\n * 最新补充,头尾信息密度最高)。按字节预算切,落在多字节字符中间时由\n * Buffer.toString 自动退回合法边界。 */\nfunction truncateMiddle(text: string, maxTokens: number): string {\n const budgetBytes = maxTokens * APPROX_BYTES_PER_TOKEN;\n const data = Buffer.from(text, \"utf-8\");\n if (data.length <= budgetBytes) return text;\n const half = Math.floor(budgetBytes / 2);\n const head = data.subarray(0, half).toString(\"utf-8\");\n const tail = data.subarray(data.length - half).toString(\"utf-8\");\n const omitted = Math.floor((data.length - budgetBytes) / APPROX_BYTES_PER_TOKEN);\n return `${head}\\n…(中间约 ${omitted} token 已截断)…\\n${tail}`;\n}\n\n/** 按 codex 策略重建历史:预算内逆序保留的用户原话 + 保留上下文 + 摘要收尾。\n * - 只保留真实 user 消息(排除 system / 旧压缩摘要 / 保留上下文块),从最新往旧装入预算,\n * 装不下的最旧一条中部截断;\n * - assistant / 普通 tool / 思考内容全部丢弃,信息由摘要承载;\n * - 带耐久标记的保留上下文(如已激活 skill)会重新注入,避免压缩后丢失;\n * - 摘要带固定前缀、作为最后一条 user 消息。 */\nexport function buildReplacementHistory(\n messages: ChatMessage[],\n summary: string,\n): ChatMessage[] {\n const retainedUsers: ChatMessage[] = [];\n let remaining = RETAINED_USER_TOKEN_BUDGET;\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i]!;\n if (message.role !== \"user\" || isSummaryMessage(message) || isRetainedContextMessage(message)) {\n continue;\n }\n if (remaining <= 0) break;\n const tokens = estimateTokens(message);\n if (tokens <= remaining) {\n retainedUsers.push(message);\n remaining -= tokens;\n } else {\n retainedUsers.push({ role: \"user\", content: truncateMiddle(message.content ?? \"\", remaining) });\n break;\n }\n }\n retainedUsers.reverse();\n const retainedContexts = retainedContextsAsMessages(extractRetainedContextsFromMessages(messages));\n return [\n ...retainedUsers,\n ...retainedContexts,\n { role: \"user\", content: `${SUMMARY_PREFIX}\\n${summary}` },\n ];\n}\n\n/**\n * 执行一次压缩:全量历史 + 摘要指令 → 模型写交接摘要 → 重建历史。\n *\n * messages 是完整现场(含 system 与全部工具往返);返回的\n * replacement_history 不含 system。任何失败(流错误、异常、空摘要)都\n * 返回 null,由调用方决定降级方式——本函数绝不抛异常。\n */\nexport async function compact(\n protocol: LlmProtocol,\n model: string,\n messages: ChatMessage[],\n settings: ModelSettings,\n): Promise<CompactionResult | null> {\n let summary: string | null = null;\n try {\n for await (const event of protocol.chatStream({\n model,\n // 摘要指令是普通 user 消息;不带工具定义,模型只能输出文本\n messages: [...messages, { role: \"user\", content: COMPACT_PROMPT }],\n settings,\n })) {\n if (event.type === \"error\") {\n console.warn(`上下文压缩失败(模型调用出错):${event.error}`);\n return null;\n }\n if (event.type === \"done\") summary = (event.response.content ?? \"\").trim();\n }\n } catch (err) {\n console.warn(`上下文压缩失败(请求异常):${err instanceof Error ? err.message : err}`);\n return null;\n }\n if (!summary) {\n console.warn(\"上下文压缩失败:模型返回了空摘要\");\n return null;\n }\n const replacement = buildReplacementHistory(messages, summary);\n const system = messages.slice(0, 1).filter((m) => m.role === \"system\");\n return {\n summary,\n replacement_history: replacement,\n tokens_before: estimateTokens(messages),\n tokens_after: estimateTokens([...system, ...replacement]),\n };\n}\n","/**\n * Agent 会话的 JSONL 持久化存储(事实源)。\n *\n * 设计定案(移植自 MovieClaw,调研 pi / codex / Claude Code 后的共识 + 取舍):\n *\n * 1. 一个会话一个 append-only JSONL 文件:首行是会话头,之后每行一条\n * 消息 entry。历史行永不改写——中断、重启都只会追加。唯一例外是\n * discardFromUserMessage(retry 的历史替换),见该方法说明;\n * 2. 只落定稿消息,不落流式 delta:文件里的 message 就是内部规范模型原样\n * 格式(ChatMessage),resume 重建上下文零转换;\n * 3. entry 带 uuid / parent_uuid:当前是纯线性链(parent 永远指向上一条),\n * 字段先留好,将来做历史分支时无需迁移文件格式;\n * 4. 读取容错:进程崩溃可能留下半行,逐行解析时静默跳过坏行并计数,\n * 绝不让整个会话打不开;\n * 5. 压缩行(type: \"compaction\"):含摘要与完整替换历史,buildHistory 从\n * 最后一条压缩行起重建(codex 的 Compacted 记录同款思路)。压缩前的\n * 原始消息仍完整留在文件里(回放展示用),但不再进入模型上下文。\n *\n * 存储位置默认 ~/.xlyra-agent/sessions(评审定案),构造参数可覆盖。\n */\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { chatMessageSchema, tokenUsageSchema, type ChatMessage } from \"../llm/models.js\";\nimport type { CompactionResult } from \"./compaction.js\";\n\n/** 文件格式版本;结构变化时 +1,读取端按版本做迁移\n * v3:新增 type=\"escalation\" 的提权请求行(读端向后兼容 v1/v2) */\nexport const SESSION_FORMAT_VERSION = 3;\n\n/** 会话标题 / 最后提示预览的截断长度 */\nexport const PREVIEW_MAX_CHARS = 80;\n\n/** 默认数据根目录(~/.xlyra-agent),sessions 与 index.json 均在其下 */\nexport function defaultDataDir(): string {\n return path.join(os.homedir(), \".xlyra-agent\");\n}\n\nexport function defaultSessionsDir(): string {\n return path.join(defaultDataDir(), \"sessions\");\n}\n\nconst sessionHeaderSchema = z.object({\n type: z.literal(\"session\").default(\"session\"),\n version: z.number().default(SESSION_FORMAT_VERSION),\n session_id: z.string(),\n created_at: z.string(),\n});\nexport type SessionHeader = z.infer<typeof sessionHeaderSchema>;\n\nconst sessionMessageEntrySchema = z.object({\n type: z.literal(\"message\").default(\"message\"),\n uuid: z.string(),\n parent_uuid: z.string().nullish(),\n timestamp: z.string(),\n message: chatMessageSchema,\n /** 以下仅 assistant 消息携带(运行元数据,不属于 message 本身,放信封层) */\n model: z.string().nullish(),\n usage: tokenUsageSchema.nullish(),\n finish_reason: z.string().nullish(),\n});\nexport type SessionMessageEntry = z.infer<typeof sessionMessageEntrySchema>;\n\nconst sessionCompactionEntrySchema = z.object({\n type: z.literal(\"compaction\").default(\"compaction\"),\n uuid: z.string(),\n parent_uuid: z.string().nullish(),\n timestamp: z.string(),\n summary: z.string(),\n replacement_history: z.array(chatMessageSchema),\n tokens_before: z.number().nullish(),\n tokens_after: z.number().nullish(),\n});\nexport type SessionCompactionEntry = z.infer<typeof sessionCompactionEntrySchema>;\n\n/** 提权请求行:越界访问的协商记录(回放时前端据此渲染确认卡片)。\n * granted=null 待确认;true 已授权;false 已拒绝 */\nconst sessionEscalationEntrySchema = z.object({\n type: z.literal(\"escalation\").default(\"escalation\"),\n uuid: z.string(),\n parent_uuid: z.string().nullish(),\n timestamp: z.string(),\n requested_path: z.string(),\n resolved_path: z.string(),\n tool_name: z.string(),\n resource_type: z.enum([\"path\", \"command\"]).default(\"path\"),\n requested_command: z.array(z.string()).nullish(),\n /** 旧记录可能省略待确认状态;读取时统一规范化为 null。 */\n granted: z.boolean().nullish().default(null),\n});\nexport type SessionEscalationEntry = z.infer<typeof sessionEscalationEntrySchema>;\n\nexport type SessionEntry = SessionMessageEntry | SessionCompactionEntry | SessionEscalationEntry;\n\nexport interface SessionSummary {\n session_id: string;\n created_at: string;\n entry_count: number;\n leaf_uuid: string | null;\n /** 首条 user 消息的截断文本;作为无自定义标题时的会话标题 */\n title: string | null;\n /** 最后一条 user 消息的截断文本 */\n last_prompt: string | null;\n last_timestamp: string;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction entryUuid(): string {\n return crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n}\n\nexport function isMessageEntry(e: SessionEntry): e is SessionMessageEntry {\n return e.type === \"message\";\n}\n\nexport function isCompactionEntry(e: SessionEntry): e is SessionCompactionEntry {\n return e.type === \"compaction\";\n}\n\nexport function isEscalationEntry(e: SessionEntry): e is SessionEscalationEntry {\n return e.type === \"escalation\";\n}\n\nfunction lastCompactionIndex(entries: SessionEntry[]): number {\n for (let i = entries.length - 1; i >= 0; i--) {\n if (isCompactionEntry(entries[i]!)) return i;\n }\n return -1;\n}\n\n/** 最后一条压缩行之后的消息(无压缩行时即全部消息) */\nfunction messagesAfterLastCompaction(entries: SessionEntry[]): ChatMessage[] {\n const last = lastCompactionIndex(entries);\n return entries.slice(last + 1).filter(isMessageEntry).map((e) => e.message);\n}\n\nexport class AgentSessionStore {\n private readonly root: string;\n /** session_id → 最后一条 entry 的 uuid(避免每次 append 都重读文件) */\n private readonly leafCache = new Map<string, string | null>();\n\n constructor(root?: string) {\n this.root = path.resolve(root ?? defaultSessionsDir());\n }\n\n get rootDir(): string {\n return this.root;\n }\n\n pathOf(sessionId: string): string {\n return path.join(this.root, `${sessionId}.jsonl`);\n }\n\n exists(sessionId: string): boolean {\n return fs.existsSync(this.pathOf(sessionId));\n }\n\n // ------------------------------------------------------------------\n // 写入\n // ------------------------------------------------------------------\n\n /** 新建会话文件并写入头行,返回头信息 */\n create(sessionId?: string): SessionHeader {\n const header: SessionHeader = {\n type: \"session\",\n version: SESSION_FORMAT_VERSION,\n session_id: sessionId ?? crypto.randomUUID().replaceAll(\"-\", \"\"),\n created_at: nowIso(),\n };\n fs.mkdirSync(this.root, { recursive: true });\n // wx:会话 id 冲突(几乎不可能)时宁可报错也不覆盖已有文件\n fs.writeFileSync(this.pathOf(header.session_id), JSON.stringify(header) + \"\\n\", { flag: \"wx\" });\n this.leafCache.set(header.session_id, null);\n return header;\n }\n\n /** 追加一条定稿消息,自动接到当前链尾,返回写入的 entry */\n append(\n sessionId: string,\n message: ChatMessage,\n meta?: { model?: string; usage?: z.infer<typeof tokenUsageSchema>; finish_reason?: string },\n ): SessionMessageEntry {\n const parent = this.currentLeaf(sessionId);\n const entry: SessionMessageEntry = {\n type: \"message\",\n uuid: entryUuid(),\n parent_uuid: parent,\n timestamp: nowIso(),\n message,\n model: meta?.model ?? null,\n usage: meta?.usage ?? null,\n finish_reason: meta?.finish_reason ?? null,\n };\n this.appendLine(sessionId, stripNulls(entry));\n this.leafCache.set(sessionId, entry.uuid);\n return entry;\n }\n\n /** 追加一条压缩行,与 append 同款接到当前链尾(parent 链线性穿过压缩行) */\n appendCompaction(sessionId: string, result: CompactionResult): SessionCompactionEntry {\n const parent = this.currentLeaf(sessionId);\n const entry: SessionCompactionEntry = {\n type: \"compaction\",\n uuid: entryUuid(),\n parent_uuid: parent,\n timestamp: nowIso(),\n summary: result.summary,\n replacement_history: result.replacement_history,\n tokens_before: result.tokens_before,\n tokens_after: result.tokens_after,\n };\n this.appendLine(sessionId, stripNulls(entry));\n this.leafCache.set(sessionId, entry.uuid);\n return entry;\n }\n\n /** 追加一条提权请求行(granted=null 待确认) */\n appendEscalation(\n sessionId: string,\n info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type?: \"path\" | \"command\";\n requested_command?: string[];\n },\n ): SessionEscalationEntry {\n const parent = this.currentLeaf(sessionId);\n const entry: SessionEscalationEntry = {\n type: \"escalation\",\n uuid: info.escalation_id,\n parent_uuid: parent,\n timestamp: nowIso(),\n requested_path: info.requested_path,\n resolved_path: info.resolved_path,\n tool_name: info.tool_name,\n resource_type: info.resource_type ?? \"path\",\n requested_command: info.requested_command,\n granted: null,\n };\n this.appendLine(sessionId, stripNulls(entry));\n this.leafCache.set(sessionId, entry.uuid);\n return entry;\n }\n\n /** 标记提权请求的确认结果(granted=true 授权 / false 拒绝)。\n * 这是 append-only 原则的第二个例外(另一个是 discardFromUserMessage):\n * 提权行的 granted 字段需要就地更新,否则确认状态无法在回放时保留。\n * 实现上仍是整文件原子重写(tmp + rename),与 discard 同款安全保证。 */\n resolveEscalation(sessionId: string, escalationId: string, granted: boolean): boolean {\n const { header, entries } = this.read(sessionId);\n const index = entries.findIndex((e) => isEscalationEntry(e) && e.uuid === escalationId);\n if (index === -1) return false;\n const target = entries[index]!;\n if (!isEscalationEntry(target)) return false;\n entries[index] = { ...target, granted };\n const filePath = this.pathOf(sessionId);\n const tmp = `${filePath}.tmp`;\n const lines = [JSON.stringify(header), ...entries.map((e) => JSON.stringify(stripNulls(e)))];\n fs.writeFileSync(tmp, lines.join(\"\\n\") + \"\\n\");\n fs.renameSync(tmp, filePath);\n return true;\n }\n\n /**\n * 中断收尾:给没有结果的 tool_call 补写错误回执,返回补写条数。\n *\n * 保证文件里 assistant 的 tool_calls 与 tool 消息任何时刻都配对完整,\n * resume 直接回喂 API 不需要修复逻辑(在写入侧一次做对)。\n * 只检查最后一条压缩行之后的消息:更早的往返已被压缩挡在上下文之外,\n * 给死上下文补回执毫无意义。\n */\n sealPendingToolCalls(sessionId: string, tone: \"interrupted\" | \"awaiting_authorization\" = \"interrupted\"): number {\n const { entries } = this.read(sessionId);\n const messages = messagesAfterLastCompaction(entries);\n const answered = new Set(\n messages.filter((m) => m.role === \"tool\").map((m) => m.tool_call_id),\n );\n // 提权暂停不是失败:回执用中性语义,回放时不会把这一步标红\n const receipt = tone === \"awaiting_authorization\"\n ? { content: \"等待用户授权,工具暂停执行。\", is_error: false }\n : { content: \"操作已被中断,工具未执行完成。\", is_error: true };\n let sealed = 0;\n for (const message of messages) {\n for (const tc of message.tool_calls ?? []) {\n if (answered.has(tc.id)) continue;\n this.append(sessionId, {\n role: \"tool\",\n content: receipt.content,\n tool_call_id: tc.id,\n name: tc.name,\n is_error: receipt.is_error,\n });\n sealed += 1;\n }\n }\n return sealed;\n }\n\n /**\n * 删除指定 user message 及其之后的全部 entry,返回删除条数。\n *\n * 这是本模块唯一改写历史行的方法,与「append-only」约定相悖,属于刻意的\n * 例外:用户要的就是「这些记录不该再存在」。整文件重写,写临时文件后\n * rename 原子换入:中途崩溃要么旧文件完好、要么新文件完整。\n * 只允许从 user message 切:从 assistant/tool 中间切会留下没有回执的\n * tool_call,重建出的上下文喂回模型直接 400。\n */\n discardFromUserMessage(sessionId: string, messageId: string): number {\n const { header, entries } = this.read(sessionId);\n const index = entries.findIndex((e) => e.uuid === messageId);\n if (index === -1) throw new Error(\"会话中没有这条记录,可能已被改写\");\n const target = entries[index]!;\n if (!isMessageEntry(target) || target.message.role !== \"user\") {\n throw new Error(\"只能重试用户消息\");\n }\n const kept = entries.slice(0, index);\n const filePath = this.pathOf(sessionId);\n const tmp = `${filePath}.tmp`;\n const lines = [JSON.stringify(header), ...kept.map((e) => JSON.stringify(stripNulls(e)))];\n fs.writeFileSync(tmp, lines.join(\"\\n\") + \"\\n\");\n fs.renameSync(tmp, filePath);\n this.leafCache.set(sessionId, kept.length > 0 ? kept[kept.length - 1]!.uuid : null);\n return entries.length - kept.length;\n }\n\n /** 删除会话文件(幂等) */\n delete(sessionId: string): void {\n fs.rmSync(this.pathOf(sessionId), { force: true });\n this.leafCache.delete(sessionId);\n }\n\n // ------------------------------------------------------------------\n // 读取\n // ------------------------------------------------------------------\n\n /** 读取整个会话(头 + 全部 entry,含压缩行),坏行静默跳过 */\n read(sessionId: string): { header: SessionHeader; entries: SessionEntry[]; badLines: number } {\n const filePath = this.pathOf(sessionId);\n if (!fs.existsSync(filePath)) throw new Error(\"会话不存在或转录文件已被删除\");\n const lines = fs.readFileSync(filePath, \"utf-8\").split(\"\\n\");\n let header: SessionHeader | null = null;\n const entries: SessionEntry[] = [];\n let bad = 0;\n for (const [lineNo, raw] of lines.entries()) {\n const line = raw.trim();\n if (!line) continue;\n if (lineNo === 0) {\n header = sessionHeaderSchema.parse(JSON.parse(line));\n continue;\n }\n try {\n const parsed: unknown = JSON.parse(line);\n const type = (parsed as { type?: string }).type;\n entries.push(\n type === \"compaction\"\n ? sessionCompactionEntrySchema.parse(parsed)\n : type === \"escalation\"\n ? sessionEscalationEntrySchema.parse(parsed)\n : sessionMessageEntrySchema.parse(parsed),\n );\n } catch {\n bad += 1;\n }\n }\n if (!header) throw new Error(\"会话文件为空或头记录损坏\");\n if (bad > 0) {\n console.warn(`会话文件存在 ${bad} 行无法解析的记录,已跳过(可能来自异常退出):${filePath}`);\n }\n return { header, entries, badLines: bad };\n }\n\n /**\n * 把会话重建成模型上下文消息列表(resume 喂回模型用)。\n * 有压缩行时,从最后一条压缩行的替换历史起步、只追加其后的增量消息;\n * system 提示词不入库(随代码版本演进),由 runner 每次运行时重新拼装。\n */\n buildHistory(sessionId: string): ChatMessage[] {\n const { entries } = this.read(sessionId);\n const last = lastCompactionIndex(entries);\n if (last < 0) return entries.filter(isMessageEntry).map((e) => e.message);\n const compaction = entries[last] as SessionCompactionEntry;\n return [\n ...compaction.replacement_history,\n ...entries.slice(last + 1).filter(isMessageEntry).map((e) => e.message),\n ];\n }\n\n /**\n * 重建提权中断前的上下文:保留原始 user 输入,但丢弃被中断的\n * assistant/tool 往返,授权后由 runner 从原输入继续推理。\n */\n buildHistoryBeforeEscalation(sessionId: string, escalationId: string): ChatMessage[] {\n const { entries } = this.read(sessionId);\n const escalationIndex = entries.findIndex(\n (entry) => isEscalationEntry(entry) && entry.uuid === escalationId,\n );\n if (escalationIndex < 0) return this.buildHistory(sessionId);\n const escalation = entries[escalationIndex]!;\n const assistantIndex = entries.findIndex(\n (entry) => entry.uuid === escalation.parent_uuid && isMessageEntry(entry)\n && entry.message.role === \"assistant\",\n );\n const cut = assistantIndex >= 0 ? assistantIndex : escalationIndex;\n const last = lastCompactionIndex(entries);\n if (last >= 0 && last < cut) {\n const compaction = entries[last] as SessionCompactionEntry;\n return [\n ...compaction.replacement_history,\n ...entries.slice(last + 1, cut).filter(isMessageEntry).map((e) => e.message),\n ];\n }\n return entries.slice(0, cut).filter(isMessageEntry).map((e) => e.message);\n }\n\n /** 扫描单个会话文件生成索引摘要 */\n summarize(sessionId: string): SessionSummary {\n const { header, entries } = this.read(sessionId);\n const userTexts = entries\n .filter(isMessageEntry)\n .filter((e) => e.message.role === \"user\" && (e.message.content ?? \"\").trim())\n .map((e) => (e.message.content ?? \"\").trim());\n const last = entries[entries.length - 1];\n return {\n session_id: header.session_id,\n created_at: header.created_at,\n entry_count: entries.length,\n leaf_uuid: last?.uuid ?? null,\n title: userTexts[0]?.slice(0, PREVIEW_MAX_CHARS) ?? null,\n last_prompt: userTexts[userTexts.length - 1]?.slice(0, PREVIEW_MAX_CHARS) ?? null,\n last_timestamp: last?.timestamp ?? header.created_at,\n };\n }\n\n /** 遍历目录下全部会话文件生成摘要(索引整体重建用;单文件损坏只跳过) */\n scanAll(): SessionSummary[] {\n if (!fs.existsSync(this.root)) return [];\n const summaries: SessionSummary[] = [];\n for (const name of fs.readdirSync(this.root).sort()) {\n if (!name.endsWith(\".jsonl\")) continue;\n const sessionId = name.slice(0, -\".jsonl\".length);\n try {\n summaries.push(this.summarize(sessionId));\n } catch (err) {\n console.warn(`会话文件无法解析,重建索引时已跳过:${name}(${err instanceof Error ? err.message : err})`);\n }\n }\n return summaries;\n }\n\n // ------------------------------------------------------------------\n\n private currentLeaf(sessionId: string): string | null {\n if (!this.leafCache.has(sessionId)) {\n const { entries } = this.read(sessionId);\n this.leafCache.set(sessionId, entries[entries.length - 1]?.uuid ?? null);\n }\n return this.leafCache.get(sessionId) ?? null;\n }\n\n private appendLine(sessionId: string, entry: SessionEntry): void {\n const filePath = this.pathOf(sessionId);\n if (!fs.existsSync(filePath)) throw new Error(\"会话不存在或转录文件已被删除\");\n fs.appendFileSync(filePath, JSON.stringify(entry) + \"\\n\");\n }\n}\n\n/** JSONL 序列化前去 null 字段(与 MovieClaw 的 exclude_none 对齐,文件更紧凑) */\nfunction stripNulls<T>(obj: T): T {\n return JSON.parse(\n JSON.stringify(obj, (_key, value: unknown) => (value === null || value === undefined ? undefined : value)),\n ) as T;\n}\n","/**\n * AgentRunner —— Agent loop 执行器。\n *\n * 循环语义(移植自 MovieClaw runner.py,设计要点逐条保留):\n * - 每一步 = 一次流式模型调用;模型输出的工具调用**以内容为准**判断是否\n * 继续循环——finish_reason 只作参考,因为兼容端点存在「stop 但带调用」\n * 「tool_calls 但数组为空」两类在案怪癖;\n * - 有工具调用 → 顺序执行每一个(参数先过 JSON Schema 校验),结果作为\n * tool 消息回喂,进入下一步;无工具调用 → STOP,正常结束;\n * - 工具的校验失败与执行异常都不中断循环:错误文本作为失败结果回喂,\n * 让模型自行修正;\n * - maxSteps(默认 200)防失控;错误一律以 agent_error 事件收尾,不抛异常。\n *\n * 取消语义(与编排层的分工):\n * - runner 接受外部 AbortSignal;signal 触发后本生成器尽快、安静地结束,\n * **不落终态事件**——agent_cancelled 由编排层在 abort 之前先落\n * (RunRegistry.cancel),保证订阅者永远先看到终态。\n */\nimport crypto from \"node:crypto\";\nimport type { ChatMessage, ChatResponse, TokenUsage } from \"../llm/models.js\";\nimport { addUsage, chatMessageSchema, emptyUsage, modelSettingsSchema, responseToMessage } from \"../llm/models.js\";\nimport type { LlmProtocol } from \"../llm/protocol.js\";\nimport { LlmError } from \"../llm/errors.js\";\nimport type { EndpointResolver } from \"../llm/router.js\";\nimport { validateToolCall } from \"../llm/validate.js\";\nimport type { AgentTool } from \"../tools/types.js\";\nimport { truncateMiddle } from \"../tools/types.js\";\nimport type { CompactionResult } from \"./compaction.js\";\nimport { compact, estimateTokens, shouldCompact } from \"./compaction.js\";\nimport { EscalationRequiredError } from \"./escalation.js\";\nimport type { AgentDone, AgentEvent, AgentStartParams, AgentToolResult } from \"./events.js\";\nimport { buildAvailableToolsPrompt, buildSystemPrompt } from \"./prompts.js\";\n\n/** tool_result 事件里输出的截断长度(完整输出仍进对话上下文喂给模型) */\nconst EVENT_OUTPUT_LIMIT = 2000;\n\n/**\n * 判断一次 LLM 调用失败是否值得 agent 侧重试(瞬态)。\n * 依据协议层抛出的固定错误前缀(见 responses/messages 的 yield error 文案),\n * 不靠错误对象类型——协议层只暴露文本。\n * 只覆盖「上游可用性问题」:网络抖动、5xx、流内声明失败、断流。\n * 凭证类错误(401/403)与参数类错误(400/404)不可重试。\n */\nfunction isTransientLLMError(message: string): boolean {\n const m = message.toLowerCase();\n if (m.includes(\"401\") || m.includes(\"403\") || m.includes(\"400\") || m.includes(\"404\")) return false;\n return (\n m.includes(\"网络错误\") ||\n m.includes(\"流读取失败\") ||\n m.includes(\"模型流异常终止\") ||\n m.includes(\"模型调用失败\") || // 上游流内 response.failed / error 事件\n m.includes(\"响应不完整\") ||\n m.includes(\"http 5\") || // 502/503/504 等,经 httpErrorSummary 带入\n m.includes(\"502\") ||\n m.includes(\"503\") ||\n m.includes(\"504\")\n );\n}\n\nexport interface AgentRunnerOptions {\n /** 直接使用单个协议实例(库形态的典型用法) */\n protocol?: LlmProtocol;\n /** 或经端点路由按 params.model 解析(服务层用法);两者必传其一 */\n resolver?: EndpointResolver;\n tools?: AgentTool[];\n maxSteps?: number;\n /** 定稿消息回调(会话持久化挂点):中间步 assistant(含 tool_calls)、\n * 每条 tool 结果、终答 assistant 各调用一次;流式 delta 不经过这里 */\n onMessage?: (message: ChatMessage, response: ChatResponse | null) => Promise<void>;\n /** 压缩定稿回调(转录落盘挂点):每次上下文压缩成功后调用一次 */\n onCompaction?: (result: CompactionResult) => Promise<void>;\n /** 提权请求回调(转录落盘挂点):回放时前端据此渲染确认卡片 */\n onEscalation?: (info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type: \"path\" | \"command\";\n requested_command?: string[];\n }) => Promise<void>;\n /** 日志输出(默认 console);测试可注入静默 logger */\n logger?: Pick<Console, \"info\" | \"warn\" | \"error\">;\n /** 提权事件里展示的工作区根(用户判断边界用);服务装配层从工具配置传入 */\n workdirHint?: string;\n}\n\nexport interface AgentRunOptions {\n runId?: string;\n signal?: AbortSignal;\n /**\n * 当前 run 的标识上下文(xlyra-callback 凭证用):sessionId 由会话层提供,\n * agentInstanceId 由部署方注入;仅标识 ID,不携带会话内容。\n * 提供 sessionId 时,runner 会在首次模型调用前把上下文推进协议实例。\n */\n sessionId?: string;\n agentInstanceId?: string;\n}\n\nexport class AgentRunner {\n private readonly protocol?: LlmProtocol;\n private readonly resolver?: EndpointResolver;\n private readonly tools: AgentTool[];\n private readonly toolsByName: Map<string, AgentTool>;\n private readonly maxSteps: number;\n private readonly onMessage?: AgentRunnerOptions[\"onMessage\"];\n private readonly onCompaction?: AgentRunnerOptions[\"onCompaction\"];\n private readonly onEscalation?: AgentRunnerOptions[\"onEscalation\"];\n private readonly logger: Pick<Console, \"info\" | \"warn\" | \"error\">;\n /** 提权事件里展示的工作区根(用户判断边界用);由构造方从工具配置传入 */\n private readonly workdirHint: string;\n\n constructor(opts: AgentRunnerOptions) {\n if (!opts.protocol && !opts.resolver) {\n throw new Error(\"AgentRunner 需要 protocol 或 resolver 之一\");\n }\n this.protocol = opts.protocol;\n this.resolver = opts.resolver;\n this.tools = opts.tools ?? [];\n this.toolsByName = new Map(this.tools.map((t) => [t.definition.name, t]));\n this.maxSteps = opts.maxSteps ?? 200;\n this.onMessage = opts.onMessage;\n this.onCompaction = opts.onCompaction;\n this.onEscalation = opts.onEscalation;\n this.logger = opts.logger ?? console;\n this.workdirHint = opts.workdirHint ?? \"\";\n }\n\n async *start(\n params: AgentStartParams,\n runOpts: AgentRunOptions = {},\n ): AsyncGenerator<AgentEvent> {\n const runId = runOpts.runId ?? crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n const started = Date.now();\n\n // 路由解析放在发事件之前:解析失败也要以 agent_error 事件告知,而不是断流\n let protocol: LlmProtocol;\n let providerName: string;\n let modelId: string;\n let contextWindow: number | undefined;\n try {\n if (this.resolver) {\n const resolved = this.resolver.resolve(params.model ?? \"\");\n protocol = resolved.protocol;\n providerName = resolved.endpoint.name;\n modelId = resolved.modelId;\n contextWindow = resolved.contextWindow;\n } else {\n protocol = this.protocol!;\n providerName = protocol.name;\n modelId = params.model ?? \"\";\n contextWindow = undefined;\n }\n } catch (err) {\n if (err instanceof LlmError) {\n yield { type: \"agent_error\", run_id: runId, error: err.message };\n return;\n }\n throw err;\n }\n if (!contextWindow) {\n this.logger.info(`模型未声明上下文窗口,自动压缩停用 model=${modelId}`);\n }\n\n // xlyra-callback 凭证:把本次 run 的标识上下文推进协议实例(协议实例按\n // 端点缓存、跨 run 复用;换 run 后旧 token 作废)。direct 凭证为 no-op。\n if (runOpts.sessionId) {\n protocol.setRunContext?.({\n agentInstanceId: runOpts.agentInstanceId ?? \"default\",\n sessionId: runOpts.sessionId,\n runId,\n model: modelId,\n });\n }\n\n // history 来自外部输入(z.input 形态,content 可选):统一过一遍 schema\n // 补全默认值,同时挡掉调用方传来的结构错误\n const history = (params.history ?? []).map((m) => chatMessageSchema.parse(m));\n const settings = modelSettingsSchema.parse(params.settings ?? {});\n const definitions = this.tools.map((t) => t.definition);\n const availableToolsPrompt = buildAvailableToolsPrompt(\n definitions.map(({ name, description }) => ({ name, description })),\n );\n const messages: ChatMessage[] = [\n {\n role: \"system\",\n content:\n params.system_prompt\n ? `${params.system_prompt.trim()}\\n\\n${availableToolsPrompt}`\n : buildSystemPrompt({ availableTools: definitions.map(({ name, description }) => ({ name, description })) }),\n },\n ...history,\n ...(params.include_input === false ? [] : [{ role: \"user\" as const, content: params.input }]),\n ];\n\n yield { type: \"agent_start\", run_id: runId, provider: providerName, model: modelId };\n\n // pre-run 检查:续聊重建的历史可能已经逼近窗口(此时还没有服务端 usage\n // 可用,用字节启发式估算),先压缩再进入循环\n const preCompact = await this.maybeCompact(\n protocol, runId, modelId, messages, estimateTokens(messages), contextWindow, settings,\n );\n if (preCompact) yield preCompact;\n\n let usage = emptyUsage();\n for (let step = 1; step <= this.maxSteps; step++) {\n if (runOpts.signal?.aborted) return; // 取消:安静退出,终态已由编排层落\n\n let final: ChatResponse | null = null;\n // step 级重试:上游网络抖动/流内声明失败时,在没向外界吐出任何增量\n // (text_delta/tool_call)之前允许换同一路由重试一次;一旦已有增量\n // 流出就不再重试,避免重复生成。可重试判定收敛在协议层固定前缀上。\n const maxStepAttempts = 2;\n let attempt = 0;\n let buffered: AgentEvent[] | null = null;\n while (true) {\n attempt += 1;\n const attemptEvents: AgentEvent[] = [];\n let sawDelta = false;\n let attemptFailed: string | null = null;\n for await (const event of protocol.chatStream({\n model: modelId,\n messages,\n tools: definitions.length ? definitions : undefined,\n settings,\n signal: runOpts.signal,\n })) {\n if (event.type === \"thinking_delta\") {\n sawDelta = true;\n attemptEvents.push({ type: \"thinking_delta\", run_id: runId, delta: event.delta });\n } else if (event.type === \"text_delta\") {\n sawDelta = true;\n attemptEvents.push({ type: \"text_delta\", run_id: runId, delta: event.delta });\n } else if (event.type === \"toolcall_start\") {\n sawDelta = true;\n attemptEvents.push({ type: \"tool_call_start\", run_id: runId, tool_call: event.tool_call });\n } else if (event.type === \"toolcall_delta\") {\n sawDelta = true;\n attemptEvents.push({\n type: \"tool_call_delta\",\n run_id: runId,\n delta: event.delta,\n tool_call_id: event.tool_call.id,\n });\n } else if (event.type === \"toolcall_end\") {\n sawDelta = true;\n attemptEvents.push({ type: \"tool_call\", run_id: runId, tool_call: event.tool_call });\n } else if (event.type === \"error\") {\n attemptFailed = event.error || \"模型调用失败,原因未知\";\n } else if (event.type === \"done\") {\n final = event.response;\n }\n }\n\n if (attemptFailed === null) {\n buffered = attemptEvents; // 成功:保留本次增量,重放给订阅者\n break;\n }\n\n // 失败:没有任何增量流出且还可重试 → 丢弃本次缓冲重来\n const retryable = !sawDelta\n && attempt < maxStepAttempts\n && isTransientLLMError(attemptFailed)\n && !runOpts.signal?.aborted;\n if (retryable) {\n this.logger.warn(`Agent LLM 调用失败(重试 ${attempt + 1}/${maxStepAttempts})run=${runId}:${attemptFailed}`);\n buffered = null;\n continue;\n }\n // 不可重试:重放缓冲(若有)后按原语义报错\n buffered = attemptEvents;\n for (const event of buffered) yield event;\n this.logger.warn(`Agent 运行失败 run=${runId}:${attemptFailed}`);\n yield { type: \"agent_error\", run_id: runId, error: attemptFailed };\n return;\n }\n\n // 成功路径:重放本次产生的全部增量事件\n for (const event of buffered ?? []) yield event;\n buffered = null;\n\n if (runOpts.signal?.aborted) return;\n if (!final) {\n yield { type: \"agent_error\", run_id: runId, error: \"模型流异常终止,未返回结果\" };\n return;\n }\n usage = addUsage(usage, final.usage);\n\n // 循环判据:以 tool_calls 内容为准(finish_reason 只作参考)\n if (final.tool_calls.length === 0) {\n await this.notify(responseToMessage(final), final);\n const result: AgentDone = {\n text: final.content,\n thinking: final.thinking,\n finish_reason: final.finish_reason,\n usage,\n steps: step,\n model: final.model,\n provider: final.provider,\n elapsed_ms: Date.now() - started,\n };\n yield { type: \"agent_done\", run_id: runId, result };\n return;\n }\n\n // assistant 消息(含 tool_calls)入上下文,随后逐个执行工具\n messages.push(responseToMessage(final));\n await this.notify(responseToMessage(final), final);\n const stepToolMessages: ChatMessage[] = [];\n let callIndex = 0;\n while (callIndex < final.tool_calls.length) {\n const firstCall = final.tool_calls[callIndex]!;\n const firstTool = this.toolsByName.get(firstCall.name);\n const canRunParallel =\n firstTool?.annotations?.readOnly === true &&\n firstTool.annotations.parallelSafe === true;\n const batch = [firstCall];\n callIndex += 1;\n if (canRunParallel) {\n while (callIndex < final.tool_calls.length) {\n const candidate = final.tool_calls[callIndex]!;\n const tool = this.toolsByName.get(candidate.name);\n if (tool?.annotations?.readOnly !== true || tool.annotations.parallelSafe !== true) break;\n batch.push(candidate);\n callIndex += 1;\n }\n }\n\n const settled = await Promise.allSettled(\n batch.map((tc) => this.executeTool(tc, definitions, {\n signal: runOpts.signal,\n runId,\n })),\n );\n for (const [index, outcome] of settled.entries()) {\n const tc = batch[index]!;\n // 提权协商:工具抛 EscalationRequiredError 时,发协商事件并以\n // agent_cancelled 收尾暂停本轮(assistant 的 tool_calls 已由\n // recorder 终态收尾补配对)。用户确认后由编排层授权并重发续跑。\n let result: Awaited<ReturnType<typeof this.executeTool>>;\n if (outcome.status === \"rejected\") {\n const err = outcome.reason;\n if (err instanceof EscalationRequiredError) {\n const escalation = {\n escalation_id: crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12),\n requested_path: err.requestedPath,\n resolved_path: err.resolvedPath,\n tool_name: tc.name,\n workdir: this.workdirHint,\n resource_type: err.resourceType,\n requested_command: err.requestedCommand,\n };\n // 先落盘(回放时前端才能渲染确认卡片),再发事件\n await this.notifyEscalation(escalation);\n yield { type: \"escalation_request\", run_id: runId, escalation };\n yield { type: \"agent_cancelled\", run_id: runId, reason: \"escalation\" };\n return;\n }\n throw err;\n } else {\n result = outcome.value;\n }\n const toolResult: AgentToolResult = {\n tool_call_id: result.tool_call_id,\n name: result.name,\n output: result.output.slice(0, EVENT_OUTPUT_LIMIT),\n is_error: result.is_error,\n elapsed_ms: result.elapsed_ms,\n };\n yield { type: \"tool_result\", run_id: runId, tool_result: toolResult };\n const toolMessage: ChatMessage = {\n role: \"tool\",\n content: result.output,\n tool_call_id: tc.id,\n name: tc.name,\n ...(result.is_error ? { is_error: true } : {}),\n };\n messages.push(toolMessage);\n stepToolMessages.push(toolMessage);\n await this.notify(toolMessage, null);\n }\n }\n\n // mid-run 检查:本步全部工具结果已回喂、call/output 配对完整,\n // 此刻丢弃历史不会产生孤儿调用,是压缩的安全点。用量以服务端上报为准,\n // 仅对尚未发送的新工具结果补估\n const stepUsage = final.usage.prompt_tokens + final.usage.completion_tokens;\n const contextTokens =\n stepUsage > 0 ? stepUsage + estimateTokens(stepToolMessages) : estimateTokens(messages);\n const midCompact = await this.maybeCompact(\n protocol, runId, modelId, messages, contextTokens, contextWindow, settings,\n );\n if (midCompact) yield midCompact;\n }\n\n this.logger.warn(`Agent 达到最大步数上限 run=${runId} steps=${this.maxSteps}`);\n yield {\n type: \"agent_error\",\n run_id: runId,\n error:\n `已达到最大执行步数上限(${this.maxSteps} 步)仍未完成,运行终止。` +\n \"请把任务拆小后重试,或检查是否陷入了循环。\",\n };\n }\n\n /** 达到水位线时压缩上下文并原地替换 messages,返回压缩事件。\n * 任何失败都降级为「本次不压缩」:记日志后照常返回 null,运行继续。 */\n private async maybeCompact(\n protocol: LlmProtocol,\n runId: string,\n modelId: string,\n messages: ChatMessage[],\n contextTokens: number,\n contextWindow: number | undefined,\n settings: import(\"../llm/models.js\").ModelSettings,\n ): Promise<AgentEvent | null> {\n if (!shouldCompact(contextTokens, contextWindow)) return null;\n let result: CompactionResult | null = null;\n try {\n result = await compact(protocol, modelId, messages, settings);\n } catch (err) {\n // 压缩是优化路径,任何故障都不应拖垮运行\n this.logger.warn(`上下文压缩发生意外错误,本次跳过压缩 run=${runId}:${err instanceof Error ? err.message : err}`);\n return null;\n }\n if (!result) return null;\n // 原地替换:system 保留在首位,其后是重建历史(保留的用户原话 + 摘要)\n messages.splice(0, messages.length, messages[0]!, ...result.replacement_history);\n await this.notifyCompaction(result);\n this.logger.info(\n `上下文已压缩 run=${runId} tokens=${result.tokens_before}→${result.tokens_after}`,\n );\n return {\n type: \"context_compacted\",\n run_id: runId,\n compaction: {\n summary: result.summary,\n tokens_before: result.tokens_before,\n tokens_after: result.tokens_after,\n },\n };\n }\n\n private async notifyCompaction(result: CompactionResult): Promise<void> {\n if (!this.onCompaction) return;\n try {\n await this.onCompaction(result);\n } catch (err) {\n this.logger.warn(`压缩记录持久化回调失败(本次压缩可能未落盘):${err instanceof Error ? err.message : err}`);\n }\n }\n\n private async notifyEscalation(info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type: \"path\" | \"command\";\n requested_command?: string[];\n }): Promise<void> {\n if (!this.onEscalation) return;\n try {\n await this.onEscalation(info);\n } catch (err) {\n this.logger.warn(`提权请求持久化回调失败(本次请求可能未落盘):${err instanceof Error ? err.message : err}`);\n }\n }\n\n private async notify(message: ChatMessage, response: ChatResponse | null): Promise<void> {\n if (!this.onMessage) return;\n try {\n await this.onMessage(message, response);\n } catch (err) {\n this.logger.warn(`Agent 消息持久化回调失败(本条消息可能未落盘):${err instanceof Error ? err.message : err}`);\n }\n }\n\n /** 执行单个工具调用:校验 → 执行;任何失败都转为回喂文本,不抛异常 */\n private async executeTool(\n tc: { id: string; name: string; raw_arguments: string },\n definitions: { name: string; description: string; parameters: Record<string, unknown> }[],\n context: import(\"../tools/types.js\").ToolContext = {},\n ): Promise<{ tool_call_id: string; name: string; output: string; is_error: boolean; elapsed_ms: number }> {\n const started = Date.now();\n const { args, error } = validateToolCall(definitions, tc);\n let output: string;\n let isError: boolean;\n if (error !== null) {\n output = error;\n isError = true;\n } else {\n const tool = this.toolsByName.get(tc.name)!; // validate 已确认工具存在\n try {\n const handled = await tool.handler(args!, context);\n output = truncateMiddle(typeof handled === \"string\" ? handled : handled.content);\n isError = typeof handled === \"string\" ? false : (handled.isError ?? false);\n } catch (err) {\n // 提权信号不上行到普通失败路径——由 runner 转成协商事件\n if (err instanceof EscalationRequiredError) throw err;\n this.logger.warn(`工具执行失败 tool=${tc.name}:${err instanceof Error ? err.message : err}`);\n output = `工具执行失败:${err instanceof Error ? err.message : err}`;\n isError = true;\n }\n }\n return {\n tool_call_id: tc.id,\n name: tc.name,\n output,\n is_error: isError,\n elapsed_ms: Date.now() - started,\n };\n }\n}\n","/**\n * 工具挂点:声明 + 执行器的绑定。\n *\n * 工具的「声明」(definition,暴露给模型)与「执行」(handler,真正干活)\n * 在此绑成一个单元——改行为时提示词与实现不会漂移。handler 约定:\n * - 入参是已通过 JSON Schema 校验的参数 dict;\n * - 返回喂回模型的文本(紧凑、模型可读即可);\n * - 业务失败 throw new Error(中文说明):runner 会把异常转成失败结果\n * 回喂模型,不中断 loop。\n */\nimport type { ToolDefinition } from \"../llm/models.js\";\n\nexport interface ToolAnnotations {\n /** 不修改文件、进程或外部状态。 */\n readOnly: boolean;\n /** 可与同一模型响应中的其他只读工具并发执行。 */\n parallelSafe: boolean;\n}\n\nexport interface ToolContext {\n /** 当前 Agent 运行的取消信号;长任务必须主动监听。 */\n signal?: AbortSignal;\n /** 当前运行编号,供进程会话与诊断日志关联。 */\n runId?: string;\n}\n\nexport interface ToolHandlerResult {\n /** 回喂模型的紧凑文本。 */\n content: string;\n /** 工具可显式返回业务失败,而不必抛异常。 */\n isError?: boolean;\n /** 仅供宿主扩展使用;当前消息协议不会把它回喂模型。 */\n metadata?: Record<string, unknown>;\n}\n\nexport interface AgentTool {\n definition: ToolDefinition;\n /** 省略时按“有副作用、不可并行”的保守策略处理。 */\n annotations?: ToolAnnotations;\n /** 字符串返回值继续兼容已有自定义工具。 */\n handler: (\n args: Record<string, unknown>,\n context?: ToolContext,\n ) => Promise<string | ToolHandlerResult>;\n}\n\n/** 工具输出统一上限:单工具单次输出 ≤ 50KB,超限保留头尾(中部截断) */\nexport const TOOL_OUTPUT_MAX_BYTES = 50_000;\n\n/** 中部截断:头尾各留一半预算(头尾信息密度最高),按字节切、退回合法 UTF-8 边界 */\nexport function truncateMiddle(text: string, maxBytes = TOOL_OUTPUT_MAX_BYTES): string {\n const data = Buffer.from(text, \"utf-8\");\n if (data.length <= maxBytes) return text;\n const half = Math.floor(maxBytes / 2);\n const head = data.subarray(0, half).toString(\"utf-8\");\n const tail = data.subarray(data.length - half).toString(\"utf-8\");\n const omitted = Math.floor((data.length - maxBytes) / 4);\n return `${head}\\n…(中间约 ${omitted} token 已截断)…\\n${tail}`;\n}\n","/**\n * 路径提权协商 —— 沙箱硬闸与「用户明确授权」之间的桥梁。\n *\n * 设计(与沙箱的关系):\n * - resolveSandboxed 的硬闸不变:默认一切越界访问都被拦下;\n * - 新增「提权请求」通道:工具 handler 在拒绝时抛出 EscalationRequiredError\n * (携带目标路径),runner 捕获后不发 tool_result,而是发 escalation_request\n * 事件并暂停本轮运行;用户在前端确认后,服务端把路径登记进会话级授权\n * 清单并自动重发上一条用户消息(续跑);\n * - 授权粒度是「会话 × 路径前缀」,随会话生命周期存在(不落盘到全局配置,\n * 重启服务即失效)——宁可每次新会话重新确认,也不留持久的越界后门。\n */\n\nimport path from \"node:path\";\n\nexport const COMMAND_EXECUTION_GRANT = \"capability://exec_command\";\n\nexport type EscalationResourceType = \"path\" | \"command\";\n\n/** 工具层抛出的提权信号(runner 识别它并转成协商流程,不作为普通工具失败回喂) */\nexport class EscalationRequiredError extends Error {\n constructor(\n /** 请求访问的原始路径(用户或模型给出的形态,用于展示) */\n public readonly requestedPath: string,\n /** 沙箱解析后的绝对路径(授权登记的键) */\n public readonly resolvedPath: string,\n message?: string,\n public readonly resourceType: EscalationResourceType = \"path\",\n public readonly requestedCommand?: string[],\n ) {\n super(message ?? (resourceType === \"command\"\n ? \"执行本机命令需要用户授权\"\n : `路径超出工作区范围,需要用户授权:${resolvedPath}`));\n this.name = \"EscalationRequiredError\";\n }\n}\n\n/**\n * 会话级路径授权登记表(进程内)。\n * key = sessionId,value = 已授权的路径前缀集合(realpath 后的绝对路径)。\n */\nexport class EscalationGrants {\n private readonly grants = new Map<string, Set<string>>();\n private readonly oneShotGrants = new Map<string, Set<string>>();\n /** 会话级完全访问开关(前端 permission_mode=full 注入;ask 时撤销,不随消息残留) */\n private readonly fullAccess = new Set<string>();\n\n /** 完全访问模式:跳过一切路径与能力提权检查(用户已在 UI 二次确认) */\n setFullAccess(sessionId: string, enabled: boolean): void {\n if (enabled) {\n this.fullAccess.add(sessionId);\n } else {\n this.fullAccess.delete(sessionId);\n }\n }\n\n hasFullAccess(sessionId: string): boolean {\n return this.fullAccess.has(sessionId);\n }\n\n grant(sessionId: string, resolvedPath: string): void {\n let set = this.grants.get(sessionId);\n if (!set) {\n set = new Set();\n this.grants.set(sessionId, set);\n }\n set.add(resolvedPath);\n }\n\n grantCapability(sessionId: string, capability: string): void {\n this.grant(sessionId, capability);\n }\n\n grantOnce(sessionId: string, resolvedPath: string): void {\n let set = this.oneShotGrants.get(sessionId);\n if (!set) {\n set = new Set();\n this.oneShotGrants.set(sessionId, set);\n }\n set.add(resolvedPath);\n }\n\n grantCapabilityOnce(sessionId: string, capability: string): void {\n this.grantOnce(sessionId, capability);\n }\n\n /** 已授权路径或其子路径视为已放开;完全访问模式直接放行 */\n isGranted(sessionId: string, resolvedPath: string): boolean {\n if (this.fullAccess.has(sessionId)) return true;\n const set = this.grants.get(sessionId);\n if (set) {\n for (const prefix of set) {\n const relative = path.relative(prefix, resolvedPath);\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) return true;\n }\n }\n const oneShot = this.oneShotGrants.get(sessionId);\n if (oneShot?.has(resolvedPath)) {\n oneShot.delete(resolvedPath);\n if (oneShot.size === 0) this.oneShotGrants.delete(sessionId);\n return true;\n }\n return false;\n }\n\n isCapabilityGranted(sessionId: string, capability: string): boolean {\n if (this.fullAccess.has(sessionId)) return true;\n if (this.grants.get(sessionId)?.has(capability)) return true;\n const oneShot = this.oneShotGrants.get(sessionId);\n if (!oneShot?.has(capability)) return false;\n oneShot.delete(capability);\n if (oneShot.size === 0) this.oneShotGrants.delete(sessionId);\n return true;\n }\n\n /** 会话删除时清掉授权(授权随会话生命周期) */\n drop(sessionId: string): void {\n this.grants.delete(sessionId);\n this.oneShotGrants.delete(sessionId);\n this.fullAccess.delete(sessionId);\n }\n}\n","/**\n * 内置工具集:文件读写、精确编辑、内容搜索,以及需要授权的本机命令会话工具。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { EscalationGrants } from \"../agent/escalation.js\";\nimport type { SkillInfo } from \"../context/skills.js\";\nimport { makeApplyPatchTool } from \"./apply-patch.js\";\nimport { makeCreateTool } from \"./create.js\";\nimport { makeEditTool } from \"./edit.js\";\nimport { makeExecCommandTool } from \"./exec-command.js\";\nimport { makeListTool } from \"./list.js\";\nimport { makeLoadSkillTool } from \"./load-skill.js\";\nimport { makeReadTool } from \"./read.js\";\nimport { makeSearchTool } from \"./search.js\";\nimport { ProcessManager } from \"./process-manager.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { makeWriteTool } from \"./write.js\";\nimport { makeWriteStdinTool } from \"./write-stdin.js\";\n\nexport interface BuiltinToolsOptions {\n /** 工作目录:相对路径解析基准 + 沙箱边界 */\n workdir: string;\n /** 显式放开沙箱(默认 false:全部路径限制在 workdir 内) */\n allowOutsideWorkdir?: boolean;\n /** 会话级路径授权清单(与 sessionId 一起提供时生效) */\n grants?: EscalationGrants;\n /** 当前会话 id(授权清单的查询键) */\n sessionId?: string;\n /** 预授权本机命令执行;关闭时工具仍会声明,但首次调用触发提权协商。 */\n enableCommandExecution?: boolean;\n /** 当前会话已发现的 skills;非空时注册 load_skill */\n skills?: SkillInfo[];\n}\n\nexport function builtinTools(opts: BuiltinToolsOptions): AgentTool[] {\n const workdir = path.resolve(opts.workdir);\n fs.mkdirSync(workdir, { recursive: true });\n const sandbox = {\n allowOutsideWorkdir: opts.allowOutsideWorkdir ?? false,\n grants: opts.grants,\n sessionId: opts.sessionId,\n };\n const tools: AgentTool[] = [\n makeListTool(workdir, sandbox),\n makeReadTool(workdir, sandbox),\n makeSearchTool(workdir, sandbox),\n makeCreateTool(workdir, sandbox),\n makeEditTool(workdir, sandbox),\n makeWriteTool(workdir, sandbox),\n makeApplyPatchTool(workdir, sandbox),\n ];\n const commandSandbox = { ...sandbox, commandExecutionEnabled: opts.enableCommandExecution ?? false };\n const processes = new ProcessManager();\n tools.push(\n makeExecCommandTool(workdir, processes, commandSandbox),\n makeWriteStdinTool(processes, commandSandbox),\n );\n if (opts.skills && opts.skills.length > 0) {\n tools.push(makeLoadSkillTool(opts.skills));\n }\n return tools;\n}\n\nexport type { AgentTool, ToolAnnotations, ToolContext, ToolHandlerResult } from \"./types.js\";\nexport { makeLoadSkillTool } from \"./load-skill.js\";\nexport { makeListTool } from \"./list.js\";\nexport { makeReadTool } from \"./read.js\";\nexport { makeCreateTool } from \"./create.js\";\nexport { makeApplyPatchTool } from \"./apply-patch.js\";\nexport { makeEditTool } from \"./edit.js\";\nexport { makeSearchTool } from \"./search.js\";\nexport { makeExecCommandTool, formatProcessResult } from \"./exec-command.js\";\nexport { makeWriteStdinTool } from \"./write-stdin.js\";\nexport { ProcessManager } from \"./process-manager.js\";\nexport { makeWriteTool } from \"./write.js\";\nexport { resolveSandboxed } from \"./workdir.js\";\nexport type { SandboxOptions } from \"./sandbox-types.js\";\n","/** 多文件补丁工具:解析 Codex 风格补丁,全部预校验后再原子落盘。 */\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst argsSchema = z.object({ patch: z.string().min(1) });\n\ntype PatchOperation =\n | { kind: \"add\"; rawPath: string; file: string; content: string }\n | { kind: \"delete\"; rawPath: string; file: string }\n | { kind: \"update\"; rawPath: string; file: string; hunks: Hunk[] };\n\ninterface Hunk {\n before: string[];\n after: string[];\n}\n\ninterface PreparedWrite {\n kind: \"add\" | \"update\";\n rawPath: string;\n file: string;\n content: string;\n}\n\nexport function makeApplyPatchTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"apply_patch\",\n description:\n \"应用 Codex 风格的多文件补丁。输入须以 *** Begin Patch 开始、*** End Patch 结束,\" +\n \"支持 *** Add File、*** Update File、*** Delete File。所有文件先校验,任何一处失败都不会写入。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { patch } = argsSchema.parse(args);\n const operations = parsePatch(patch, workdir, sandbox);\n const writes: PreparedWrite[] = [];\n const deletes: Array<{ rawPath: string; file: string }> = [];\n\n for (const operation of operations) {\n if (operation.kind === \"add\") {\n if (fs.existsSync(operation.file)) throw new Error(`新增文件已存在:${operation.rawPath}`);\n writes.push({ ...operation, kind: \"add\" });\n } else if (operation.kind === \"delete\") {\n assertRegularFile(operation.rawPath, operation.file);\n deletes.push(operation);\n } else {\n assertRegularFile(operation.rawPath, operation.file);\n let content = fs.readFileSync(operation.file, \"utf-8\");\n for (const hunk of operation.hunks) content = applyHunk(content, hunk, operation.rawPath);\n writes.push({ kind: \"update\", rawPath: operation.rawPath, file: operation.file, content });\n }\n }\n\n const staged: Array<PreparedWrite & { tmp: string }> = [];\n try {\n for (const write of writes) staged.push(stageWrite(write));\n } catch (err) {\n for (const item of staged) fs.rmSync(item.tmp, { force: true });\n throw err;\n }\n const backups = new Map<string, string>();\n const installedAdds: string[] = [];\n try {\n for (const item of staged) {\n if (item.kind === \"update\") {\n const backup = backupPath(item.file);\n fs.renameSync(item.file, backup);\n backups.set(item.file, backup);\n } else {\n installedAdds.push(item.file);\n }\n fs.mkdirSync(path.dirname(item.file), { recursive: true });\n fs.renameSync(item.tmp, item.file);\n }\n for (const deletion of deletes) {\n const backup = backupPath(deletion.file);\n fs.renameSync(deletion.file, backup);\n backups.set(deletion.file, backup);\n }\n } catch (err) {\n for (const item of staged) fs.rmSync(item.tmp, { force: true });\n for (const file of installedAdds) fs.rmSync(file, { force: true });\n for (const [file, backup] of [...backups].reverse()) {\n fs.rmSync(file, { force: true });\n if (fs.existsSync(backup)) fs.renameSync(backup, file);\n }\n throw err;\n }\n for (const backup of backups.values()) fs.rmSync(backup, { force: true });\n\n const summary = operations.map((operation) => `${operation.kind} ${operation.rawPath}`).join(\"\\n\");\n return `补丁已应用(${operations.length} 个文件):\\n${summary}`;\n },\n };\n}\n\nfunction parsePatch(patch: string, workdir: string, sandbox: SandboxOptions): PatchOperation[] {\n const lines = patch.replace(/\\r\\n/g, \"\\n\").split(\"\\n\");\n if (lines[0] !== \"*** Begin Patch\") throw new Error(\"补丁必须以 *** Begin Patch 开始\");\n const end = lines.lastIndexOf(\"*** End Patch\");\n if (end < 0) throw new Error(\"补丁缺少 *** End Patch\");\n if (lines.slice(end + 1).some((line) => line.trim())) throw new Error(\"*** End Patch 后不能有内容\");\n\n const operations: PatchOperation[] = [];\n const seen = new Set<string>();\n let index = 1;\n while (index < end) {\n if (!lines[index]) {\n index += 1;\n continue;\n }\n const header = lines[index]!;\n const matched = header.match(/^\\*\\*\\* (Add|Update|Delete) File: (.+)$/);\n if (!matched) throw new Error(`无法识别的补丁行 ${index + 1}:${header}`);\n const kind = matched[1]!.toLowerCase() as PatchOperation[\"kind\"];\n const rawPath = matched[2]!.trim();\n if (!rawPath) throw new Error(`补丁第 ${index + 1} 行缺少文件路径`);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (seen.has(file)) throw new Error(`同一补丁不能多次操作文件:${rawPath}`);\n seen.add(file);\n index += 1;\n\n const body: string[] = [];\n while (index < end && !lines[index]!.startsWith(\"*** \")) {\n body.push(lines[index]!);\n index += 1;\n }\n if (kind === \"add\") {\n if (body.some((line) => !line.startsWith(\"+\"))) {\n throw new Error(`新增文件 ${rawPath} 的每一行都必须以 + 开头`);\n }\n operations.push({ kind, rawPath, file, content: body.map((line) => line.slice(1)).join(\"\\n\") });\n } else if (kind === \"delete\") {\n if (body.some((line) => line.length > 0)) throw new Error(`删除文件 ${rawPath} 不接受补丁正文`);\n operations.push({ kind, rawPath, file });\n } else {\n const hunks = parseHunks(body, rawPath);\n operations.push({ kind, rawPath, file, hunks });\n }\n }\n if (operations.length === 0) throw new Error(\"补丁不包含任何文件操作\");\n return operations;\n}\n\nfunction parseHunks(lines: string[], rawPath: string): Hunk[] {\n const hunks: Hunk[] = [];\n let current: Hunk | null = null;\n for (const line of lines) {\n if (line.startsWith(\"@@\")) {\n current = { before: [], after: [] };\n hunks.push(current);\n continue;\n }\n if (!current) throw new Error(`更新文件 ${rawPath} 的正文必须从 @@ 开始`);\n const marker = line[0];\n const text = line.slice(1);\n if (marker === \" \") {\n current.before.push(text);\n current.after.push(text);\n } else if (marker === \"-\") {\n current.before.push(text);\n } else if (marker === \"+\") {\n current.after.push(text);\n } else {\n throw new Error(`更新文件 ${rawPath} 包含非法补丁行:${line}`);\n }\n }\n if (hunks.length === 0) throw new Error(`更新文件 ${rawPath} 缺少 @@ hunk`);\n return hunks;\n}\n\nfunction applyHunk(content: string, hunk: Hunk, rawPath: string): string {\n const before = hunk.before.join(\"\\n\");\n const after = hunk.after.join(\"\\n\");\n if (!before) throw new Error(`更新文件 ${rawPath} 的 hunk 缺少上下文或删除行`);\n const first = content.indexOf(before);\n if (first < 0) throw new Error(`更新文件 ${rawPath} 时未找到 hunk 上下文`);\n if (content.indexOf(before, first + before.length) >= 0) {\n throw new Error(`更新文件 ${rawPath} 的 hunk 上下文不唯一`);\n }\n return content.slice(0, first) + after + content.slice(first + before.length);\n}\n\nfunction assertRegularFile(rawPath: string, file: string): void {\n if (!fs.existsSync(file)) throw new Error(`文件不存在:${rawPath}`);\n if (!fs.statSync(file).isFile()) throw new Error(`${rawPath} 不是普通文件`);\n}\n\nfunction stageWrite(write: PreparedWrite): PreparedWrite & { tmp: string } {\n fs.mkdirSync(path.dirname(write.file), { recursive: true });\n const tmp = path.join(path.dirname(write.file), `.xlyra-tmp-${crypto.randomUUID()}${path.extname(write.file)}`);\n fs.writeFileSync(tmp, write.content);\n return { ...write, tmp };\n}\n\nfunction backupPath(file: string): string {\n return path.join(path.dirname(file), `.xlyra-backup-${crypto.randomUUID()}${path.extname(file)}`);\n}\n","/**\n * 工作区沙箱:四个文件工具共用的路径解析。\n *\n * 默认全部路径限制在 workdir 内:相对路径基于 workdir 解析;解析结果经\n * realpath 校验仍须落在 workdir 内——**含符号链接逃逸拦截**(指向 workdir\n * 外的符号链接会被拒绝)。\n *\n * 越界时的行为分两层:\n * - 无授权 → 抛 EscalationRequiredError(runner 转成提权协商事件,等待用户确认);\n * - 会话级授权清单(grants)已覆盖该路径 → 放行;\n * - allowOutsideWorkdir 显式放开(本机部署的完全信任模式)→ 直接放行。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { EscalationRequiredError, type EscalationGrants } from \"../agent/escalation.js\";\n\n/**\n * 解析目标路径并做沙箱校验;返回可直接用于 fs 操作的绝对路径。\n * 目标不存在时(create 场景):取最深的已存在祖先做 realpath,再拼回剩余段。\n */\nexport function resolveSandboxed(\n workdir: string,\n raw: string,\n opts: {\n allowOutsideWorkdir?: boolean;\n /** 会话级授权清单(提供 sessionId 时生效) */\n grants?: EscalationGrants;\n sessionId?: string;\n } = {},\n): string {\n const baseReal = fs.realpathSync(workdir);\n const candidate = path.resolve(path.isAbsolute(raw) ? raw : path.join(baseReal, raw));\n if (opts.allowOutsideWorkdir) return candidate;\n\n // 目标或最深已存在祖先的 realpath(处理符号链接与 .. 逃逸)\n let existing = candidate;\n const missing: string[] = [];\n while (!fs.existsSync(existing)) {\n missing.unshift(path.basename(existing));\n const parent = path.dirname(existing);\n if (parent === existing) break; // 已到根\n existing = parent;\n }\n const existingReal = fs.realpathSync(existing);\n const realTarget = path.join(existingReal, ...missing);\n\n if (realTarget !== baseReal && !realTarget.startsWith(baseReal + path.sep)) {\n // 会话级授权覆盖 → 放行\n if (opts.grants && opts.sessionId && opts.grants.isGranted(opts.sessionId, realTarget)) {\n return realTarget;\n }\n throw new EscalationRequiredError(raw, realTarget);\n }\n return realTarget;\n}\n","/**\n * create 工具:新建文件(已存在则失败)。\n *\n * 与 write 形成对称硬闸:create 只建不覆盖(wx 语义),write 只覆盖不新建。\n * 设计意图是把「覆盖已有内容」变成模型必须显式选择的动作,防误覆盖。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst argsSchema = z.object({\n path: z.string(),\n content: z.string(),\n});\n\nexport function makeCreateTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"create\",\n description:\n \"新建文件并写入内容(自动创建父目录)。目标已存在时失败——\" +\n \"如需修改已有文件请用 write 工具。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { path: rawPath, content } = argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n fs.mkdirSync(path.dirname(file), { recursive: true });\n try {\n fs.writeFileSync(file, content, { flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n throw new Error(`文件已存在:${rawPath};如需修改请用 write 工具`);\n }\n throw err;\n }\n return `已创建 ${rawPath}(${content.length} 字符,${content.split(\"\\n\").length} 行)`;\n },\n };\n}\n","/** 精确编辑工具:old_text 唯一命中替换,避免整文件重写。 */\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst argsSchema = z.object({\n path: z.string(),\n old_text: z.string().min(1),\n new_text: z.string(),\n replace_all: z.boolean().default(false),\n});\n\nexport function makeEditTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"edit\",\n description:\n \"精确修改已有文本文件。默认要求 old_text 在文件中恰好出现一次;\" +\n \"未命中或多次命中都会失败。确需替换全部匹配时传 replace_all=true。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { path: rawPath, old_text: oldText, new_text: newText, replace_all: replaceAll } =\n argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(file)) throw new Error(`文件不存在:${rawPath}`);\n if (fs.statSync(file).isDirectory()) throw new Error(`${rawPath} 是目录不是文件`);\n\n const original = fs.readFileSync(file, \"utf-8\");\n const matches = countMatches(original, oldText);\n if (matches === 0) throw new Error(`未找到要替换的 old_text:${rawPath}`);\n if (!replaceAll && matches !== 1) {\n throw new Error(\n `old_text 在 ${rawPath} 中出现 ${matches} 次;请提供更长的唯一上下文,` +\n \"或明确传 replace_all=true\",\n );\n }\n\n const first = original.indexOf(oldText);\n const updated = replaceAll\n ? original.split(oldText).join(newText)\n : original.slice(0, first) + newText + original.slice(first + oldText.length);\n atomicReplace(file, updated);\n return `已编辑 ${rawPath}(替换 ${replaceAll ? matches : 1} 处)`;\n },\n };\n}\n\nfunction countMatches(text: string, needle: string): number {\n let count = 0;\n let cursor = 0;\n while (true) {\n const index = text.indexOf(needle, cursor);\n if (index < 0) return count;\n count += 1;\n cursor = index + needle.length;\n }\n}\n\nfunction atomicReplace(file: string, content: string): void {\n const tmp = path.join(path.dirname(file), `.xlyra-tmp-${crypto.randomUUID()}${path.extname(file)}`);\n try {\n fs.writeFileSync(tmp, content);\n fs.renameSync(tmp, file);\n } catch (err) {\n fs.rmSync(tmp, { force: true });\n throw err;\n }\n}\n","import fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { COMMAND_EXECUTION_GRANT, EscalationRequiredError } from \"../agent/escalation.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport { ProcessManager, type ProcessPollResult } from \"./process-manager.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst argsSchema = z.object({\n command: z.array(z.string()).min(1),\n cwd: z.string().default(\".\"),\n timeout_ms: z.number().int().min(100).max(1_800_000).default(300_000),\n yield_time_ms: z.number().int().min(0).max(600_000).default(10_000),\n max_output_bytes: z.number().int().min(1_000).max(100_000).default(50_000),\n});\n\nexport function makeExecCommandTool(\n workdir: string,\n manager: ProcessManager,\n sandbox: SandboxOptions = {},\n): AgentTool {\n return {\n definition: {\n name: \"exec_command\",\n description:\n \"直接执行命令 argv,不经过 shell。command 必须是字符串数组,例如 \" +\n '[\"pnpm\",\"test\"]。预计执行较久的命令(克隆仓库、安装依赖、构建等)' +\n \"务必把 yield_time_ms 和 timeout_ms 都设大(最高分别为 600000 和 1800000):\" +\n \"进程一结束调用就立即返回,不会白等。只有超过 yield_time_ms 仍在运行时\" +\n \"才返回 session_id,此时用 write_stdin 以较长 yield_time_ms(如 120000)继续等待,\" +\n \"不要短时间反复轮询。执行前可能需要用户授权。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args, context) => {\n const parsed = argsSchema.parse(args);\n const commandAllowed = sandbox.commandExecutionEnabled === true\n || (sandbox.grants !== undefined && sandbox.sessionId !== undefined\n && sandbox.grants.isCapabilityGranted(sandbox.sessionId, COMMAND_EXECUTION_GRANT));\n if (!commandAllowed) {\n throw new EscalationRequiredError(\n parsed.command.join(\" \"),\n COMMAND_EXECUTION_GRANT,\n \"执行本机命令需要用户授权\",\n \"command\",\n parsed.command,\n );\n }\n const cwd = resolveSandboxed(workdir, parsed.cwd, sandbox);\n if (!fs.existsSync(cwd)) throw new Error(`工作目录不存在:${parsed.cwd}`);\n if (!fs.statSync(cwd).isDirectory()) throw new Error(`cwd 不是目录:${parsed.cwd}`);\n const sessionId = manager.start({\n command: parsed.command,\n cwd,\n timeoutMs: parsed.timeout_ms,\n signal: context?.signal,\n });\n const result = await manager.poll(sessionId, parsed.yield_time_ms, parsed.max_output_bytes);\n return formatProcessResult(result);\n },\n };\n}\n\nexport function formatProcessResult(result: ProcessPollResult): { content: string; isError: boolean } {\n const sections = [\n `session_id: ${result.sessionId}`,\n result.running\n ? \"status: running\"\n : `status: exited${result.exitCode !== null ? `\\nexit_code: ${result.exitCode}` : \"\"}` +\n `${result.exitSignal ? `\\nexit_signal: ${result.exitSignal}` : \"\"}`,\n ];\n if (result.output) sections.push(`output:\\n${result.output}`);\n else sections.push(\"output: (暂无新输出)\");\n if (result.error) sections.push(`error: ${result.error}`);\n return {\n content: sections.join(\"\\n\"),\n isError: Boolean(result.error) || (!result.running && result.exitCode !== null && result.exitCode !== 0),\n };\n}\n","import crypto from \"node:crypto\";\nimport { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { truncateMiddle } from \"./types.js\";\n\nconst TRANSCRIPT_MAX_CHARS = 200_000;\nconst COMPLETED_SESSION_RETENTION_MS = 60 * 60 * 1000;\nconst MAX_SESSIONS = 128;\n\ninterface ProcessSession {\n id: string;\n child: ChildProcessWithoutNullStreams;\n output: string;\n readCursor: number;\n exitCode: number | null;\n exitSignal: NodeJS.Signals | null;\n error: string | null;\n completedAt: number | null;\n done: Promise<void>;\n resolveDone: () => void;\n timeout: ReturnType<typeof setTimeout>;\n abortSignal?: AbortSignal;\n abortListener?: () => void;\n}\n\nexport interface SpawnProcessOptions {\n command: string[];\n cwd: string;\n timeoutMs: number;\n signal?: AbortSignal;\n}\n\nexport interface ProcessPollResult {\n sessionId: string;\n output: string;\n running: boolean;\n exitCode: number | null;\n exitSignal: NodeJS.Signals | null;\n error: string | null;\n}\n\nexport class ProcessManager {\n private readonly sessions = new Map<string, ProcessSession>();\n\n start(options: SpawnProcessOptions): string {\n this.prune();\n if (this.sessions.size >= MAX_SESSIONS) {\n const completed = [...this.sessions.values()]\n .filter((session) => session.completedAt !== null)\n .sort((a, b) => a.completedAt! - b.completedAt!);\n for (const session of completed) {\n this.sessions.delete(session.id);\n if (this.sessions.size < MAX_SESSIONS) break;\n }\n }\n if (this.sessions.size >= MAX_SESSIONS) {\n throw new Error(`进程会话已达到上限(${MAX_SESSIONS});请等待已有命令结束后重试`);\n }\n const id = crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n const child = spawn(options.command[0]!, options.command.slice(1), {\n cwd: options.cwd,\n env: process.env,\n stdio: \"pipe\",\n shell: false,\n });\n let resolveDone = (): void => {};\n const done = new Promise<void>((resolve) => { resolveDone = resolve; });\n const session: ProcessSession = {\n id,\n child,\n output: \"\",\n readCursor: 0,\n exitCode: null,\n exitSignal: null,\n error: null,\n completedAt: null,\n done,\n resolveDone,\n timeout: setTimeout(() => this.terminate(id, \"命令执行超时\"), options.timeoutMs),\n abortSignal: options.signal,\n };\n session.timeout.unref?.();\n this.sessions.set(id, session);\n\n const append = (chunk: Buffer): void => {\n session.output += chunk.toString(\"utf-8\");\n if (session.output.length > TRANSCRIPT_MAX_CHARS) {\n const removed = session.output.length - TRANSCRIPT_MAX_CHARS;\n session.output = session.output.slice(removed);\n session.readCursor = Math.max(0, session.readCursor - removed);\n }\n };\n child.stdout.on(\"data\", append);\n child.stderr.on(\"data\", append);\n child.once(\"error\", (err) => {\n session.error = err.message;\n this.finish(session, child.exitCode, child.signalCode);\n });\n child.once(\"close\", (code, signal) => this.finish(session, code, signal));\n\n if (options.signal) {\n const onAbort = (): void => this.terminate(id, \"命令已取消\");\n session.abortListener = onAbort;\n if (options.signal.aborted) onAbort();\n else options.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n return id;\n }\n\n async poll(sessionId: string, yieldTimeMs: number, maxOutputBytes: number): Promise<ProcessPollResult> {\n const session = this.require(sessionId);\n if (session.child.exitCode === null && session.exitSignal === null && !session.error) {\n await Promise.race([\n session.done,\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, yieldTimeMs);\n timer.unref?.();\n }),\n ]);\n }\n const unread = session.output.slice(session.readCursor);\n session.readCursor = session.output.length;\n return {\n sessionId,\n output: truncateMiddle(unread, maxOutputBytes),\n running: session.child.exitCode === null && session.exitSignal === null && !session.error,\n exitCode: session.exitCode,\n exitSignal: session.exitSignal,\n error: session.error,\n };\n }\n\n write(sessionId: string, chars: string): void {\n const session = this.require(sessionId);\n if (session.child.exitCode !== null || session.exitSignal !== null || session.error) {\n throw new Error(`进程会话已结束:${sessionId}`);\n }\n session.child.stdin.write(chars);\n }\n\n private require(sessionId: string): ProcessSession {\n this.prune();\n const session = this.sessions.get(sessionId);\n if (!session) throw new Error(`进程会话不存在:${sessionId}`);\n return session;\n }\n\n private terminate(sessionId: string, reason: string): void {\n const session = this.sessions.get(sessionId);\n if (!session || session.completedAt !== null) return;\n session.error = reason;\n session.child.kill(\"SIGTERM\");\n const force = setTimeout(() => session.child.kill(\"SIGKILL\"), 1_000);\n force.unref?.();\n }\n\n private finish(\n session: ProcessSession,\n code: number | null,\n signal: NodeJS.Signals | null,\n ): void {\n if (session.completedAt !== null) return;\n clearTimeout(session.timeout);\n session.exitCode = code;\n session.exitSignal = signal;\n session.completedAt = Date.now();\n if (session.abortSignal && session.abortListener) {\n session.abortSignal.removeEventListener(\"abort\", session.abortListener);\n }\n session.resolveDone();\n }\n\n private prune(): void {\n const cutoff = Date.now() - COMPLETED_SESSION_RETENTION_MS;\n for (const [id, session] of this.sessions) {\n if (session.completedAt !== null && session.completedAt <= cutoff) this.sessions.delete(id);\n }\n }\n}\n","/**\n * list 工具:列目录内容。\n *\n * 落地细节:\n * - 内置 ignore 清单(.git / node_modules / dist 等),否则一次递归列目录\n * 可能产出几万行直接打爆上下文;\n * - 单次最多 500 条,截断时附「共 N 条,已省略 M 条」;\n * - 输出相对 workdir 的路径,目录带 / 后缀;\n * - pattern 是简化 glob:* 匹配段内任意字符,** 跨段匹配,? 匹配单字符。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst MAX_ENTRIES = 500;\n\nconst IGNORE_NAMES = new Set([\n \".git\",\n \"node_modules\",\n \"dist\",\n \".next\",\n \"out\",\n \"coverage\",\n \".turbo\",\n \".cache\",\n \"__pycache__\",\n \".venv\",\n]);\n\nconst argsSchema = z.object({\n path: z.string().default(\".\"),\n recursive: z.boolean().default(false),\n pattern: z.string().optional(),\n});\n\n/** 简化 glob → RegExp(* 段内任意,** 跨段,? 单字符) */\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"\u0000\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/\\?/g, \"[^/]\")\n .replace(/\u0000/g, \".*\");\n return new RegExp(`(^|/)${escaped}$|^${escaped}$`);\n}\n\nexport function makeListTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"list\",\n description:\n \"列出目录内容(文件与子目录,目录带 / 后缀)。默认只列一层,\" +\n `recursive=true 递归列出。内置忽略 .git、node_modules 等目录。` +\n `单次最多返回 ${MAX_ENTRIES} 条,超出时提示省略数量。`,\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: true, parallelSafe: true },\n handler: async (args) => {\n const { path: rawPath, recursive, pattern } = argsSchema.parse(args);\n const dir = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(dir)) throw new Error(`目录不存在:${rawPath}`);\n if (!fs.statSync(dir).isDirectory()) throw new Error(`${rawPath} 是文件不是目录;读取文件请用 read 工具`);\n\n const matcher = pattern ? globToRegExp(pattern) : null;\n const results: string[] = [];\n let omitted = 0;\n\n const walk = (current: string): void => {\n if (results.length >= MAX_ENTRIES) {\n omitted += countRemaining(current, recursive);\n return;\n }\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(current, { withFileTypes: true });\n } catch {\n return; // 无权限等:跳过该目录\n }\n entries.sort((a, b) => a.name.localeCompare(b.name));\n for (const entry of entries) {\n if (IGNORE_NAMES.has(entry.name)) continue;\n const full = path.join(current, entry.name);\n const rel = path.relative(dir, full);\n const display = entry.isDirectory() ? `${rel}/` : rel;\n if (!matcher || matcher.test(display)) {\n if (results.length < MAX_ENTRIES) results.push(display);\n else omitted += 1;\n }\n if (recursive && entry.isDirectory()) walk(full);\n }\n };\n walk(dir);\n\n const header = `目录 ${rawPath} 的内容:`;\n if (results.length === 0) return `${header}\\n(空目录或无匹配项)`;\n const body = results.join(\"\\n\");\n return omitted > 0\n ? `${header}\\n${body}\\n(共 ${results.length + omitted} 条,已省略 ${omitted} 条;可用 pattern 缩小范围)`\n : `${header}\\n${body}`;\n },\n };\n}\n\nfunction countRemaining(dir: string, recursive: boolean): number {\n let count = 0;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return 0;\n }\n for (const entry of entries) {\n if (IGNORE_NAMES.has(entry.name)) continue;\n count += 1;\n if (recursive && entry.isDirectory()) count += countRemaining(path.join(dir, entry.name), true);\n }\n return count;\n}\n","/**\n * load_skill —— 按名称激活已发现的 Agent Skill。\n *\n * 返回结构化正文 + 资源清单(不预读资源)。metadata.retainedContext 供压缩层\n * 识别并在重建历史时保留;正文同时带耐久标记,跨 run 续聊也能靠消息内容识别。\n */\nimport path from \"node:path\";\nimport { loadSkillContent, type SkillInfo } from \"../context/skills.js\";\nimport type { AgentTool } from \"./types.js\";\nimport {\n RETAINED_CONTEXT_END,\n RETAINED_CONTEXT_START,\n type RetainedContextBlock,\n} from \"../agent/retained-context.js\";\n\nfunction escapeXml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n\nexport function makeLoadSkillTool(skills: SkillInfo[]): AgentTool {\n const byName = new Map(skills.map((skill) => [skill.name, skill]));\n const names = skills.map((skill) => skill.name);\n\n return {\n definition: {\n name: \"load_skill\",\n description:\n \"按名称激活一个 Agent Skill,返回 SKILL.md 全文和可按需读取的资源相对路径列表。\" +\n \"仅在任务匹配 skill 描述时调用;不要猜测未列出的名称。\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n enum: names,\n description: \"要激活的 skill 名称(必须是当前会话已发现的名称)\",\n },\n },\n required: [\"name\"],\n additionalProperties: false,\n },\n },\n annotations: { readOnly: true, parallelSafe: false },\n handler: async (args) => {\n const name = String(args.name ?? \"\");\n const info = byName.get(name);\n if (!info) throw new Error(`未知 skill:${name}`);\n\n const loaded = loadSkillContent(info);\n const resourceLines =\n loaded.resources.length > 0\n ? loaded.resources.map((rel) => `- ${path.join(info.root, rel)}`).join(\"\\n\")\n : \"(无额外资源)\";\n\n const body = [\n `<skill_content name=\"${escapeXml(info.name)}\">`,\n loaded.content.trimEnd(),\n \"\",\n `Skill directory: ${info.root}`,\n \"Relative paths in this skill are relative to the skill directory.\",\n \"<skill_resources>\",\n ...loaded.resources.map((rel) => ` <file>${escapeXml(rel)}</file>`),\n \"</skill_resources>\",\n \"</skill_content>\",\n ...(loaded.warnings.length > 0\n ? [\"\", \"加载告警:\", ...loaded.warnings.map((warning) => `- ${warning}`)]\n : []),\n \"\",\n \"资源绝对路径(未读取内容):\",\n resourceLines,\n ].join(\"\\n\");\n\n const retained: RetainedContextBlock = {\n key: `skill:${info.name}`,\n content: body,\n };\n\n return {\n content: `${RETAINED_CONTEXT_START} ${retained.key}\\n${body}\\n${RETAINED_CONTEXT_END}`,\n metadata: { retainedContext: retained },\n };\n },\n };\n}\n","/**\n * Agent Skills 发现与解析(对齐 https://agentskills.io/specification)。\n *\n * 实现要点(见官方 client-implementation 指南):\n * - 只扫描各 skills 根下的一级子目录中名为 SKILL.md 的文件;\n * - 渐进披露:启动时只暴露 name + description;正文在激活时再读;\n * - 项目级路径优先于用户级;同名后者忽略并告警;\n * - 解析严格遵循规范,单个无效 skill 跳过并告警,不阻断其他 skill。\n */\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\n\n/** 激活时资源清单上限 */\nexport const SKILL_RESOURCE_LIST_LIMIT = 200;\n/** 资源目录递归最大深度 */\nexport const SKILL_RESOURCE_MAX_DEPTH = 8;\n/** 宿主显式启用截断时的建议上限;默认加载不截断 SKILL.md。 */\nexport const SKILL_MD_MAX_BYTES = 32_000;\n/** 单次发现最多暴露的 skill 数量 */\nexport const SKILL_DISCOVERY_LIMIT = 200;\n/** Skill catalog 的总字节上限,避免大量描述占满 system prompt。 */\nexport const SKILL_CATALOG_MAX_BYTES = 32_000;\n\nconst NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport interface SkillInfo {\n name: string;\n description: string;\n /** skill 目录绝对路径 */\n root: string;\n /** SKILL.md 绝对路径 */\n skillFile: string;\n /** 来源作用域:project 覆盖 user / extra */\n scope: \"project\" | \"user\" | \"extra\";\n license?: string;\n compatibility?: string;\n metadata?: Record<string, string>;\n /** 官方实验字段;本实现解析但不强制执行 */\n allowedTools?: string;\n warnings: string[];\n}\n\nexport interface SkillsContext {\n skills: SkillInfo[];\n warnings: string[];\n}\n\nexport interface DiscoverSkillsOptions {\n /** 额外 skills 根目录(优先级低于标准项目/用户路径,高于冲突时被标准路径压制) */\n extraDirs?: string[];\n /** 覆盖默认 home(测试用) */\n homeDir?: string;\n}\n\nexport interface LoadedSkillContent {\n /** SKILL.md 全文(含 frontmatter);超限时为合法 UTF-8 前缀 */\n content: string;\n /** 相对 skill 根的资源路径(不含 SKILL.md),跳过符号链接 */\n resources: string[];\n /** 正文是否因上限被截断 */\n contentTruncated: boolean;\n /** 资源清单是否因数量或深度上限被截断 */\n resourcesTruncated: boolean;\n /** 加载阶段的可恢复告警 */\n warnings: string[];\n}\n\ninterface SkillRoot {\n dir: string;\n scope: SkillInfo[\"scope\"];\n}\n\nfunction skillRoots(workdir: string, opts: DiscoverSkillsOptions): SkillRoot[] {\n const home = opts.homeDir ?? os.homedir();\n const project = path.resolve(workdir);\n const roots: SkillRoot[] = [\n { dir: path.join(project, \".agents\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".xlyra\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".codex\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".claude\", \"skills\"), scope: \"project\" },\n { dir: path.join(project, \".pi\", \"skills\"), scope: \"project\" },\n { dir: path.join(home, \".agents\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".xlyra\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".codex\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".claude\", \"skills\"), scope: \"user\" },\n { dir: path.join(home, \".pi\", \"agent\", \"skills\"), scope: \"user\" },\n ];\n for (const extra of opts.extraDirs ?? []) {\n // 配置中的相对路径以 workdir 为基准,绝对路径保持显式配置的语义。\n roots.push({\n dir: path.isAbsolute(extra) ? path.resolve(extra) : path.resolve(project, extra),\n scope: \"extra\",\n });\n }\n return roots;\n}\n\nfunction stringMap(value: unknown): Record<string, string> | undefined | null {\n if (value === undefined) return undefined;\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const out: Record<string, string> = {};\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n if (typeof entry !== \"string\") return null;\n out[key] = entry;\n }\n return out;\n}\n\nfunction stringField(value: unknown): string | undefined {\n return typeof value === \"string\" ? value.trim() : undefined;\n}\n\nfunction charLength(value: string): number {\n return [...value].length;\n}\n\nfunction parseFrontmatter(text: string): Record<string, unknown> | null {\n const normalized = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n const lines = normalized.split(/\\r?\\n/);\n if (lines[0] !== \"---\") return null;\n const end = lines.findIndex((line, index) => index > 0 && line === \"---\");\n if (end < 0) return null;\n\n let parsed: unknown;\n try {\n parsed = parseYaml(lines.slice(1, end).join(\"\\n\"));\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return null;\n return parsed as Record<string, unknown>;\n}\n\n/**\n * 解析单个 SKILL.md。返回 null 表示应跳过(缺必填或不符合规范)。\n * Skill specification 要求 name 与目录名一致;无效名称不进入 catalog。\n */\nexport function parseSkillFile(skillFile: string, skillRoot: string): SkillInfo | null {\n let text: string;\n try {\n text = fs.readFileSync(skillFile, \"utf-8\");\n } catch (err) {\n throw new Error(`无法读取 ${skillFile}:${err instanceof Error ? err.message : err}`);\n }\n\n const front = parseFrontmatter(text);\n if (!front) return null;\n\n const name = stringField(front.name);\n const description = stringField(front.description);\n if (!name || !description) return null;\n\n const dirName = path.basename(path.resolve(skillRoot));\n if (\n name !== dirName ||\n charLength(name) > 64 ||\n !NAME_PATTERN.test(name) ||\n name.startsWith(\"-\") ||\n name.endsWith(\"-\") ||\n name.includes(\"--\") ||\n charLength(description) > 1024\n ) {\n return null;\n }\n\n const compatibility = stringField(front.compatibility);\n if (front.compatibility !== undefined && (!compatibility || charLength(compatibility) > 500)) {\n return null;\n }\n\n const metadata = stringMap(front.metadata);\n if (metadata === null) return null;\n\n const warnings: string[] = [];\n if (description.length < 1) return null;\n if (typeof front.license !== \"undefined\" && typeof front.license !== \"string\") {\n warnings.push(`skill license 不是字符串:${name}`);\n }\n if (typeof front[\"allowed-tools\"] !== \"undefined\" && typeof front[\"allowed-tools\"] !== \"string\") {\n warnings.push(`skill allowed-tools 不是字符串,已忽略:${name}`);\n }\n\n return {\n name,\n description,\n root: path.resolve(skillRoot),\n skillFile: path.resolve(skillFile),\n scope: \"project\",\n warnings,\n ...(stringField(front.license) ? { license: stringField(front.license) } : {}),\n ...(compatibility ? { compatibility } : {}),\n ...(metadata ? { metadata } : {}),\n ...(stringField(front[\"allowed-tools\"]) ? { allowedTools: stringField(front[\"allowed-tools\"]) } : {}),\n };\n}\n\nexport function discoverSkills(\n workdir: string,\n opts: DiscoverSkillsOptions = {},\n): SkillsContext {\n const skills: SkillInfo[] = [];\n const warnings: string[] = [];\n const seen = new Map<string, SkillInfo>();\n let discovered = 0;\n\n // 扫描顺序:项目 → 用户 → extra;先到先得,项目天然覆盖用户\n for (const { dir, scope } of skillRoots(workdir, opts)) {\n if (discovered >= SKILL_DISCOVERY_LIMIT) {\n warnings.push(`skill 发现达到上限 ${SKILL_DISCOVERY_LIMIT},已停止扫描`);\n break;\n }\n let entries: fs.Dirent[];\n try {\n if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) continue;\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (err) {\n warnings.push(`无法扫描 skills 目录 ${dir}:${err instanceof Error ? err.message : err}`);\n continue;\n }\n\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n if (discovered >= SKILL_DISCOVERY_LIMIT) {\n warnings.push(`skill 发现达到上限 ${SKILL_DISCOVERY_LIMIT},已停止扫描`);\n break;\n }\n if (!entry.isDirectory() || entry.isSymbolicLink()) continue;\n discovered += 1;\n const skillRoot = path.join(dir, entry.name);\n const skillFile = path.join(skillRoot, \"SKILL.md\");\n try {\n const stat = fs.lstatSync(skillFile);\n if (stat.isSymbolicLink() || !stat.isFile()) continue;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n warnings.push(`无法检查 skill 文件:${skillFile}`);\n }\n continue;\n }\n\n let parsed: SkillInfo | null = null;\n try {\n parsed = parseSkillFile(skillFile, skillRoot);\n } catch (err) {\n warnings.push(`无法解析 ${skillFile}:${err instanceof Error ? err.message : err}`);\n continue;\n }\n if (!parsed) {\n warnings.push(`跳过不符合规范的 skill:${skillFile}`);\n continue;\n }\n\n parsed.scope = scope;\n warnings.push(...parsed.warnings);\n\n const existing = seen.get(parsed.name);\n if (existing) {\n warnings.push(\n `skill 名称冲突「${parsed.name}」:保留 ${existing.root},忽略 ${skillRoot}`,\n );\n continue;\n }\n seen.set(parsed.name, parsed);\n skills.push(parsed);\n }\n }\n\n return { skills, warnings };\n}\n\n/** 格式化为系统提示中的 skill 目录;无 skill 时返回空串(勿注入空段)。 */\nexport function formatSkillsCatalog(context: SkillsContext, maxBytes = SKILL_CATALOG_MAX_BYTES): string {\n if (context.skills.length === 0) return \"\";\n const lines = [\n \"# 可用 Agent Skills\",\n \"以下技能提供特定任务的专用指令。任务匹配某 skill 的描述时,先调用 load_skill(name) 加载全文,再按其指引行动。\",\n \"不要臆造未列出的 skill 名。相对路径相对于该 skill 目录;若路径在工作区外,现有文件沙箱仍会生效。\",\n ];\n let omitted = 0;\n for (const [index, skill] of context.skills.entries()) {\n const description = skill.description.replace(/\\s+/g, \" \").trim();\n const fullLine = `- ${skill.name}:${description}(${skill.skillFile})`;\n const compactLine = `- ${skill.name}`;\n if (Buffer.byteLength([...lines, fullLine].join(\"\\n\"), \"utf-8\") <= maxBytes) {\n lines.push(fullLine);\n continue;\n }\n // Keep every discovered name visible even when long descriptions or paths fill the budget.\n if (Buffer.byteLength([...lines, compactLine].join(\"\\n\"), \"utf-8\") <= maxBytes) {\n lines.push(compactLine);\n continue;\n }\n omitted = context.skills.length - index;\n break;\n }\n if (omitted > 0) {\n const marker = `- (skill catalog 已截断,尚有 ${omitted} 个 skill 未列出)`;\n if (Buffer.byteLength([...lines, marker].join(\"\\n\"), \"utf-8\") <= maxBytes) lines.push(marker);\n }\n return boundedUtf8Prefix(Buffer.from(lines.join(\"\\n\"), \"utf-8\"), maxBytes);\n}\n\nfunction boundedUtf8Prefix(data: Buffer, maxBytes: number): string {\n if (data.length <= maxBytes) return data.toString(\"utf-8\");\n let end = Math.max(0, maxBytes);\n while (end > 0) {\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(data.subarray(0, end));\n } catch {\n end -= 1;\n }\n }\n return \"\";\n}\n\n/** 激活时重新读取 SKILL.md,并枚举资源(不预读内容) */\nexport function loadSkillContent(\n info: SkillInfo,\n opts: {\n /** 显式设置时才启用正文截断;默认遵循规范完整读取。 */\n maxBytes?: number;\n resourceLimit?: number;\n maxDepth?: number;\n } = {},\n): LoadedSkillContent {\n const resourceLimit = opts.resourceLimit ?? SKILL_RESOURCE_LIST_LIMIT;\n const maxDepth = opts.maxDepth ?? SKILL_RESOURCE_MAX_DEPTH;\n const data = fs.readFileSync(info.skillFile);\n const contentTruncated = opts.maxBytes !== undefined && data.length > opts.maxBytes;\n const content = opts.maxBytes === undefined\n ? data.toString(\"utf-8\")\n : boundedUtf8Prefix(data, opts.maxBytes);\n const resources: string[] = [];\n const warnings: string[] = [];\n let resourcesTruncated = false;\n\n if (contentTruncated && opts.maxBytes !== undefined) {\n warnings.push(`SKILL.md 超过 ${opts.maxBytes} 字节,已截断注入;完整内容请用 read 工具读取 ${info.skillFile}`);\n }\n\n const walk = (dir: string, relative: string, depth: number): void => {\n if (resources.length >= resourceLimit) {\n resourcesTruncated = true;\n return;\n }\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n warnings.push(`无法扫描 skill 资源目录:${dir}`);\n return;\n }\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n if (resources.length >= resourceLimit) {\n resourcesTruncated = true;\n return;\n }\n if (entry.isSymbolicLink()) continue;\n const rel = relative ? `${relative}/${entry.name}` : entry.name;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (depth >= maxDepth) {\n resourcesTruncated = true;\n continue;\n }\n walk(full, rel, depth + 1);\n continue;\n }\n if (entry.isFile() && rel !== \"SKILL.md\") resources.push(rel.split(path.sep).join(\"/\"));\n }\n };\n\n walk(info.root, \"\", 0);\n if (resourcesTruncated) {\n warnings.push(`skill 资源清单超过限制(最多 ${resourceLimit} 项、深度 ${maxDepth}),仅列出部分路径`);\n }\n\n return { content, resources, contentTruncated, resourcesTruncated, warnings };\n}\n","/**\n * read 工具:读文本文件。\n *\n * 落地细节:\n * - offset(1 起)/ limit 分段读取;单次最多 2000 行或 50KB 先到为准,\n * 截断时在尾部附「继续读请传 offset=N」;\n * - 目录 → 报错并提示用 list;图片后缀 → 明确报错不支持(纯文本管线)。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst MAX_LINES = 2000;\nconst MAX_BYTES = 50_000;\n\nconst IMAGE_SUFFIXES = new Set([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\", \".svg\"]);\n\nconst argsSchema = z.object({\n path: z.string(),\n offset: z.number().int().min(1).default(1),\n limit: z.number().int().min(1).optional(),\n});\n\nexport function makeReadTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"read\",\n description:\n \"读取文本文件内容。单次最多返回 2000 行或 50KB(先到为准),\" +\n \"大文件用 offset/limit 分段读取,直到读完为止。不支持图片。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: true, parallelSafe: true },\n handler: async (args) => {\n const { path: rawPath, offset, limit } = argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(file)) throw new Error(`文件不存在:${rawPath}`);\n if (fs.statSync(file).isDirectory()) {\n throw new Error(`${rawPath} 是目录不是文件;查看目录内容请用 list 工具`);\n }\n if (IMAGE_SUFFIXES.has(path.extname(file).toLowerCase())) {\n throw new Error(\"暂不支持读取图片文件,只支持文本文件\");\n }\n\n const lines = fs.readFileSync(file, \"utf-8\").split(\"\\n\");\n const total = lines.length;\n if (offset > total && total > 0) {\n throw new Error(`offset 超出范围:文件共 ${total} 行,offset=${offset}`);\n }\n const cap = Math.min(limit ?? MAX_LINES, MAX_LINES);\n const window = lines.slice(offset - 1, offset - 1 + cap);\n\n // 字节上限:逐行累加,超限即停\n const picked: string[] = [];\n let size = 0;\n for (const line of window) {\n size += Buffer.byteLength(line, \"utf-8\") + 1;\n if (picked.length > 0 && size > MAX_BYTES) break;\n picked.push(line);\n }\n const end = offset - 1 + picked.length;\n\n let body = picked.join(\"\\n\");\n if (end < total) {\n body += `\\n(文件共 ${total} 行,本次返回第 ${offset}-${end} 行;继续读取请传 offset=${end + 1})`;\n }\n return body || \"(空文件)\";\n },\n };\n}\n","/** 文件内容搜索工具:有界遍历、跳过二进制与常见生成目录。 */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\n\nconst MAX_FILE_BYTES = 2 * 1024 * 1024;\nconst HARD_MAX_RESULTS = 500;\nconst IGNORE_NAMES = new Set([\n \".git\", \"node_modules\", \"dist\", \".next\", \"out\", \"coverage\", \".turbo\", \".cache\",\n \"__pycache__\", \".venv\",\n]);\n\nconst argsSchema = z.object({\n query: z.string().min(1),\n path: z.string().default(\".\"),\n glob: z.string().optional(),\n case_sensitive: z.boolean().default(false),\n max_results: z.number().int().min(1).max(HARD_MAX_RESULTS).default(100),\n});\n\nexport function makeSearchTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"search\",\n description:\n \"在工作区文本文件中搜索内容,返回 path:line:match。可用 glob 按文件路径筛选,\" +\n \"例如 **/*.ts;默认忽略 .git、node_modules、dist 等目录和二进制文件。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: true, parallelSafe: true },\n handler: async (args, context) => {\n const parsed = argsSchema.parse(args);\n const target = resolveSandboxed(workdir, parsed.path, sandbox);\n if (!fs.existsSync(target)) throw new Error(`路径不存在:${parsed.path}`);\n const matcher = parsed.glob ? globToRegExp(parsed.glob) : null;\n const needle = parsed.case_sensitive ? parsed.query : parsed.query.toLocaleLowerCase();\n const results: string[] = [];\n let truncated = false;\n\n const visit = (entryPath: string): void => {\n if (context?.signal?.aborted || results.length >= parsed.max_results) {\n truncated = results.length >= parsed.max_results;\n return;\n }\n const lstat = fs.lstatSync(entryPath);\n if (lstat.isSymbolicLink()) return;\n const stat = lstat;\n if (stat.isDirectory()) {\n for (const entry of fs.readdirSync(entryPath, { withFileTypes: true })) {\n if (IGNORE_NAMES.has(entry.name)) continue;\n visit(path.join(entryPath, entry.name));\n if (results.length >= parsed.max_results || context?.signal?.aborted) break;\n }\n return;\n }\n const relative = path.relative(workdir, entryPath) || path.basename(entryPath);\n const portable = relative.split(path.sep).join(\"/\");\n if (matcher && !matcher.test(portable)) return;\n if (stat.size > MAX_FILE_BYTES || isBinary(entryPath)) return;\n let text: string;\n try {\n text = fs.readFileSync(entryPath, \"utf-8\");\n } catch {\n return;\n }\n for (const [index, line] of text.split(\"\\n\").entries()) {\n const haystack = parsed.case_sensitive ? line : line.toLocaleLowerCase();\n if (!haystack.includes(needle)) continue;\n results.push(`${portable}:${index + 1}:${line}`);\n if (results.length >= parsed.max_results) {\n truncated = true;\n break;\n }\n }\n };\n\n visit(target);\n if (context?.signal?.aborted) throw new Error(\"搜索已取消\");\n if (results.length === 0) return `未找到匹配:${parsed.query}`;\n return results.join(\"\\n\") +\n (truncated ? `\\n(结果已截断到 ${parsed.max_results} 条;请缩小 path 或 glob)` : \"\");\n },\n };\n}\n\nfunction isBinary(file: string): boolean {\n const fd = fs.openSync(file, \"r\");\n try {\n const buffer = Buffer.alloc(4096);\n const read = fs.readSync(fd, buffer, 0, buffer.length, 0);\n return buffer.subarray(0, read).includes(0);\n } finally {\n fs.closeSync(fd);\n }\n}\n\nfunction globToRegExp(glob: string): RegExp {\n let source = \"\";\n for (let index = 0; index < glob.length; index += 1) {\n const char = glob[index]!;\n if (char === \"*\") {\n if (glob[index + 1] === \"*\") {\n if (glob[index + 2] === \"/\") {\n source += \"(?:.*/)?\";\n index += 2;\n } else {\n source += \".*\";\n index += 1;\n }\n } else {\n source += \"[^/]*\";\n }\n } else if (char === \"?\") {\n source += \"[^/]\";\n } else {\n source += char.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\");\n }\n }\n return new RegExp(`^${source}$`);\n}\n","/**\n * write 工具:覆盖写已有文件(不存在则失败)。\n *\n * 与 create 形成对称硬闸(见 create.ts)。写入用临时文件 + rename 原子换入:\n * 写一半进程崩溃要么旧文件完好、要么新文件完整,不留残文件。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { z } from \"zod\";\nimport type { AgentTool } from \"./types.js\";\nimport { resolveSandboxed } from \"./workdir.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\n\nconst argsSchema = z.object({\n path: z.string(),\n content: z.string(),\n});\n\nexport function makeWriteTool(workdir: string, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"write\",\n description:\n \"整体覆盖已有文件的内容。目标不存在时失败——新建文件请用 create 工具。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const { path: rawPath, content } = argsSchema.parse(args);\n const file = resolveSandboxed(workdir, rawPath, sandbox);\n if (!fs.existsSync(file)) {\n throw new Error(`文件不存在:${rawPath};新建文件请用 create 工具`);\n }\n if (fs.statSync(file).isDirectory()) {\n throw new Error(`${rawPath} 是目录不是文件`);\n }\n // 同目录临时文件 + rename:保证原子性(同文件系统内 rename 才原子)\n const tmp = path.join(\n path.dirname(file),\n `.xlyra-tmp-${crypto.randomUUID()}${path.extname(file)}`,\n );\n try {\n fs.writeFileSync(tmp, content);\n fs.renameSync(tmp, file);\n } catch (err) {\n fs.rmSync(tmp, { force: true });\n throw err;\n }\n return `已覆盖 ${rawPath}(${content.length} 字符,${content.split(\"\\n\").length} 行)`;\n },\n };\n}\n","import { z } from \"zod\";\nimport { COMMAND_EXECUTION_GRANT, EscalationRequiredError } from \"../agent/escalation.js\";\nimport type { SandboxOptions } from \"./sandbox-types.js\";\nimport { formatProcessResult } from \"./exec-command.js\";\nimport { ProcessManager } from \"./process-manager.js\";\nimport type { AgentTool } from \"./types.js\";\n\nconst argsSchema = z.object({\n session_id: z.string().min(1),\n chars: z.string().optional(),\n yield_time_ms: z.number().int().min(0).max(600_000).default(30_000),\n max_output_bytes: z.number().int().min(1_000).max(100_000).default(50_000),\n});\n\nexport function makeWriteStdinTool(manager: ProcessManager, sandbox: SandboxOptions = {}): AgentTool {\n return {\n definition: {\n name: \"write_stdin\",\n description:\n \"继续读取 exec_command 返回的进程会话;提供 chars 时先向进程标准输入写入内容。\" +\n \"等待长任务输出时务必把 yield_time_ms 设大(建议 120000,进程结束会立即返回),避免短时间反复空轮询;\" +\n \"仅当需要向进程输入内容时才提供 chars。交互式输入通常需要自行附加换行符。\" +\n \"使用前可能需要用户授权。\",\n parameters: z.toJSONSchema(argsSchema) as Record<string, unknown>,\n },\n annotations: { readOnly: false, parallelSafe: false },\n handler: async (args) => {\n const parsed = argsSchema.parse(args);\n const commandAllowed = sandbox.commandExecutionEnabled === true\n || (sandbox.grants !== undefined && sandbox.sessionId !== undefined\n && sandbox.grants.isCapabilityGranted(sandbox.sessionId, COMMAND_EXECUTION_GRANT));\n if (!commandAllowed) {\n throw new EscalationRequiredError(\n `exec_command session ${parsed.session_id}`,\n COMMAND_EXECUTION_GRANT,\n \"继续命令会话需要用户授权\",\n \"command\",\n );\n }\n if (parsed.chars !== undefined) manager.write(parsed.session_id, parsed.chars);\n const result = await manager.poll(parsed.session_id, parsed.yield_time_ms, parsed.max_output_bytes);\n return formatProcessResult(result);\n },\n };\n}\n","/**\n * 服务装配:把配置、协议路由、存储、注册表、路由组装成一个可运行的服务。\n */\nimport path from \"node:path\";\nimport { serve } from \"@hono/node-server\";\nimport type { Hono } from \"hono\";\nimport { defaultDataDir, AgentSessionStore } from \"../agent/sessions.js\";\nimport { EscalationGrants } from \"../agent/escalation.js\";\nimport { EndpointResolver } from \"../llm/router.js\";\nimport { builtinTools } from \"../tools/index.js\";\nimport { loadConfig, type AppConfig } from \"./config.js\";\nimport { createConfigRoutes } from \"./config-routes.js\";\nimport { AgentRunRecorder } from \"./recorder.js\";\nimport { createAgentRoutes } from \"./routes.js\";\nimport { RunRegistry } from \"./run-registry.js\";\nimport { SessionIndex } from \"./session-index.js\";\n\nexport interface AgentServer {\n app: Hono;\n registry: RunRegistry;\n store: AgentSessionStore;\n index: SessionIndex;\n}\n\n/** 以代码方式装配服务(嵌入用法) */\nexport function createAgentServer(\n config: AppConfig,\n opts: { configPath?: string; dataDir?: string } = {},\n): AgentServer {\n const dataDir = path.resolve(opts.dataDir ?? defaultDataDir());\n const configPath = opts.configPath ?? path.join(dataDir, \"config.json\");\n const resolver = new EndpointResolver(config.endpoints);\n const store = new AgentSessionStore(path.join(dataDir, \"sessions\"));\n const index = new SessionIndex(path.join(dataDir, \"index.json\"));\n // 启动自愈:从事实源(JSONL 文件)整体重建索引\n index.rebuild(store.scanAll());\n const registry = new RunRegistry();\n const workdir = path.resolve(config.agent?.workdir ?? path.join(dataDir, \"workspace\"));\n const grants = new EscalationGrants();\n const buildWorkspaceContext = (agentConfig: AppConfig[\"agent\"]) => ({\n enableAgentsMd: agentConfig?.enable_agents_md !== false,\n enableSkills: agentConfig?.enable_skills !== false,\n ...(agentConfig?.disabled_skills?.length ? { disabledSkills: agentConfig.disabled_skills } : {}),\n ...(agentConfig?.skills_dirs?.length ? { skills: { extraDirs: agentConfig.skills_dirs } } : {}),\n });\n // 每次 run 前重新读配置装配上下文选项:Web 端改开关/停用名单后下一轮对话即生效,\n // 无需重启服务;配置损坏时回退启动时的快照\n const startupWorkspaceContext = buildWorkspaceContext(config.agent);\n const resolveWorkspaceContext = () => {\n try {\n return buildWorkspaceContext(loadConfig(configPath).agent);\n } catch (error) {\n console.warn(`[workspace-context] 配置读取失败,沿用启动快照:${error instanceof Error ? error.message : error}`);\n return startupWorkspaceContext;\n }\n };\n const app = createAgentRoutes({\n resolver,\n store,\n index,\n registry,\n grants,\n makeTools: (sessionId, skills) => builtinTools({\n workdir,\n grants,\n sessionId,\n enableCommandExecution: config.agent?.enable_command_execution ?? false,\n ...(skills?.length ? { skills } : {}),\n }),\n workdir,\n workspaceContext: startupWorkspaceContext,\n resolveWorkspaceContext,\n ...(config.agent?.agent_name ? { agentName: config.agent.agent_name } : {}),\n ...(config.agent?.persona ? { persona: config.agent.persona } : {}),\n ...(config.agent?.agent_instance_id ? { agentInstanceId: config.agent.agent_instance_id } : {}),\n ...(config.server?.token ? { token: config.server.token } : {}),\n });\n // 配置管理 API。\n const configRoutes = createConfigRoutes({ configPath });\n if (config.server?.token) {\n configRoutes.use(\"*\", async (c, next) => {\n const header = c.req.header(\"authorization\") ?? \"\";\n if (header !== `Bearer ${config.server!.token}`) {\n return c.json({ success: false, code: 401, message: \"未授权:缺少或错误的 Bearer token\" }, 401);\n }\n await next();\n });\n }\n app.route(\"/\", configRoutes);\n return { app, registry, store, index };\n}\n\n/** 以配置文件启动 HTTP 服务(CLI serve 命令) */\nexport function serveFromConfig(opts: { configPath?: string; port?: number; dataDir?: string }): void {\n const dataDir = opts.dataDir ? path.resolve(opts.dataDir) : defaultDataDir();\n const configPath = opts.configPath ?? path.join(dataDir, \"config.json\");\n const config = loadConfig(configPath);\n const { app } = createAgentServer(config, { configPath, dataDir });\n const port = opts.port ?? config.server?.port ?? 3210;\n const server = serve({ fetch: app.fetch, port }, (info) => {\n console.log(`xlyra-agent 服务已启动:http://127.0.0.1:${info.port}`);\n console.log(`数据目录:${dataDir}(sessions/ 会话转录,workspace/ 工具工作区)`);\n if (!config.server?.token) {\n console.warn(\"⚠ 未配置 server.token,接口无鉴权——请勿暴露到公网\");\n }\n });\n // 优雅退出:tsx watch 重启依赖进程响应 SIGTERM;\n // SSE 长连接会拖住 server.close(),2 秒兜底强退\n const shutdown = () => {\n server.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 2000).unref();\n };\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n}\n\nexport { AgentRunRecorder, RunRegistry, SessionIndex };\nexport { createAgentRoutes } from \"./routes.js\";\nexport {\n loadConfig,\n saveConfig,\n upsertEndpoint,\n removeEndpoint,\n configExists,\n defaultConfigPath,\n} from \"./config.js\";\nexport type { AppConfig, ServerConfig, AgentServiceConfig } from \"./config.js\";\nexport { createConfigRoutes } from \"./config-routes.js\";\nexport { HttpError, type StoredAgentEvent } from \"./run-registry.js\";\n","/**\n * 服务配置:~/.xlyra-agent/config.json。\n *\n * 职责:\n * - 端点配置(base_url / api_key / models / protocol 类型)统一落在这里,\n * 由 `xlyra config` 子命令管理(add/list/remove),也可手编;\n * - api_key 支持 \"${ENV_VAR}\" 环境变量插值——配置文件可以入库/共享而不泄漏\n * 凭证;\n * - 加载时经 Zod schema 校验:结构错误在启动时给出明确中文报错,\n * 而不是运行到一半才以奇怪方式失败;\n * - 保存一律 tmp + rename 原子换入。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { defaultDataDir } from \"../agent/sessions.js\";\n\n// ---------------------------------------------------------------------------\n// Schema(加载/保存共用同一份定义,防漂移)\n// ---------------------------------------------------------------------------\n\nconst endpointSchema = z\n .object({\n name: z.string().min(1, \"端点名不能为空\"),\n protocol: z.enum([\"openai-responses\", \"anthropic-messages\"]),\n /** 省略时按 direct 处理(兼容旧配置) */\n mode: z.enum([\"direct\", \"remote-xlyra\"]).default(\"direct\"),\n base_url: z.url(\"base_url 必须是合法 URL\"),\n api_key: z.string().min(1, \"api_key 不能为空(可用 ${ENV_VAR} 引用环境变量)\").optional(),\n credential: z\n .discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"temporary-bearer\"),\n token: z.string().min(1, \"credential.token 不能为空(可用 ${ENV_VAR} 引用环境变量)\"),\n }),\n z.object({\n type: z.literal(\"xlyra-callback\"),\n url: z.url(\"credential.url 必须是合法 URL\"),\n }),\n ])\n .optional(),\n models: z.record(z.string(), z.object({ context_window: z.number().positive().optional() })).optional(),\n default_model: z.string().optional(),\n })\n .superRefine((endpoint, ctx) => {\n // 凭证互斥规则(docs 第 4/5 章):direct 只要 api_key;remote-xlyra 只要 credential\n if (endpoint.mode === \"remote-xlyra\") {\n if (!endpoint.credential) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"credential\"],\n message: \"remote-xlyra 模式必须配置临时凭证(temporary-bearer 或 xlyra-callback)\",\n });\n }\n if (endpoint.api_key !== undefined) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"api_key\"],\n message: \"remote-xlyra 模式不允许配置 api_key\",\n });\n }\n return;\n }\n\n if (!endpoint.api_key) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"api_key\"],\n message: \"direct 模式必须配置 api_key\",\n });\n }\n if (endpoint.credential !== undefined) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"credential\"],\n message: \"direct 模式不允许配置 credential\",\n });\n }\n });\n\nconst appConfigSchema = z.object({\n endpoints: z.array(endpointSchema).min(1, \"endpoints 为空:至少配置一个模型端点\"),\n server: z\n .object({\n port: z.number().int().positive().optional(),\n token: z.string().optional(),\n })\n .optional(),\n agent: z\n .object({\n workdir: z.string().optional(),\n agent_name: z.string().optional(),\n persona: z.string().optional(),\n /** 部署方注入的 agent 实例标识(xlyra-callback 凭证用),run 启动参数可覆盖 */\n agent_instance_id: z.string().optional(),\n /** 本机命令可访问当前用户权限范围内的系统资源,必须显式开启。 */\n enable_command_execution: z.boolean().optional(),\n /** 是否注入 workdir 下的 AGENTS.md(默认 true) */\n enable_agents_md: z.boolean().optional(),\n /** 是否发现并暴露 Agent Skills(默认 true) */\n enable_skills: z.boolean().optional(),\n /** 停用的 skill 名称名单(不删文件,run 时跳过注入;在 enable_skills 之后生效) */\n disabled_skills: z.array(z.string()).optional(),\n /** 额外 skills 根目录(不替换标准路径) */\n skills_dirs: z.array(z.string()).optional(),\n })\n .optional(),\n});\n\nexport type AppConfig = z.infer<typeof appConfigSchema>;\n/** 配置输入类型:mode 等带默认值的字段可省略(saveConfig 校验时补齐) */\nexport type AppConfigInput = z.input<typeof appConfigSchema>;\nexport type ServerConfig = NonNullable<AppConfig[\"server\"]>;\nexport type AgentServiceConfig = NonNullable<AppConfig[\"agent\"]>;\n/** 端点输入类型:mode 可省略(schema 解析后补 direct),供 CLI/调用方构造 */\nexport type EndpointInput = z.input<typeof endpointSchema>;\n/** 供 config-routes 的 PUT payload 复用(保证加载/写入同一套校验规则) */\nexport { endpointSchema, appConfigSchema };\n\n// ---------------------------------------------------------------------------\n// 路径与读写\n// ---------------------------------------------------------------------------\n\nexport function defaultConfigPath(): string {\n return path.join(defaultDataDir(), \"config.json\");\n}\n\n/** 加载并校验配置;文件不存在/结构非法时抛出明确中文错误 */\nexport function loadConfig(configPath?: string): AppConfig {\n const file = configPath ?? defaultConfigPath();\n if (!fs.existsSync(file)) {\n throw new Error(\n `配置文件不存在:${file}\\n先运行 xlyra config init 交互式创建,或参考 README 手工编写。`,\n );\n }\n let raw: unknown;\n try {\n raw = JSON.parse(fs.readFileSync(file, \"utf-8\"));\n } catch (err) {\n throw new Error(`配置文件不是合法 JSON:${file}(${err instanceof Error ? err.message : err})`);\n }\n const parsed = appConfigSchema.safeParse(raw);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => ` - ${i.path.join(\".\") || \"(根)\"}:${i.message}`)\n .join(\"\\n\");\n throw new Error(`配置文件校验失败:${file}\\n${issues}`);\n }\n for (const endpoint of parsed.data.endpoints) {\n if (endpoint.api_key !== undefined) {\n endpoint.api_key = interpolateEnv(endpoint.api_key, file);\n }\n if (endpoint.credential?.type === \"temporary-bearer\") {\n endpoint.credential.token = interpolateEnv(endpoint.credential.token, file);\n }\n }\n return parsed.data;\n}\n\n/** 保存配置(schema 校验并补默认值,tmp + rename 原子写入)。\n * 配置可能含凭证:目录 0700、文件 0600(docs §12.4) */\nexport function saveConfig(config: AppConfigInput, configPath?: string): void {\n const file = configPath ?? defaultConfigPath();\n const validated = appConfigSchema.parse(config);\n fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });\n const tmp = `${file}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(validated, null, 2) + \"\\n\", { mode: 0o600 });\n fs.renameSync(tmp, file);\n // rename 保留 tmp 的权限;对既有文件(早期版本可能更宽)显式收紧\n fs.chmodSync(file, 0o600);\n}\n\n/** 配置是否存在(config init 判重 / 首次运行引导用) */\nexport function configExists(configPath?: string): boolean {\n return fs.existsSync(configPath ?? defaultConfigPath());\n}\n\n// ---------------------------------------------------------------------------\n// 端点管理(config add/remove 子命令的实现)\n// ---------------------------------------------------------------------------\n\n/** 新增或更新端点(按 name 匹配,同名覆盖);返回写入后的完整配置 */\nexport function upsertEndpoint(\n endpoint: EndpointInput,\n configPath?: string,\n): AppConfig {\n const file = configPath ?? defaultConfigPath();\n let config: AppConfig;\n if (fs.existsSync(file)) {\n // 已有配置:加载校验后合并(loadConfig 会插值 api_key,写回前需还原原始配置——\n // 因此这里读原始 JSON 而不是走 loadConfig)\n const raw = JSON.parse(fs.readFileSync(file, \"utf-8\")) as AppConfig;\n config = appConfigSchema.parse({ ...raw, endpoints: raw.endpoints ?? [] });\n } else {\n config = { endpoints: [] };\n }\n const idx = config.endpoints.findIndex((e) => e.name === endpoint.name);\n // 先单条过 schema(补 mode 默认值并执行互斥校验),再合并进整体配置\n const parsedEndpoint = endpointSchema.parse(endpoint);\n if (idx >= 0) {\n config.endpoints[idx] = parsedEndpoint;\n } else {\n config.endpoints.push(parsedEndpoint);\n }\n // 写回前整体过一遍 schema(endpoints 至少一条此时必然成立)\n const validated = appConfigSchema.parse(config);\n saveConfig(validated, file);\n return validated;\n}\n\n/** 按 name 删除端点;不存在时返回 false。不允许删除最后一条(配置必须非空) */\nexport function removeEndpoint(name: string, configPath?: string): boolean {\n const file = configPath ?? defaultConfigPath();\n if (!fs.existsSync(file)) return false;\n const raw = JSON.parse(fs.readFileSync(file, \"utf-8\")) as AppConfig;\n const endpoints = (raw.endpoints ?? []).filter((e) => e.name !== name);\n if (endpoints.length === (raw.endpoints ?? []).length) return false;\n if (endpoints.length === 0) {\n throw new Error(`不能删除最后一个端点(配置必须保留至少一个模型端点):${file}`);\n }\n saveConfig({ ...raw, endpoints }, file);\n return true;\n}\n\n/** \"${ENV_VAR}\" → 环境变量值;未设置时报出可读错误 */\nfunction interpolateEnv(value: string, file: string): string {\n return value.replace(/\\$\\{([A-Z0-9_]+)\\}/g, (whole, name: string) => {\n const v = process.env[name];\n if (v === undefined) {\n throw new Error(`配置文件 ${file} 引用了未设置的环境变量 ${name}(来自 \"${whole}\")`);\n }\n return v;\n });\n}\n","/**\n * 配置管理 API:\n * - GET /config 读取完整配置;api_key 打码回显(头 4 + 尾 4),\n * \"${ENV_VAR}\" 引用保持原文不插值——不回显真实凭证;\n * - PUT /config 整体保存配置(经 schema 校验,原子写盘);\n * - POST /config/test 端点连通性测试(最小真实调用,返回延迟/错误)。\n *\n * 注意:PUT 只落盘——运行中的服务下一次请求才生效的部分(工具 workdir 等\n * 启动期装配的项)需要重启服务;端点列表由 EndpointResolver 惰性构建,\n * 新增端点保存后立即可用。\n */\nimport { Hono } from \"hono\";\nimport fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { resolveCredentialProvider } from \"../llm/credential.js\";\nimport { AnthropicMessagesProtocol } from \"../llm/protocols/messages.js\";\nimport { OpenAIResponsesProtocol } from \"../llm/protocols/responses.js\";\nimport type { EndpointCredential } from \"../llm/router.js\";\nimport {\n appConfigSchema,\n endpointSchema,\n loadConfig,\n saveConfig,\n type AppConfig,\n} from \"./config.js\";\nimport { HttpError } from \"./run-registry.js\";\n\nexport interface ConfigRoutesContext {\n configPath: string;\n}\n\n/** api_key/token 打码:只留头 4 尾 4;\"${ENV_VAR}\" 引用原样保留(不是真实凭证) */\nfunction maskApiKey(key: string): string {\n if (key.includes(\"${\")) return key;\n if (key.length <= 8) return \"****\";\n return `${key.slice(0, 4)}…${key.slice(-4)}`;\n}\n\n/**\n * credential 打码回显:\n * - temporary-bearer:token 比照 api_key 打码(PUT 回传打码值时据此保留原值);\n * - xlyra-callback:运行时 token 只在内存,不回显不掩码,只报 configured 状态。\n */\nfunction maskCredential(credential: EndpointCredential): Record<string, unknown> {\n if (credential.type === \"temporary-bearer\") {\n return { type: credential.type, token: maskApiKey(credential.token) };\n }\n return {\n type: credential.type,\n url: credential.url,\n configured: true,\n };\n}\n\ntype MaskedEndpoint = Omit<AppConfig[\"endpoints\"][number], \"api_key\" | \"credential\"> & {\n api_key?: string;\n credential?: Record<string, unknown>;\n};\n\nfunction maskedConfig(config: AppConfig): Omit<AppConfig, \"endpoints\"> & { endpoints: MaskedEndpoint[] } {\n return {\n ...config,\n endpoints: config.endpoints.map((e) => ({\n ...e,\n ...(e.api_key !== undefined ? { api_key: maskApiKey(e.api_key) } : {}),\n ...(e.credential ? { credential: maskCredential(e.credential) } : {}),\n })),\n };\n}\n\n/**\n * 保留语义(以磁盘原始值为准):\n * - incoming 与原始值一致(含 \"${ENV_VAR}\" 引用原样回传)→ 保留原始值;\n * - incoming 是插值后真实值的打码形式 → 保留原始值(可能是引用,不写明文);\n * - 其余 → 按新值。\n */\nfunction retainSecret(\n incoming: string | undefined,\n existingRaw: string | undefined,\n existingResolved: string | undefined,\n): string | undefined {\n if (incoming === undefined || existingRaw === undefined) return incoming;\n if (incoming === existingRaw) return existingRaw;\n if (existingResolved !== undefined && incoming === maskApiKey(existingResolved)) return existingRaw;\n return incoming;\n}\n\n/**\n * credential 保留语义:\n * - temporary-bearer:token 走 retainSecret(原始值可能是 \"${ENV_VAR}\" 引用);\n * - xlyra-callback:type+url 与现有一致(含只带 configured 标记的回传)→ 保留原有配置;\n * - 其余情况按新值保存(由 schema 校验)。\n */\nfunction retainCredential(\n incoming: EndpointCredential | undefined,\n existingRaw: AppConfig[\"endpoints\"][number] | undefined,\n existingResolved: AppConfig[\"endpoints\"][number] | undefined,\n): EndpointCredential | undefined {\n const prevRaw = existingRaw?.credential;\n const prevResolved = existingResolved?.credential;\n if (!incoming || !prevRaw) return incoming;\n if (prevRaw.type === \"temporary-bearer\" && incoming.type === \"temporary-bearer\") {\n const resolvedToken = prevResolved?.type === \"temporary-bearer\" ? prevResolved.token : undefined;\n const token = retainSecret(incoming.token, prevRaw.token, resolvedToken);\n return token === undefined ? incoming : { type: \"temporary-bearer\", token };\n }\n if (prevRaw.type === \"xlyra-callback\" && incoming.type === \"xlyra-callback\" && incoming.url === prevRaw.url) {\n return prevRaw;\n }\n return incoming;\n}\n\nconst putPayloadSchema = z.object({\n endpoints: z.array(endpointSchema).min(1, \"endpoints 为空:至少配置一个模型端点\"),\n /** 显式确认修改 remote-xlyra 端点的 base_url/callback 地址(SSRF 防护闸) */\n allow_remote_endpoint_override: z.boolean().optional(),\n server: z.object({ port: z.number().int().positive().optional(), token: z.string().optional() }).optional(),\n agent: z.object({\n workdir: z.string().optional(),\n agent_name: z.string().optional(),\n persona: z.string().optional(),\n agent_instance_id: z.string().optional(),\n enable_command_execution: z.boolean().optional(),\n enable_agents_md: z.boolean().optional(),\n enable_skills: z.boolean().optional(),\n disabled_skills: z.array(z.string()).optional(),\n skills_dirs: z.array(z.string()).optional(),\n }).optional(),\n});\n\n/**\n * 读取磁盘上的原始配置(未插值):PUT 的保留语义必须以原始值为准,\n * 否则 loadConfig 插值后的明文会把磁盘上的 \"${ENV_VAR}\" 引用固化成明文。\n */\nfunction loadRawConfig(configPath: string): AppConfig {\n const raw = JSON.parse(fs.readFileSync(configPath, \"utf-8\")) as unknown;\n return appConfigSchema.parse(raw);\n}\n\nexport function createConfigRoutes(ctx: ConfigRoutesContext): Hono {\n const app = new Hono();\n\n app.onError((err, c) => {\n if (err instanceof HttpError) {\n return c.json({ success: false, code: err.status, message: err.message }, err.status as 400);\n }\n console.error(`配置接口处理失败:${err instanceof Error ? err.message : err}`);\n return c.json({ success: false, code: 500, message: err instanceof Error ? err.message : \"服务内部错误\" }, 500);\n });\n\n /** 读取配置(api_key 打码) */\n app.get(\"/config\", (c) => {\n const config = loadConfig(ctx.configPath);\n return c.json({ success: true, code: 0, message: \"\", data: maskedConfig(config) });\n });\n\n /**\n * 整体保存配置。api_key / credential.token 与打码形式一致(含 …)时视为\n * 「未修改」,保留磁盘上的原值——Web 表单回显打码值后直接提交不会把凭证冲掉。\n * xlyra-callback 回传 type+url(或 configured 标记)视为未修改。\n * 保留比对基于磁盘原始值:含 \"${ENV_VAR}\" 的引用保持引用形态,不回写明文。\n */\n app.put(\"/config\", async (c) => {\n const payload = putPayloadSchema.parse(await c.req.json());\n const current = loadRawConfig(ctx.configPath); // 原始值(可能含 ${ENV_VAR})\n const resolved = loadConfig(ctx.configPath); // 插值后的真实值(打码基准)\n const endpoints = payload.endpoints.map((incoming) => {\n const existingRaw = current.endpoints.find((e) => e.name === incoming.name);\n const existingResolved = resolved.endpoints.find((e) => e.name === incoming.name);\n const apiKey = retainSecret(incoming.api_key, existingRaw?.api_key, existingResolved?.api_key);\n const credential = retainCredential(incoming.credential, existingRaw, existingResolved);\n const merged = { ...incoming, credential };\n if (apiKey !== undefined) merged.api_key = apiKey;\n else delete merged.api_key;\n\n // SSRF 防护(docs §5/§12.5):已存在的 remote-xlyra 端点,普通 PUT 修改\n // base_url 或 callback url 需要显式确认——这两个地址决定 agent 的 LLM 流量\n // 与 run 标识上下文发往何处,默认只能由 runner/受信接口生成配置时设定。\n if (incoming.mode === \"remote-xlyra\" && existingRaw?.mode === \"remote-xlyra\") {\n const callbackUrlChanged =\n incoming.credential?.type === \"xlyra-callback\" &&\n existingRaw.credential?.type === \"xlyra-callback\" &&\n incoming.credential.url !== existingRaw.credential.url;\n if (incoming.base_url !== existingRaw.base_url || callbackUrlChanged) {\n if (payload.allow_remote_endpoint_override !== true) {\n throw new HttpError(\n 400,\n `端点 ${incoming.name} 是 remote-xlyra 模式,base_url/callback 地址只能由 runner 或受信任管理接口修改(PUT 需带 allow_remote_endpoint_override: true 显式确认)`,\n );\n }\n }\n }\n return merged;\n });\n // 保留语义合并后再整体过一遍 schema(互斥规则在最终形态上校验)\n const next: AppConfig = appConfigSchema.parse({\n endpoints,\n ...(payload.server ? { server: payload.server } : {}),\n ...(payload.agent ? { agent: payload.agent } : {}),\n });\n saveConfig(next, ctx.configPath);\n return c.json({ success: true, code: 0, message: \"配置已保存(部分启动期装配项需重启服务后生效)\", data: maskedConfig(next) });\n });\n\n /**\n * 端点连通性测试:一次最小真实调用(max_tokens=1),返回延迟或错误。\n * xlyra-callback 的 callback 需要 session_id/run_id 才能签发 token,\n * 无活动 run 上下文时不可测试,返回明确错误(docs §10.3)。\n */\n app.post(\"/config/test\", async (c) => {\n const { name } = z.object({ name: z.string().min(1) }).parse(await c.req.json());\n const config = loadConfig(ctx.configPath);\n const endpoint = config.endpoints.find((e) => e.name === name);\n if (!endpoint) throw new HttpError(404, `端点不存在:${name}`);\n if (endpoint.mode === \"remote-xlyra\" && endpoint.credential?.type === \"xlyra-callback\") {\n throw new HttpError(400, `端点 ${name} 使用 xlyra-callback 凭证,需在 run 上下文中测试(此处无活动 run)`);\n }\n const model = endpoint.default_model ?? Object.keys(endpoint.models ?? {})[0];\n if (!model) throw new HttpError(400, `端点 ${name} 未配置 default_model 或 models,无法测试`);\n const credential = resolveCredentialProvider(endpoint);\n const protocol =\n endpoint.protocol === \"anthropic-messages\"\n ? new AnthropicMessagesProtocol({ baseUrl: endpoint.base_url, credential, providerName: endpoint.name })\n : new OpenAIResponsesProtocol({ baseUrl: endpoint.base_url, credential, providerName: endpoint.name });\n\n const started = Date.now();\n for await (const event of protocol.chatStream({\n model,\n messages: [{ role: \"user\", content: \"ping\" }],\n settings: { max_tokens: endpoint.protocol === \"anthropic-messages\" ? 16 : 16 },\n })) {\n if (event.type === \"error\") {\n return c.json({ success: false, code: 502, message: `连通性测试失败:${event.error}`, data: null }, 502);\n }\n if (event.type === \"done\") {\n return c.json({\n success: true, code: 0,\n message: `端点 ${name} 连通正常(${Date.now() - started}ms)`,\n data: { elapsed_ms: Date.now() - started, model: event.response.model || model },\n });\n }\n }\n return c.json({ success: false, code: 502, message: \"连通性测试失败:流异常终止\", data: null }, 502);\n });\n\n return app;\n}\n","/**\n * 进程内 Agent 运行注册表:后台执行、事件回放与广播订阅。\n *\n * 设计(移植自 MovieClaw agent_runs.py):为每次运行维护一份只追加的事件\n * 日志,订阅者各自持有序号游标——不用消息队列(队列消息只会被一个消费者\n * 取走,无法同时满足多个 SSE 订阅者,也无法让断线客户端回放历史)。\n * Promise 通知链只负责在新事件到达时唤醒等待者,消息本身始终以日志为准。\n *\n * 注册表仅在单个进程内有效;若未来需要多实例部署,应把这一层替换为\n * Redis 等共享存储,而不是改变 AgentRunner 或 SSE 事件协议。\n */\nimport crypto from \"node:crypto\";\nimport type { AgentEvent, AgentEventType, AgentStartParams } from \"../agent/events.js\";\nimport { TERMINAL_EVENT_TYPES } from \"../agent/events.js\";\nimport type { AgentRunner } from \"../agent/runner.js\";\n\nexport const DEFAULT_RETENTION_MS = 24 * 60 * 60 * 1000;\n\nexport interface StoredAgentEvent {\n /** 运行内递增序号;直接用作 SSE 的 id */\n sequence: number;\n event: AgentEvent;\n}\n\ninterface Run {\n runId: string;\n sessionId: string;\n events: StoredAgentEvent[];\n terminal: boolean;\n completedAt: number | null;\n controller: AbortController;\n /** 等待新事件的唤醒回调(一次性,触发后移除) */\n waiters: Set<() => void>;\n /** 终态钩子:运行进入终态后调用一次(停心跳、补配对、清运行标记) */\n onTerminal: ((event: AgentEvent) => Promise<void>) | null;\n}\n\nexport class RunRegistry {\n private readonly retentionMs: number;\n private readonly runs = new Map<string, Run>();\n private readonly latestBySession = new Map<string, string>();\n private closing = false;\n\n constructor(opts: { retentionMs?: number } = {}) {\n this.retentionMs = opts.retentionMs ?? DEFAULT_RETENTION_MS;\n }\n\n /** 分配运行编号并把 runner 放入后台执行,立即返回编号 */\n start(\n runner: AgentRunner,\n params: AgentStartParams,\n opts: {\n sessionId: string;\n onTerminal?: (event: AgentEvent) => Promise<void>;\n /** 部署方注入的 agent 实例标识(xlyra-callback 凭证用) */\n agentInstanceId?: string;\n },\n ): string {\n if (this.closing) throw new Error(\"运行注册表正在关闭,无法创建新运行\");\n this.pruneExpired();\n const runId = crypto.randomUUID().replaceAll(\"-\", \"\").slice(0, 12);\n const run: Run = {\n runId,\n sessionId: opts.sessionId,\n events: [],\n terminal: false,\n completedAt: null,\n controller: new AbortController(),\n waiters: new Set(),\n onTerminal: opts.onTerminal ?? null,\n };\n this.runs.set(runId, run);\n this.latestBySession.set(opts.sessionId, runId);\n void this.execute(run, runner, params, opts.agentInstanceId);\n return runId;\n }\n\n /** 按公开会话编号读取当前(或最近一轮)事件 */\n async getSessionEvents(\n sessionId: string,\n afterSequence: number,\n timeoutSeconds: number,\n ): Promise<{ events: StoredAgentEvent[]; terminal: boolean }> {\n return this.getEvents(this.sessionRun(sessionId).runId, afterSequence, timeoutSeconds);\n }\n\n /**\n * 返回游标后的事件;暂无事件时等待通知,超时返回空列表供 SSE 发心跳。\n * 调用方应先发送本批事件,再在 terminal=true 且批次已追平时关闭连接。\n */\n async getEvents(\n runId: string,\n afterSequence: number,\n timeoutSeconds: number,\n ): Promise<{ events: StoredAgentEvent[]; terminal: boolean }> {\n if (afterSequence < 0) throw new HttpError(400, \"SSE 事件游标不能为负数\");\n const run = this.getRun(runId);\n if (afterSequence > run.events.length) {\n throw new HttpError(400, `SSE 事件游标 ${afterSequence} 超出当前事件范围`);\n }\n if (afterSequence === run.events.length && !run.terminal && timeoutSeconds > 0) {\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n run.waiters.delete(wake);\n resolve();\n }, timeoutSeconds * 1000);\n const wake = (): void => {\n clearTimeout(timer);\n run.waiters.delete(wake);\n resolve();\n };\n run.waiters.add(wake);\n });\n }\n return { events: run.events.slice(afterSequence), terminal: run.terminal };\n }\n\n /**\n * 幂等取消一次运行:**先落可回放的 agent_cancelled 终态事件,再 abort**。\n * 顺序很重要:运行刚创建、事件循环尚未开始消费时,直接 abort 会让 runner\n * 一次都不执行,订阅者会永久等待——先落终态事件保证任何情况下订阅者\n * 都能看到收尾。\n */\n async cancel(runId: string): Promise<void> {\n const run = this.getRun(runId);\n if (run.terminal) return;\n await this.publish(run, { type: \"agent_cancelled\", run_id: run.runId });\n run.controller.abort();\n }\n\n async cancelSession(sessionId: string): Promise<void> {\n await this.cancel(this.sessionRun(sessionId).runId);\n }\n\n /** 应用关闭时取消全部活动运行 */\n async close(): Promise<void> {\n this.closing = true;\n for (const run of this.runs.values()) {\n if (!run.terminal) await this.cancel(run.runId);\n }\n this.runs.clear();\n this.latestBySession.clear();\n }\n\n /** 消费 runner 事件并写入日志,兜住所有退出路径补齐终态 */\n private async execute(\n run: Run,\n runner: AgentRunner,\n params: AgentStartParams,\n agentInstanceId?: string,\n ): Promise<void> {\n try {\n for await (const event of runner.start(params, {\n runId: run.runId,\n signal: run.controller.signal,\n sessionId: run.sessionId,\n ...(agentInstanceId ? { agentInstanceId } : {}),\n })) {\n await this.publish(run, event);\n }\n if (!run.terminal) {\n await this.publish(run, {\n type: \"agent_error\",\n run_id: run.runId,\n error: \"Agent 运行异常结束,未返回终态事件\",\n });\n }\n } catch (err) {\n // runner 设计为不抛异常;这里是最后防线——后台任务必须转成可见终态\n if (!run.terminal) {\n await this.publish(run, {\n type: \"agent_error\",\n run_id: run.runId,\n error: `Agent 运行发生未知错误:${err instanceof Error ? err.message : err}`,\n });\n }\n }\n }\n\n /** 原子追加事件并广播唤醒;终态之后的迟到事件直接忽略 */\n private async publish(run: Run, event: AgentEvent): Promise<void> {\n if (run.terminal) return;\n run.events.push({ sequence: run.events.length + 1, event });\n let becameTerminal = false;\n if (TERMINAL_EVENT_TYPES.has(event.type as AgentEventType)) {\n run.terminal = true;\n run.completedAt = Date.now();\n becameTerminal = true;\n }\n for (const wake of [...run.waiters]) wake();\n // 终态钩子在事件广播之后调用:收尾涉及文件 IO,不应阻塞事件流;\n // terminal 置位保证本钩子最多触发一次\n if (becameTerminal && run.onTerminal) {\n try {\n await run.onTerminal(event);\n } catch (err) {\n console.error(`Agent 运行终态钩子执行失败 run=${run.runId}:${err instanceof Error ? err.message : err}`);\n }\n }\n }\n\n getRun(runId: string): Run {\n this.pruneExpired();\n const run = this.runs.get(runId);\n if (!run) throw new HttpError(404, \"Agent 运行不存在或事件历史已过期\");\n return run;\n }\n\n private sessionRun(sessionId: string): Run {\n this.pruneExpired();\n const runId = this.latestBySession.get(sessionId);\n const run = runId ? this.runs.get(runId) : undefined;\n if (!run) throw new HttpError(404, \"会话没有可跟随或停止的运行\");\n return run;\n }\n\n /** 惰性清理超过保留期的终态运行;活动运行永不在这里删除 */\n private pruneExpired(): void {\n const cutoff = Date.now() - this.retentionMs;\n for (const [runId, run] of [...this.runs]) {\n if (run.completedAt !== null && run.completedAt <= cutoff) {\n this.runs.delete(runId);\n if (this.latestBySession.get(run.sessionId) === runId) {\n this.latestBySession.delete(run.sessionId);\n }\n }\n }\n }\n}\n\n/** 路由层可直接转成统一错误响应的异常 */\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n ) {\n super(message);\n this.name = \"HttpError\";\n }\n}\n","/**\n * 会话记录器:把一次 Agent 运行的定稿消息接进 JSONL 存储与会话索引。\n *\n * 一次运行一个实例,由路由层创建并挂到两个钩子上:\n * - AgentRunner(onMessage / onCompaction)——定稿消息与压缩行落盘并刷新\n * 索引(先文件后索引,见 sessions.ts 的写入顺序约定);\n * - RunRegistry.start(onTerminal)——运行终态时收尾:停心跳、给未配对的\n * tool_call 补错误回执、清空运行标记(列表立即显示已结束)。\n *\n * 心跳独立于消息追加:长工具执行期间可能几十秒没有新消息,心跳任务保证\n * last_heartbeat 持续刷新,调用方才能正确区分「还在跑」和「已崩溃」。\n * 进程硬崩时心跳自然停止,超时窗过后状态自愈为已结束——这正是不持久化\n * 静态 status 字段的原因。\n */\nimport type { AgentEvent } from \"../agent/events.js\";\nimport type { CompactionResult } from \"../agent/compaction.js\";\nimport { PREVIEW_MAX_CHARS, type AgentSessionStore } from \"../agent/sessions.js\";\nimport type { ChatMessage, ChatResponse } from \"../llm/models.js\";\nimport type { SessionIndex } from \"./session-index.js\";\n\n/** 心跳间隔(毫秒);超时窗见 session-index 的 HEARTBEAT_TIMEOUT_MS(须大于本值) */\nexport const HEARTBEAT_INTERVAL_MS = 10_000;\n\nexport class AgentRunRecorder {\n private readonly store: AgentSessionStore;\n private readonly index: SessionIndex;\n private readonly sessionId: string;\n /** 运行开始时会话已有的 entry 数;之后每次落盘递增,避免反复重读文件 */\n private entryCount: number;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n /** begin 与 onTerminal 分别由路由层和后台任务并发调用:用同一根 Promise\n * 链串行化,防「极速结束的运行被误标为永远运行中」的竞态 */\n private lifecycle: Promise<void> = Promise.resolve();\n private terminated = false;\n\n constructor(store: AgentSessionStore, index: SessionIndex, sessionId: string, entryCount: number) {\n this.store = store;\n this.index = index;\n this.sessionId = sessionId;\n this.entryCount = entryCount;\n }\n\n /** 运行启动:标记 running 并开启心跳。运行已先一步终态时跳过。 */\n async begin(runId: string): Promise<void> {\n this.lifecycle = this.lifecycle.then(() => {\n if (this.terminated) return;\n this.index.markRunning(this.sessionId, runId);\n this.heartbeatTimer = setInterval(() => {\n try {\n this.index.heartbeat(this.sessionId);\n } catch (err) {\n console.warn(`会话心跳刷新失败 session=${this.sessionId}:${err instanceof Error ? err.message : err}`);\n }\n }, HEARTBEAT_INTERVAL_MS);\n this.heartbeatTimer.unref?.();\n });\n await this.lifecycle;\n }\n\n /** 落盘 user message,刷新标题(仅首条)与最后提示预览,返回 message id */\n async recordUserMessage(text: string): Promise<string> {\n const entry = this.store.append(this.sessionId, { role: \"user\", content: text });\n this.entryCount += 1;\n const preview = text.trim().slice(0, PREVIEW_MAX_CHARS);\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n last_prompt: preview,\n title: preview,\n });\n return entry.uuid;\n }\n\n /** runner 定稿消息回调:assistant 带响应元数据,tool 结果不带 */\n onMessage = async (message: ChatMessage, response: ChatResponse | null): Promise<void> => {\n const entry = this.store.append(this.sessionId, message, {\n ...(response?.model ? { model: response.model } : {}),\n ...(response?.usage ? { usage: response.usage } : {}),\n ...(response?.finish_reason ? { finish_reason: response.finish_reason } : {}),\n });\n this.entryCount += 1;\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n });\n };\n\n /** runner 压缩定稿回调:压缩行落盘并刷新索引(与 onMessage 同一节奏) */\n onCompaction = async (result: CompactionResult): Promise<void> => {\n const entry = this.store.appendCompaction(this.sessionId, result);\n this.entryCount += 1;\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n });\n };\n\n /** runner 提权请求回调:提权行落盘并刷新索引(回放时前端渲染确认卡片) */\n onEscalation = async (info: {\n escalation_id: string;\n requested_path: string;\n resolved_path: string;\n tool_name: string;\n resource_type?: \"path\" | \"command\";\n requested_command?: string[];\n }): Promise<void> => {\n const entry = this.store.appendEscalation(this.sessionId, {\n escalation_id: info.escalation_id,\n requested_path: info.requested_path,\n resolved_path: info.resolved_path,\n tool_name: info.tool_name,\n resource_type: info.resource_type,\n requested_command: info.requested_command,\n });\n this.entryCount += 1;\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: this.entryCount,\n });\n };\n\n /** 运行终态收尾(done / error / cancelled 统一路径) */\n onTerminal = async (_event: AgentEvent): Promise<void> => {\n this.lifecycle = this.lifecycle.then(() => {\n this.terminated = true;\n if (this.heartbeatTimer !== null) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n // 取消/出错的运行可能留下没有回执的 tool_call,补齐保证配对完整;\n // 提权协商暂停(等待用户确认)用中性回执,不标为失败\n let sealed = 0;\n try {\n const awaitingAuth = _event.type === \"agent_cancelled\" && _event.reason === \"escalation\";\n sealed = this.store.sealPendingToolCalls(this.sessionId, awaitingAuth ? \"awaiting_authorization\" : \"interrupted\");\n } catch (err) {\n console.warn(`会话中断收尾失败 session=${this.sessionId}:${err instanceof Error ? err.message : err}`);\n }\n if (sealed > 0) {\n this.entryCount += sealed;\n const { entries } = this.store.read(this.sessionId);\n this.index.touchAfterAppend(this.sessionId, {\n leaf_uuid: entries[entries.length - 1]?.uuid ?? \"\",\n entry_count: this.entryCount,\n });\n }\n this.index.finishRun(this.sessionId);\n });\n await this.lifecycle;\n };\n}\n","/**\n * REST + SSE 路由(Hono)—— Agent 会话的 HTTP 面。\n *\n * 响应统一信封:成功 {success:true, code, message, data};\n * 错误 {success:false, code, message}(HTTP 状态码同步表达错误类别)。\n */\nimport { Hono } from \"hono\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { buildSystemPrompt } from \"../agent/prompts.js\";\nimport { compact, type CompactionResult } from \"../agent/compaction.js\";\nimport {\n isCompactionEntry,\n isEscalationEntry,\n isMessageEntry,\n type AgentSessionStore,\n} from \"../agent/sessions.js\";\nimport { AgentRunner } from \"../agent/runner.js\";\nimport type { AgentEvent } from \"../agent/events.js\";\nimport type { EndpointResolver } from \"../llm/router.js\";\nimport { modelSettingsSchema } from \"../llm/models.js\";\nimport type { AgentTool } from \"../tools/types.js\";\nimport type { SkillInfo } from \"../context/skills.js\";\nimport {\n discoverSkills,\n loadSkillContent,\n loadWorkspaceContext,\n type WorkspaceContext,\n type WorkspaceContextOptions,\n} from \"../context/index.js\";\nimport { AgentRunRecorder } from \"./recorder.js\";\nimport { HttpError, RunRegistry } from \"./run-registry.js\";\nimport type { SessionIndex } from \"./session-index.js\";\n\nexport interface RoutesContext {\n resolver: EndpointResolver;\n store: AgentSessionStore;\n index: SessionIndex;\n registry: RunRegistry;\n /** 会话级路径授权登记表(提权协商的确认落点) */\n grants: import(\"../agent/escalation.js\").EscalationGrants;\n /** 工具工厂:按会话构建工具集;skills 由每次 run 刷新后传入 */\n makeTools: (sessionId: string, skills?: SkillInfo[]) => AgentTool[];\n /** 提权事件展示的工作区根 */\n workdir: string;\n agentName?: string;\n persona?: string;\n /** 部署方注入的 agent 实例标识默认值(xlyra-callback 凭证用);run 启动参数可覆盖 */\n agentInstanceId?: string;\n /** AGENTS.md / Skills 发现开关与额外目录(启动快照) */\n workspaceContext?: WorkspaceContextOptions;\n /** 每次 run/查询时解析最新上下文选项(配置热生效);缺省回退 workspaceContext */\n resolveWorkspaceContext?: () => WorkspaceContextOptions;\n /** 可选静态 Bearer token;配置后全部端点要求鉴权 */\n token?: string;\n}\n\nfunction ok<T>(data: T, message = \"\"): { success: true; code: number; message: string; data: T } {\n return { success: true, code: 0, message, data };\n}\n\nfunction fail(status: number, message: string): never {\n throw new HttpError(status, message);\n}\n\nconst startPayloadSchema = z.object({\n content: z.string().min(1, \"消息内容不能为空\"),\n session_id: z.string().optional(),\n model: z.string().default(\"\"),\n settings: modelSettingsSchema.optional(),\n reasoning_effort: modelSettingsSchema.shape.reasoning_effort,\n /** 部署方注入的 agent 实例标识(xlyra-callback 凭证用),缺省用服务级配置 */\n agent_instance_id: z.string().optional(),\n /** 权限模式:ask(默认,越界操作走提权协商)/ full(本会话完全访问,跳过硬闸确认) */\n permission_mode: z.enum([\"ask\", \"full\"]).optional(),\n});\n\nconst retryPayloadSchema = z.object({\n message_id: z.string().min(1),\n content: z.string().optional(),\n model: z.string().default(\"\"),\n settings: modelSettingsSchema.optional(),\n reasoning_effort: modelSettingsSchema.shape.reasoning_effort,\n agent_instance_id: z.string().optional(),\n permission_mode: z.enum([\"ask\", \"full\"]).optional(),\n});\n\n/** PATCH /sessions/:id 请求体:title 与 archived 至少提供一个 */\nconst patchPayloadSchema = z\n .object({\n title: z.string().min(1).optional(),\n archived: z.boolean().optional(),\n })\n .refine((v) => v.title !== undefined || v.archived !== undefined, {\n message: \"至少提供 title 或 archived 之一\",\n });\n\nexport function createAgentRoutes(ctx: RoutesContext): Hono {\n const app = new Hono();\n\n // 统一错误处理:HttpError → 对应状态码;其余 → 500\n app.onError((err, c) => {\n if (err instanceof HttpError) {\n return c.json({ success: false, code: err.status, message: err.message }, err.status as 400);\n }\n // 请求体校验失败是客户端错误:返回 400 与具体字段,不淹没在 500 里\n if (err instanceof z.ZodError) {\n const issue = err.issues[0];\n const where = issue && issue.path.length > 0 ? `${issue.path.join(\".\")}: ` : \"\";\n return c.json({ success: false, code: 400, message: `参数校验失败:${where}${issue?.message ?? \"非法请求\"}` }, 400);\n }\n console.error(`请求处理失败:${err instanceof Error ? (err.stack ?? err.message) : err}`);\n return c.json({ success: false, code: 500, message: \"服务内部错误\" }, 500);\n });\n\n // 可选 Bearer 鉴权\n if (ctx.token) {\n app.use(\"*\", async (c, next) => {\n const header = c.req.header(\"authorization\") ?? \"\";\n if (header !== `Bearer ${ctx.token}`) {\n return c.json({ success: false, code: 401, message: \"未授权:缺少或错误的 Bearer token\" }, 401);\n }\n await next();\n });\n }\n\n const currentWorkspaceOptions = () => ctx.resolveWorkspaceContext?.() ?? ctx.workspaceContext ?? {};\n\n const refreshWorkspace = () => {\n const workspace = loadWorkspaceContext(ctx.workdir, currentWorkspaceOptions());\n for (const warning of workspace.warnings) {\n console.warn(`[workspace-context] ${warning}`);\n }\n return workspace;\n };\n\n const buildSystem = (fragments: string[] = []): string =>\n buildSystemPrompt({\n agentName: ctx.agentName,\n persona: ctx.persona,\n contextFragments: fragments,\n });\n\n /** 在已校验的会话链尾追加用户消息并启动后台运行(start / retry 共用) */\n async function launchUserMessage(args: {\n sessionId: string;\n content: string;\n model: string;\n history: import(\"../llm/models.js\").ChatMessage[];\n entryCount: number;\n settings?: import(\"../llm/models.js\").ModelSettings;\n systemPrompt?: string;\n recordUser?: boolean;\n agentInstanceId?: string;\n workspace?: WorkspaceContext;\n }): Promise<{ sessionId: string; messageId: string; runId: string; model: string; agentInstanceId: string }> {\n const workspace = args.workspace ?? refreshWorkspace();\n const recorder = new AgentRunRecorder(ctx.store, ctx.index, args.sessionId, args.entryCount);\n const messageId = args.recordUser === false ? \"\" : await recorder.recordUserMessage(args.content);\n const runner = new AgentRunner({\n resolver: ctx.resolver,\n tools: ctx.makeTools(args.sessionId, workspace.skills.skills),\n onMessage: recorder.onMessage,\n onCompaction: recorder.onCompaction,\n onEscalation: recorder.onEscalation,\n workdirHint: ctx.workdir,\n });\n const runId = ctx.registry.start(\n runner,\n {\n input: args.content,\n include_input: args.recordUser !== false,\n history: args.history,\n model: args.model,\n settings: args.settings,\n system_prompt: args.systemPrompt ?? buildSystem(workspace.fragments),\n },\n {\n sessionId: args.sessionId,\n onTerminal: recorder.onTerminal,\n ...(args.agentInstanceId ?? ctx.agentInstanceId\n ? { agentInstanceId: args.agentInstanceId ?? ctx.agentInstanceId }\n : {}),\n },\n );\n await recorder.begin(runId);\n const resolvedModel = ctx.resolver.resolve(args.model).modelId;\n return {\n sessionId: args.sessionId,\n messageId,\n runId,\n model: resolvedModel,\n agentInstanceId: args.agentInstanceId ?? ctx.agentInstanceId ?? \"default\",\n };\n }\n\n /** 开始新会话,或向已有会话发送用户消息(202 异步) */\n app.post(\"/sessions\", async (c) => {\n const payload = startPayloadSchema.parse(await c.req.json());\n // 路由解析先行:端点未配置/模型不存在时必须在会话落盘前失败,\n // 否则磁盘上会残留一条空会话\n ctx.resolver.resolve(payload.model);\n\n let sessionId: string;\n let history: import(\"../llm/models.js\").ChatMessage[];\n let entryCount: number;\n if (payload.session_id) {\n sessionId = payload.session_id;\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再发送消息\");\n if (ctx.index.isRunning(sessionId)) {\n fail(400, \"该会话已有正在进行的运行,请先停止或等待完成\");\n }\n history = ctx.store.buildHistory(sessionId);\n entryCount = ctx.store.read(sessionId).entries.length;\n } else {\n const header = ctx.store.create();\n sessionId = header.session_id;\n ctx.index.create(sessionId);\n history = [];\n entryCount = 0;\n }\n // 权限模式随每条消息注入:full 放开本会话全部提权检查,ask 撤销(不含已逐项授权的路径)\n if (payload.permission_mode !== undefined) {\n ctx.grants.setFullAccess(sessionId, payload.permission_mode === \"full\");\n }\n const { messageId, runId, model, agentInstanceId } = await launchUserMessage({\n sessionId,\n content: payload.content,\n model: payload.model,\n history,\n entryCount,\n settings: {\n ...payload.settings,\n ...(payload.reasoning_effort ? { reasoning_effort: payload.reasoning_effort } : {}),\n },\n ...(payload.agent_instance_id ? { agentInstanceId: payload.agent_instance_id } : {}),\n });\n return c.json(ok({ session_id: sessionId, message_id: messageId, run_id: runId, model, agent_instance_id: agentInstanceId }, \"用户消息已提交\"), 202);\n });\n\n /** 最近会话列表(按最后活跃时间倒序) */\n app.get(\"/sessions\", (c) => {\n const limit = Math.min(Number(c.req.query(\"limit\") ?? 50), 200);\n const offset = Math.max(Number(c.req.query(\"offset\") ?? 0), 0);\n const list = ctx.index.list(limit, offset).map((meta) => ({\n ...meta,\n running: ctx.index.isRunning(meta.session_id),\n }));\n return c.json(ok(list));\n });\n\n /** 读取会话完整轨迹(message/compaction 按写入顺序) */\n app.get(\"/sessions/:id/transcript\", (c) => {\n const sessionId = c.req.param(\"id\");\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n const { entries } = ctx.store.read(sessionId);\n return c.json(\n ok({\n session: ctx.index.get(sessionId) ?? null,\n entries: entries.map((e) =>\n isCompactionEntry(e)\n ? {\n type: \"compaction\" as const,\n compaction_id: e.uuid,\n parent_id: e.parent_uuid,\n timestamp: e.timestamp,\n summary: e.summary,\n replacement_history: e.replacement_history,\n tokens_before: e.tokens_before,\n tokens_after: e.tokens_after,\n }\n : isEscalationEntry(e)\n ? {\n type: \"escalation\" as const,\n escalation_id: e.uuid,\n parent_id: e.parent_uuid,\n timestamp: e.timestamp,\n requested_path: e.requested_path,\n resolved_path: e.resolved_path,\n tool_name: e.tool_name,\n resource_type: e.resource_type,\n requested_command: e.requested_command,\n workdir: ctx.workdir,\n granted: e.granted,\n }\n : {\n type: \"message\" as const,\n message_id: e.uuid,\n parent_id: e.parent_uuid,\n timestamp: e.timestamp,\n message: e.message,\n model: e.model,\n usage: e.usage,\n finish_reason: e.finish_reason,\n },\n ),\n }),\n );\n });\n\n /** 重命名 / 归档状态(归档 = 只读,恢复后才可继续会话) */\n app.patch(\"/sessions/:id\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const { title, archived } = patchPayloadSchema.parse(await c.req.json());\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (archived === true && ctx.index.isRunning(sessionId)) {\n fail(400, \"该会话正在运行中,请先停止运行再归档\");\n }\n if (title !== undefined) ctx.index.rename(sessionId, title);\n if (archived !== undefined) ctx.index.setArchived(sessionId, archived);\n return c.json(\n ok(ctx.index.get(sessionId), archived === undefined ? \"会话已重命名\" : archived ? \"会话已归档\" : \"会话已恢复\"),\n );\n });\n\n /** 手动压缩会话上下文(不删除完整轨迹) */\n app.post(\"/sessions/:id/compact-context\", async (c) => {\n const sessionId = c.req.param(\"id\");\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再压缩\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中,请等待完成后再压缩\");\n const history = ctx.store.buildHistory(sessionId);\n if (history.length === 0) fail(400, \"会话没有可压缩的内容\");\n\n // 沿用会话最近一次运行的模型(转录里 assistant 行带 model 元数据)\n const { entries } = ctx.store.read(sessionId);\n const lastModel = [...entries].reverse().find((e) => isMessageEntry(e) && e.model);\n const modelRef = (lastModel && isMessageEntry(lastModel) && lastModel.model) || \"\";\n const resolved = ctx.resolver.resolve(modelRef);\n\n const result: CompactionResult | null = await compact(\n resolved.protocol,\n resolved.modelId,\n [{ role: \"system\", content: buildSystem(refreshWorkspace().fragments) }, ...history],\n {},\n );\n if (!result) fail(502, \"压缩失败:模型未能生成摘要,请稍后重试\");\n\n const entry = ctx.store.appendCompaction(sessionId, result);\n ctx.index.touchAfterAppend(sessionId, {\n leaf_uuid: entry.uuid,\n entry_count: entries.length + 1,\n });\n return c.json(\n ok(\n {\n summary: result.summary,\n tokens_before: result.tokens_before,\n tokens_after: result.tokens_after,\n compaction_id: entry.uuid,\n },\n \"会话上下文已压缩\",\n ),\n );\n });\n\n /** 从指定 user message 重新提问(可替换问题内容) */\n app.post(\"/sessions/:id/retry\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const payload = retryPayloadSchema.parse(await c.req.json());\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再重试\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中,请先停止运行再重试\");\n\n const { entries } = ctx.store.read(sessionId);\n const target = entries.find((e) => e.uuid === payload.message_id);\n if (!target) fail(404, \"会话中没有这条记录,可能已被改写\");\n if (!isMessageEntry(target) || target.message.role !== \"user\") {\n fail(400, \"只能重试用户消息\");\n }\n const content = payload.content ?? (target.message.content ?? \"\");\n if (payload.permission_mode !== undefined) {\n ctx.grants.setFullAccess(sessionId, payload.permission_mode === \"full\");\n }\n\n // 端点和工作区上下文校验先于不可逆的历史删除。\n ctx.resolver.resolve(payload.model);\n const workspace = refreshWorkspace();\n ctx.store.discardFromUserMessage(sessionId, payload.message_id);\n const history = ctx.store.buildHistory(sessionId);\n const remaining = ctx.store.read(sessionId).entries.length;\n\n const { messageId, runId, model, agentInstanceId } = await launchUserMessage({\n sessionId,\n content,\n model: payload.model,\n history,\n entryCount: remaining,\n workspace,\n settings: {\n ...payload.settings,\n ...(payload.reasoning_effort ? { reasoning_effort: payload.reasoning_effort } : {}),\n },\n ...(payload.agent_instance_id ? { agentInstanceId: payload.agent_instance_id } : {}),\n });\n return c.json(ok({ session_id: sessionId, message_id: messageId, run_id: runId, model, agent_instance_id: agentInstanceId }, \"已重新提交\"), 202);\n });\n\n /**\n * 提权确认:用户在前端确认后,把路径登记进会话级授权清单,并自动\n * 重发最近一条用户消息续跑(效果 = 授权后从中断处继续)。\n * 授权粒度是「会话 × 路径前缀」,随会话生命周期存在(进程内,不落盘)。\n */\n app.post(\"/sessions/:id/grant-access\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const { escalation_id, granted, resolved_path } = z.object({\n escalation_id: z.string().min(1),\n granted: z.boolean(),\n resolved_path: z.string().min(1),\n }).parse(await c.req.json());\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isArchived(sessionId)) fail(400, \"会话已归档,请先恢复后再授权\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中\");\n\n // 用 escalation_id 定位并校验目标路径,防前端传错/被篡改\n const { entries } = ctx.store.read(sessionId);\n const esc = entries.find(\n (e) => e.type === \"escalation\" && e.uuid === escalation_id,\n );\n if (!esc || esc.type !== \"escalation\") fail(404, \"提权请求不存在或已过期\");\n if (esc.resolved_path !== resolved_path) fail(400, \"授权路径与提权请求不一致\");\n if (esc.granted !== null && esc.granted !== undefined) fail(400, \"该提权请求已处理过\");\n\n const lastModelEntry = [...entries].reverse().find(\n (entry) => isMessageEntry(entry) && Boolean(entry.model?.trim()),\n );\n const model = lastModelEntry && isMessageEntry(lastModelEntry) ? lastModelEntry.model?.trim() ?? \"\" : \"\";\n if (!model) fail(400, \"无法确定会话使用的模型,请重新发送消息\");\n ctx.resolver.resolve(model);\n\n // 落确认结果(回放时卡片显示已授权/已拒绝)\n ctx.store.resolveEscalation(sessionId, escalation_id, granted);\n\n if (!granted) {\n // 拒绝不回死对话:用「工具被拒」的回执补齐上下文后续跑,\n // 让模型直接向用户说明或给出替代方案,而不是静默结束\n const history = ctx.store.buildHistoryBeforeEscalation(sessionId, escalation_id);\n const assistantEntry = entries.find(\n (e) => e.uuid === esc.parent_uuid && isMessageEntry(e) && e.message.role === \"assistant\",\n );\n if (assistantEntry && isMessageEntry(assistantEntry)) {\n history.push(assistantEntry.message);\n for (const call of assistantEntry.message.tool_calls ?? []) {\n const recorded = entries.find(\n (e) => isMessageEntry(e) && e.message.role === \"tool\" && e.message.tool_call_id === call.id,\n );\n // 被提权拦下的调用(无真实结果或只有中断回执)改写为明确的拒绝语义,\n // 其余调用沿用已记录的真实结果\n const interrupted = !recorded\n || (isMessageEntry(recorded) && recorded.message.is_error === true\n && recorded.message.content === \"操作已被中断,工具未执行完成。\");\n if (call.name === esc.tool_name && interrupted) {\n history.push({\n role: \"tool\",\n tool_call_id: call.id,\n name: call.name,\n content: \"用户拒绝了本次权限请求,该操作未执行。不要重试相同或类似的越权操作;直接向用户说明无法执行的原因,或给出不需要该权限的替代方案。\",\n is_error: true,\n });\n } else if (recorded && isMessageEntry(recorded)) {\n history.push(recorded.message);\n } else {\n history.push({\n role: \"tool\",\n tool_call_id: call.id,\n name: call.name,\n content: \"操作已被中断,工具未执行完成。\",\n is_error: true,\n });\n }\n }\n }\n const { runId, model: resumedModel, agentInstanceId } = await launchUserMessage({\n sessionId,\n content: \"\",\n model,\n history,\n entryCount: entries.length,\n recordUser: false,\n });\n return c.json(ok({ session_id: sessionId, granted: false, run_id: runId, model: resumedModel, agent_instance_id: agentInstanceId }, \"已拒绝授权,由模型继续应答\"), 202);\n }\n if (esc.resource_type === \"command\") {\n ctx.grants.grantCapabilityOnce(sessionId, resolved_path);\n } else {\n ctx.grants.grantOnce(sessionId, resolved_path);\n }\n\n // 自动续跑:沿用原始 user 历史,不追加新的 user 记录;\n // 提权中断的运行已由 recorder 终态收尾补配对,轨迹仍可完整回放。\n const lastUser = [...entries].reverse().find(\n (e) => isMessageEntry(e) && e.message.role === \"user\",\n );\n if (!lastUser || !isMessageEntry(lastUser)) fail(400, \"会话中没有可续跑的用户消息\");\n const history = ctx.store.buildHistoryBeforeEscalation(sessionId, escalation_id);\n const { messageId, runId, model: resumedModel, agentInstanceId } = await launchUserMessage({\n sessionId,\n content: \"\",\n model,\n history,\n entryCount: entries.length,\n recordUser: false,\n });\n return c.json(\n ok({ session_id: sessionId, message_id: messageId, run_id: runId, model: resumedModel, agent_instance_id: agentInstanceId, granted_path: resolved_path }, \"已授权并继续执行\"),\n 202,\n );\n });\n\n /** 删除会话(转录文件与索引一并删除;运行中拒绝) */\n app.delete(\"/sessions/:id\", (c) => {\n const sessionId = c.req.param(\"id\");\n if (!ctx.store.exists(sessionId)) fail(404, \"会话不存在\");\n if (ctx.index.isRunning(sessionId)) fail(400, \"该会话正在运行中,请先停止运行再删除\");\n ctx.store.delete(sessionId);\n ctx.index.remove(sessionId);\n ctx.grants.drop(sessionId); // 授权随会话生命周期\n return c.json(ok({}, \"会话已删除\"));\n });\n\n /** SSE 跟随会话当前消息的处理事件(支持 Last-Event-ID 断线续传) */\n app.get(\"/sessions/:id/events\", async (c) => {\n const sessionId = c.req.param(\"id\");\n const cursor = Number(c.req.header(\"last-event-id\") ?? 0);\n // 在响应建立前完成存在性和游标校验,404/400 仍能以标准 JSON 返回\n const initial = await ctx.registry.getSessionEvents(sessionId, cursor, 0);\n\n const stream = new ReadableStream<Uint8Array>({\n async start(controller) {\n const encoder = new TextEncoder();\n let current = cursor;\n let { events, terminal } = initial;\n try {\n for (;;) {\n for (const stored of events) {\n current = stored.sequence;\n const { run_id: _omit, ...payload } = stored.event;\n controller.enqueue(\n encoder.encode(\n `id: ${stored.sequence}\\nevent: ${stored.event.type}\\ndata: ${JSON.stringify(payload)}\\n\\n`,\n ),\n );\n }\n if (terminal) return;\n ({ events, terminal } = await ctx.registry.getSessionEvents(sessionId, current, 15));\n if (events.length === 0 && !terminal) {\n controller.enqueue(encoder.encode(\": heartbeat\\n\\n\"));\n }\n }\n } finally {\n controller.close();\n }\n },\n });\n return new Response(stream, {\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n },\n });\n });\n\n /** 停止会话当前消息的模型处理(幂等) */\n app.post(\"/sessions/:id/stop\", async (c) => {\n await ctx.registry.cancelSession(c.req.param(\"id\"));\n return c.json(ok({}, \"已请求停止会话\"));\n });\n\n /**\n * Skills 权威列表:与 run 启动时同一套发现逻辑,附全局开关与逐项启用状态。\n * 全局停用(enable_skills=false)时仍返回清单,便于管理界面操作开关。\n */\n app.get(\"/skills\", (c) => {\n const opts = currentWorkspaceOptions();\n const disabled = new Set(opts.disabledSkills ?? []);\n const discovered = discoverSkills(ctx.workdir, opts.skills ?? {});\n return c.json(ok({\n enabled: opts.enableSkills !== false,\n skills: discovered.skills.map((skill) => ({\n name: skill.name,\n description: skill.description,\n scope: skill.scope,\n enabled: !disabled.has(skill.name),\n path: skill.skillFile,\n ...(skill.license ? { license: skill.license } : {}),\n })),\n warnings: discovered.warnings,\n }));\n });\n\n /** 单文件查看上限(文档/脚本查看场景,超出部分截断返回) */\n const SKILL_FILE_VIEW_MAX_BYTES = 256_000;\n\n /** 按名称解析当前生效的 skill(与 run 注入同一套发现与覆盖规则) */\n const findSkill = (name: string): { skill: SkillInfo; disabled: Set<string> } | null => {\n const opts = currentWorkspaceOptions();\n const discovered = discoverSkills(ctx.workdir, opts.skills ?? {});\n const skill = discovered.skills.find((item) => item.name === name);\n return skill ? { skill, disabled: new Set(opts.disabledSkills ?? []) } : null;\n };\n\n /** Skill 详情:frontmatter 元信息 + SKILL.md 全文 + 资源文件清单(供管理界面展示) */\n app.get(\"/skills/:name\", (c) => {\n const found = findSkill(c.req.param(\"name\"));\n if (!found) throw new HttpError(404, `skill 不存在:${c.req.param(\"name\")}`);\n const { skill, disabled } = found;\n const loaded = loadSkillContent(skill);\n return c.json(ok({\n name: skill.name,\n description: skill.description,\n scope: skill.scope,\n enabled: !disabled.has(skill.name),\n path: skill.skillFile,\n ...(skill.license ? { license: skill.license } : {}),\n ...(skill.metadata ? { metadata: skill.metadata } : {}),\n content: loaded.content,\n contentTruncated: loaded.contentTruncated,\n resources: loaded.resources,\n }));\n });\n\n /** 读取 skill 目录内的单个资源文件(文档/脚本预览;限 skill 根内、非符号链接、限大小) */\n app.get(\"/skills/:name/file\", (c) => {\n const found = findSkill(c.req.param(\"name\"));\n if (!found) throw new HttpError(404, `skill 不存在:${c.req.param(\"name\")}`);\n const rel = (c.req.query(\"path\") ?? \"\").trim().replaceAll(\"\\\\\", \"/\").replace(/^\\/+/, \"\");\n if (!rel) throw new HttpError(400, \"缺少 path 参数\");\n const root = found.skill.root;\n // 注意不能用 path.join 对比做越界判断(join 同样会归一化 ..),用路径前缀判定\n const target = path.resolve(root, rel);\n if (!target.startsWith(root + path.sep)) {\n throw new HttpError(400, \"路径越界:仅允许 skill 目录内的文件\");\n }\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(target);\n } catch {\n throw new HttpError(404, `文件不存在:${rel}`);\n }\n if (stat.isSymbolicLink() || !stat.isFile()) {\n throw new HttpError(400, \"仅支持读取普通文件\");\n }\n const truncated = stat.size > SKILL_FILE_VIEW_MAX_BYTES;\n const data = Buffer.alloc(Math.min(stat.size, SKILL_FILE_VIEW_MAX_BYTES));\n const fd = fs.openSync(target, \"r\");\n try {\n fs.readSync(fd, data, 0, data.length, 0);\n } finally {\n fs.closeSync(fd);\n }\n return c.json(ok({ path: rel, content: data.toString(\"utf-8\"), truncated }));\n });\n\n app.get(\"/health\", (c) => c.json(ok({ status: \"ok\" })));\n\n return app;\n}\n","/**\n * AGENTS.md 发现与格式化(对齐 https://agents.md/)。\n *\n * 根目录的 AGENTS.override.md 优先于 AGENTS.md;每个嵌套目录同样遵循该\n * 规则。根目录有效文件正文常驻注入,嵌套文件只列出路径供模型按需读取。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/** 嵌套扫描最大深度(相对 workdir);根 AGENTS.md 本身不计入 */\nexport const AGENTS_MD_MAX_DEPTH = 6;\n/** 嵌套扫描最多访问的目录数,防止超大仓库失控 */\nexport const AGENTS_MD_MAX_DIRS = 2_000;\n/** 根 AGENTS.md 注入上限(字节) */\nexport const AGENTS_MD_MAX_BYTES = 32_000;\n/** 格式化后提示词片段的总字节上限 */\nexport const AGENTS_MD_MAX_FORMAT_BYTES = 48_000;\n\nconst SKIP_DIR_NAMES = new Set([\".git\", \"node_modules\"]);\n\ntype AgentsMdName = \"AGENTS.md\" | \"AGENTS.override.md\";\n\nexport interface AgentsMdContext {\n rootPath: string | null;\n rootInstructions: string | null;\n rootTruncated: boolean;\n nestedPaths: string[];\n warnings: string[];\n}\n\nexport interface DiscoverAgentsMdOptions {\n maxDepth?: number;\n maxDirs?: number;\n maxBytes?: number;\n}\n\nexport interface FormatAgentsMdOptions {\n maxBytes?: number;\n}\n\nfunction normalizeText(raw: string): string {\n return raw.replace(/^\\uFEFF/, \"\").replace(/\\r\\n?/g, \"\\n\");\n}\n\nfunction readFilePrefix(file: string, maxBytes: number): { text: string; truncated: boolean } {\n const fd = fs.openSync(file, \"r\");\n try {\n const size = fs.fstatSync(fd).size;\n const length = Math.min(size, Math.max(0, maxBytes) + 4);\n const buffer = Buffer.alloc(length);\n fs.readSync(fd, buffer, 0, length, 0);\n return { text: buffer.toString(\"utf-8\"), truncated: size > length };\n } finally {\n fs.closeSync(fd);\n }\n}\n\nfunction truncateUtf8(text: string, maxBytes: number): string {\n const limit = Math.max(0, maxBytes);\n const data = Buffer.from(text, \"utf-8\");\n if (data.length <= limit) return text;\n let end = limit;\n while (end > 0) {\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(data.subarray(0, end));\n } catch {\n end -= 1;\n }\n }\n return \"\";\n}\n\nfunction fileIfPresent(dir: string, name: AgentsMdName, warnings?: string[]): string | null {\n const candidate = path.join(dir, name);\n try {\n const stat = fs.lstatSync(candidate);\n return !stat.isSymbolicLink() && stat.isFile() ? candidate : null;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n warnings?.push(`访问 ${candidate} 失败:${error instanceof Error ? error.message : String(error)}`);\n }\n return null;\n }\n}\n\nfunction effectiveFile(dir: string, warnings?: string[]): string | null {\n return fileIfPresent(dir, \"AGENTS.override.md\", warnings) ?? fileIfPresent(dir, \"AGENTS.md\", warnings);\n}\n\nexport function discoverAgentsMd(\n workdir: string,\n opts: DiscoverAgentsMdOptions = {},\n): AgentsMdContext {\n const maxDepth = opts.maxDepth ?? AGENTS_MD_MAX_DEPTH;\n const maxDirs = opts.maxDirs ?? AGENTS_MD_MAX_DIRS;\n const maxBytes = opts.maxBytes ?? AGENTS_MD_MAX_BYTES;\n const root = path.resolve(workdir);\n const warnings: string[] = [];\n const nestedPaths: string[] = [];\n let rootInstructions: string | null = null;\n let rootTruncated = false;\n const rootFile = effectiveFile(root, warnings);\n const rootPath = rootFile;\n\n if (rootFile) {\n try {\n const read = readFilePrefix(rootFile, maxBytes);\n const normalized = normalizeText(read.text);\n const data = Buffer.from(normalized, \"utf-8\");\n rootTruncated = read.truncated || data.length > maxBytes;\n rootInstructions = rootTruncated ? truncateUtf8(normalized, maxBytes) : normalized;\n if (rootTruncated) {\n warnings.push(`根 ${path.basename(rootFile)} 超过 ${maxBytes} 字节,已截断注入;完整内容请用 read 工具读取 ${rootFile}`);\n }\n } catch (error) {\n warnings.push(`读取 ${rootFile} 失败:${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n try {\n if (!fs.statSync(root).isDirectory()) return { rootPath, rootInstructions, rootTruncated, nestedPaths, warnings };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n warnings.push(`访问工作目录 ${root} 失败:${error instanceof Error ? error.message : String(error)}`);\n }\n return { rootPath, rootInstructions, rootTruncated, nestedPaths, warnings };\n }\n\n let visited = 0;\n let depthWarned = false;\n let dirsWarned = false;\n const warnDepth = (): void => {\n if (!depthWarned) {\n depthWarned = true;\n warnings.push(`AGENTS.md 嵌套扫描达到深度上限 ${maxDepth},已停止更深目录扫描`);\n }\n };\n const warnDirs = (): void => {\n if (!dirsWarned) {\n dirsWarned = true;\n warnings.push(`AGENTS.md 嵌套扫描达到目录上限 ${maxDirs},已停止`);\n }\n };\n const walk = (dir: string, depth: number): void => {\n if (depth > maxDepth) {\n warnDepth();\n return;\n }\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (error) {\n warnings.push(`遍历目录 ${dir} 失败:${error instanceof Error ? error.message : String(error)}`);\n return;\n }\n for (const entry of entries) {\n if (SKIP_DIR_NAMES.has(entry.name) || entry.isSymbolicLink() || !entry.isDirectory()) continue;\n if (visited >= maxDirs) {\n warnDirs();\n return;\n }\n visited += 1;\n const full = path.join(dir, entry.name);\n const candidate = effectiveFile(full, warnings);\n if (candidate) nestedPaths.push(candidate);\n walk(full, depth + 1);\n }\n };\n walk(root, 1);\n\n nestedPaths.sort((a, b) => a.localeCompare(b));\n return { rootPath, rootInstructions, rootTruncated, nestedPaths, warnings };\n}\n\n/** 将发现结果格式化为系统提示词片段;无内容时返回空串。 */\nexport function formatAgentsMdContext(\n context: AgentsMdContext,\n opts: FormatAgentsMdOptions = {},\n): string {\n if (!context.rootInstructions && context.nestedPaths.length === 0 && context.warnings.length === 0) return \"\";\n const lines = [\n \"# 项目约定 (AGENTS.md)\",\n \"以下是仓库给 coding agent 的项目级指令。用户当轮明确要求覆盖其中冲突项。\",\n \"修改某个子目录中的文件前,若下方列出了更近的嵌套 AGENTS.md,先用 read 读取该路径向上最近的一份;更近者优先。\",\n ];\n if (context.rootInstructions) {\n lines.push(\"\", \"## 根 AGENTS.md\");\n if (context.rootPath) lines.push(`路径:${context.rootPath}`);\n if (context.rootTruncated) lines.push(\"(正文已因体积上限截断;需要全文时请 read 上述路径)\");\n lines.push(normalizeText(context.rootInstructions).trimEnd());\n }\n if (context.nestedPaths.length > 0) {\n lines.push(\"\", \"## 嵌套 AGENTS.md\", \"仅列出路径,不预加载正文:\");\n for (const p of context.nestedPaths) lines.push(`- ${p}`);\n }\n if (context.warnings.length > 0) lines.push(\"\", \"扫描告警:\", ...context.warnings.map((warning) => `- ${warning}`));\n return truncateUtf8(lines.join(\"\\n\"), opts.maxBytes ?? AGENTS_MD_MAX_FORMAT_BYTES);\n}\n","/**\n * 工作区上下文装配:把 AGENTS.md 与 Skills 拼成可注入的提示词片段。\n */\nimport {\n discoverAgentsMd,\n formatAgentsMdContext,\n type AgentsMdContext,\n type DiscoverAgentsMdOptions,\n} from \"./agents-md.js\";\nimport {\n discoverSkills,\n formatSkillsCatalog,\n type DiscoverSkillsOptions,\n type SkillsContext,\n} from \"./skills.js\";\n\nexport * from \"./agents-md.js\";\nexport * from \"./skills.js\";\n\nexport interface WorkspaceContextOptions {\n enableAgentsMd?: boolean;\n enableSkills?: boolean;\n /** 停用的 skill 名称名单:发现后过滤,不注入 catalog(文件保留,便于随时重新启用) */\n disabledSkills?: string[];\n agentsMd?: DiscoverAgentsMdOptions;\n skills?: DiscoverSkillsOptions;\n}\n\nexport interface WorkspaceContext {\n agents: AgentsMdContext | null;\n skills: SkillsContext;\n /** 可直接拼进 system prompt 的非空片段 */\n fragments: string[];\n warnings: string[];\n}\n\nexport function loadWorkspaceContext(\n workdir: string,\n opts: WorkspaceContextOptions = {},\n): WorkspaceContext {\n const enableAgentsMd = opts.enableAgentsMd !== false;\n const enableSkills = opts.enableSkills !== false;\n const warnings: string[] = [];\n const fragments: string[] = [];\n\n let agents: AgentsMdContext | null = null;\n if (enableAgentsMd) {\n agents = discoverAgentsMd(workdir, opts.agentsMd);\n warnings.push(...agents.warnings);\n const fragment = formatAgentsMdContext(agents);\n if (fragment) fragments.push(fragment);\n }\n\n let skills: SkillsContext = enableSkills\n ? discoverSkills(workdir, opts.skills)\n : { skills: [], warnings: [] };\n const disabled = new Set(opts.disabledSkills ?? []);\n if (disabled.size > 0 && skills.skills.length > 0) {\n skills = { ...skills, skills: skills.skills.filter((skill) => !disabled.has(skill.name)) };\n }\n warnings.push(...skills.warnings);\n const catalog = formatSkillsCatalog(skills);\n if (catalog) fragments.push(catalog);\n\n return { agents, skills, fragments, warnings };\n}\n","/**\n * 会话元数据索引(index.json)—— JSONL 文件的查询索引,不是事实源。\n *\n * 设计(移植自 MovieClaw 的「文件是事实源,DB 只是索引」并去 SQLite 化):\n * - 索引随时可由 sessions/ 目录的 JSONL 文件整体重建(rebuild);\n * - 写入顺序固定「先落 JSONL 文件、后更新索引」,两步之间崩溃只会让索引\n * 落后,启动时扫描重建即自愈;\n * - 写盘一律 tmp + rename 原子换入;\n * - 运行状态不持久化静态 status:只记 last_heartbeat 时间戳,进程硬崩后\n * 心跳自然停止,超过超时窗即视为已结束(状态自愈)。\n * - 归档标记 archived_at 与 title 同级:只存索引不进 JSONL,rebuild 时\n * 从旧索引保留;代价是 index.json 整体丢失时归档/标题归零(可接受)。\n *\n * 升级预留:未来 SQLite 化只需用相同方法表面(create/get/touchAfterAppend/\n * rename/setArchived/markRunning/heartbeat/finishRun/isRunning/list/remove/\n * rebuild)替换本类实现,路由层不感知存储介质。\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { SessionSummary } from \"../agent/sessions.js\";\nimport { PREVIEW_MAX_CHARS } from \"../agent/sessions.js\";\n\n/** 心跳超时窗(毫秒):超过即视为运行已结束;须大于记录器的心跳间隔 */\nexport const HEARTBEAT_TIMEOUT_MS = 30_000;\n\nexport interface RunningState {\n run_id: string;\n /** 最近一次心跳的 epoch 毫秒 */\n last_heartbeat: number;\n}\n\nexport interface SessionMeta {\n session_id: string;\n created_at: string;\n title: string | null;\n last_prompt: string | null;\n entry_count: number;\n leaf_uuid: string | null;\n last_active: string;\n /** 归档时间(ISO);null = 活跃。归档 = 只读,恢复后才能继续会话 */\n archived_at: string | null;\n running: RunningState | null;\n}\n\nexport class SessionIndex {\n private readonly file: string;\n private readonly metas = new Map<string, SessionMeta>();\n\n constructor(indexFile: string) {\n this.file = indexFile;\n this.load();\n }\n\n /** 启动时加载;文件不存在/损坏则从空开始(rebuild 会补齐) */\n private load(): void {\n try {\n const raw = JSON.parse(fs.readFileSync(this.file, \"utf-8\")) as { sessions?: SessionMeta[] };\n for (const meta of raw.sessions ?? []) this.metas.set(meta.session_id, meta);\n } catch {\n this.metas.clear();\n }\n }\n\n /** 从事实源整体重建(启动自愈):扫描结果单向覆盖索引 */\n rebuild(summaries: SessionSummary[]): void {\n for (const s of summaries) {\n const existing = this.metas.get(s.session_id);\n this.metas.set(s.session_id, {\n session_id: s.session_id,\n created_at: s.created_at,\n // 已有人工标题时保留(文件里不存标题,扫描回填的是首条 user 消息)\n title: existing?.title ?? s.title,\n last_prompt: s.last_prompt,\n entry_count: s.entry_count,\n leaf_uuid: s.leaf_uuid,\n last_active: s.last_timestamp,\n // 归档标记与 title 同级:从旧索引保留,不被扫描回填覆盖\n archived_at: existing?.archived_at ?? null,\n running: null, // 进程刚启动,任何「运行中」都是上一世的残留\n });\n }\n this.persist();\n }\n\n create(sessionId: string): void {\n const now = new Date().toISOString();\n this.metas.set(sessionId, {\n session_id: sessionId,\n created_at: now,\n title: null,\n last_prompt: null,\n entry_count: 0,\n leaf_uuid: null,\n last_active: now,\n archived_at: null,\n running: null,\n });\n this.persist();\n }\n\n get(sessionId: string): SessionMeta | undefined {\n return this.metas.get(sessionId);\n }\n\n /** 每次追加 entry 后刷新链尾/计数/预览;title 仅在传入时更新(首条消息) */\n touchAfterAppend(\n sessionId: string,\n update: { leaf_uuid: string; entry_count: number; last_prompt?: string; title?: string },\n ): void {\n const meta = this.metas.get(sessionId);\n if (!meta) return;\n meta.leaf_uuid = update.leaf_uuid;\n meta.entry_count = update.entry_count;\n meta.last_active = new Date().toISOString();\n if (update.last_prompt !== undefined) {\n meta.last_prompt = update.last_prompt.slice(0, PREVIEW_MAX_CHARS);\n }\n if (update.title !== undefined && meta.title === null) {\n meta.title = update.title.slice(0, PREVIEW_MAX_CHARS);\n }\n this.persist();\n }\n\n rename(sessionId: string, title: string): boolean {\n const meta = this.metas.get(sessionId);\n if (!meta) return false;\n meta.title = title.slice(0, PREVIEW_MAX_CHARS);\n this.persist();\n return true;\n }\n\n /** 归档/恢复(null 表示恢复为活跃);会话不存在返回 false */\n setArchived(sessionId: string, archived: boolean): boolean {\n const meta = this.metas.get(sessionId);\n if (!meta) return false;\n meta.archived_at = archived ? new Date().toISOString() : null;\n this.persist();\n return true;\n }\n\n /** 是否已归档(归档 = 只读) */\n isArchived(sessionId: string): boolean {\n return this.metas.get(sessionId)?.archived_at != null;\n }\n\n markRunning(sessionId: string, runId: string): void {\n const meta = this.metas.get(sessionId);\n if (!meta) return;\n meta.running = { run_id: runId, last_heartbeat: Date.now() };\n this.persist();\n }\n\n heartbeat(sessionId: string): void {\n const meta = this.metas.get(sessionId);\n if (!meta?.running) return;\n meta.running.last_heartbeat = Date.now();\n this.persist();\n }\n\n finishRun(sessionId: string): void {\n const meta = this.metas.get(sessionId);\n if (!meta) return;\n meta.running = null;\n this.persist();\n }\n\n /** 是否有正在进行的消息处理:运行标记存在且心跳未超时 */\n isRunning(sessionId: string): boolean {\n const running = this.metas.get(sessionId)?.running;\n if (!running) return false;\n return Date.now() - running.last_heartbeat < HEARTBEAT_TIMEOUT_MS;\n }\n\n /** 按最后活跃时间倒序分页 */\n list(limit: number, offset: number): SessionMeta[] {\n return [...this.metas.values()]\n .sort((a, b) => b.last_active.localeCompare(a.last_active))\n .slice(offset, offset + limit);\n }\n\n remove(sessionId: string): void {\n this.metas.delete(sessionId);\n this.persist();\n }\n\n private persist(): void {\n const dir = path.dirname(this.file);\n fs.mkdirSync(dir, { recursive: true });\n const tmp = `${this.file}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify({ sessions: [...this.metas.values()] }, null, 2));\n fs.renameSync(tmp, this.file);\n }\n}\n"],"mappings":"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","names":["errMsg","safeParse","ok","import_zod","import_zod","path","os","crypto","fs","import_node_crypto","truncateMiddle","import_node_path","path","crypto","truncateMiddle","import_node_fs","import_node_path","import_node_crypto","import_node_fs","import_node_path","import_zod","import_node_fs","import_node_path","fs","path","fs","path","crypto","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","import_node_crypto","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","crypto","import_node_fs","import_zod","import_node_crypto","session","crypto","truncateMiddle","argsSchema","fs","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","import_node_path","import_node_fs","import_node_os","import_node_path","os","path","parseYaml","fs","path","import_node_fs","import_node_path","import_zod","argsSchema","fs","path","import_node_fs","import_node_path","import_zod","IGNORE_NAMES","argsSchema","fs","globToRegExp","path","import_node_fs","import_node_path","import_node_crypto","import_zod","argsSchema","fs","path","crypto","import_zod","argsSchema","path","fs","import_node_path","import_node_fs","import_node_path","import_zod","path","fs","import_node_fs","import_zod","import_node_crypto","crypto","fs","import_hono","import_node_fs","import_node_path","import_zod","import_node_fs","import_node_path","fs","path","history","runId","resumedModel","agentInstanceId","path","fs","import_node_fs","import_node_path","fs","path","path"]}
|