@cxyhhhhh/qqbot-cli 0.1.0-dev.202606011703

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/loader.ts","../src/config/schema.ts","../src/config/watcher.ts","../src/runner.ts","../src/backend/echo.ts","../src/telemetry/metrics.ts","../src/telemetry/constants.ts","../src/backend/openai.ts","../src/cloudagent/acp-client.ts","../src/cloudagent/acp-transport.ts","../src/cloudagent/sandbox.ts","../src/telemetry/client-interceptor.ts","../src/cloudagent/connection-pool.ts","../src/backend/cloudagent.ts","../src/mcp/server.ts","../src/mcp/openapi-tools.ts","../src/slash/index.ts","../src/envelope.ts","../src/display.ts","../src/reply.ts","../src/telemetry/middleware.ts"],"sourcesContent":["/**\n * 配置文件加载器\n *\n * 支持 YAML / JSON 格式,环境变量 ${VAR} 插值。\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { botConfigSchema, type BotConfig } from \"./schema.js\";\n\n/**\n * 对字符串中的 ${VAR} 或 ${VAR:-default} 进行环境变量插值。\n *\n * - ${VAR} → process.env[VAR],未设置则为 \"\"\n * - ${VAR:-default} → process.env[VAR],未设置或为空则用 default\n */\nfunction interpolateEnv(text: string): string {\n return text.replace(/\\$\\{([^}]+)\\}/g, (_, expr: string) => {\n const match = expr.match(/^([^:}-]+)(?::-([\\s\\S]*))?$/);\n if (!match) return \"\";\n const varName = match[1].trim();\n const defaultVal = match[2] ?? \"\";\n const val = process.env[varName];\n if (val === undefined || val === \"\") {\n return defaultVal;\n }\n return val;\n });\n}\n\n/**\n * 加载并校验配置文件。\n */\nexport async function loadConfig(configPath: string): Promise<BotConfig> {\n const resolved = path.resolve(configPath);\n\n if (!fs.existsSync(resolved)) {\n throw new Error(`配置文件不存在: ${resolved}\\n提示: 运行 qqbot-cli init 生成模板配置`);\n }\n\n const raw = fs.readFileSync(resolved, \"utf-8\");\n const interpolated = interpolateEnv(raw);\n\n let data: unknown;\n const ext = path.extname(resolved).toLowerCase();\n if (ext === \".yaml\" || ext === \".yml\") {\n data = parseYaml(interpolated);\n } else if (ext === \".json\" || ext === \".jsonc\") {\n data = JSON.parse(interpolated);\n } else {\n // 尝试 YAML\n try {\n data = parseYaml(interpolated);\n } catch {\n data = JSON.parse(interpolated);\n }\n }\n\n const result = botConfigSchema.safeParse(data);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`配置校验失败:\\n${issues}`);\n }\n\n // 后端类型特定校验\n const config = result.data;\n if (config.backend.type === \"cloudagent\" && !config.backend.cloudagent) {\n throw new Error(\"backend.type=cloudagent 时,backend.cloudagent 配置块必填\");\n }\n if (config.backend.type === \"openai\" && !config.backend.openai) {\n throw new Error(\"backend.type=openai 时,backend.openai 配置块必填\");\n }\n\n return config;\n}\n","/**\n * 配置 Zod Schema + 类型定义\n */\n\nimport { z } from \"zod\";\n\nconst coerceString = z.preprocess(\n (val) => (val === undefined || val === null ? val : String(val)),\n z.string(),\n);\n\nconst qqSchema = z.object({\n appId: coerceString.pipe(z.string().min(1, \"qq.appId 必填\")),\n appSecret: coerceString.pipe(z.string().min(1, \"qq.appSecret 必填\")),\n markdown: z.boolean().default(false),\n /** 自定义 User-Agent(默认 qqbot-cli/<version>) */\n userAgent: z.string().optional(),\n /** QQ Open Platform API 基址(默认 https://api.sgroup.qq.com) */\n baseUrl: z.string().optional(),\n /** Token 接口基址(默认 https://bots.qq.com) */\n tokenBaseUrl: z.string().optional(),\n /**\n * 启动时 Token 获取策略。\n * - \"sync\" (默认): 阻塞等待 token 获取成功后再接受流量,凭证错误立即暴露。\n * - \"async\": 后台异步获取 token,服务更快启动,但首次请求可能失败。\n */\n tokenPrefetch: z.enum([\"sync\", \"async\"]).default(\"sync\"),\n /**\n * 事件传输模式。\n * - \"websocket\" (默认): WS 长连(心跳/重连/RESUME)\n * - \"webhook\": QQ 平台 POST 回调到你的 HTTPS 端点\n */\n transport: z.enum([\"websocket\", \"webhook\"]).default(\"websocket\"),\n /** Webhook 模式配置(仅 transport=webhook 时生效) */\n webhook: z.object({\n /** 监听端口,默认 8080 */\n port: z.number().default(8080),\n /** 监听路径,默认 \"/\" */\n path: z.string().default(\"/callback\"),\n }).default({}),\n});\n\nconst cloudagentSchema = z.object({\n apiKey: z.string().optional(),\n endpoint: z.string().default(\"https://www.codebuddy.cn/v2\"),\n sandbox: z.object({\n /** auto: 自动创建 Runtime | manual: 指定 runtimeId | direct: 直连 ACP 端点 */\n mode: z.enum([\"auto\", \"manual\", \"direct\"]).default(\"auto\"),\n runtimeName: z.string().optional(),\n runtimeId: z.string().optional(),\n /** direct 模式:ACP 端点 URL(如 http://localhost:65225/acp) */\n acpEndpoint: z.string().optional(),\n /** direct 模式:ACP 认证 token */\n acpToken: z.string().optional(),\n }).default({}),\n manifest: z.object({\n systemPrompt: z.string().optional(),\n systemPromptFile: z.string().optional(),\n }).default({}),\n acp: z.object({\n lazyConnect: z.boolean().default(true),\n maxRetries: z.number().default(20),\n retryIntervalMs: z.number().default(3000),\n /** 等待下一个 ACP 事件的超时时间(ms),工具调用可能耗时较长。默认 180s */\n eventTimeoutMs: z.number().default(180_000),\n }).default({}),\n /** 多用户 Session 连接池配置 */\n session: z.object({\n /** 最大并发连接数。默认 20 */\n maxConnections: z.number().default(20),\n /** 是否启用空闲清理。默认 false */\n enableCleanup: z.boolean().default(false),\n /** 连接空闲超时(ms)。默认 30min */\n idleTimeoutMs: z.number().default(1_800_000),\n /** 清理扫描间隔(ms)。默认 60s */\n cleanupIntervalMs: z.number().default(60_000),\n /** 淘汰时保留服务端 session(下次自动恢复上下文)。默认 true */\n preserveOnEvict: z.boolean().default(true),\n }).default({}),\n /** 额外的 MCP Server,和内置的一起传给 ACP session */\n mcpServers: z.array(z.object({\n type: z.enum([\"http\", \"sse\"]).default(\"http\"),\n name: z.string(),\n url: z.string(),\n headers: z.record(z.string()).default({}),\n })).default([]),\n});\n\nconst openaiSchema = z.object({\n apiKey: z.string().min(1, \"backend.openai.apiKey 必填\"),\n baseUrl: z.string().default(\"https://api.openai.com/v1\"),\n model: z.string().default(\"gpt-4o\"),\n systemPrompt: z.string().default(\"你是一个 QQ 机器人助手。\"),\n maxTokens: z.number().default(2048),\n temperature: z.number().default(0.7),\n});\n\nconst backendSchema = z.object({\n type: z.enum([\"echo\", \"openai\", \"cloudagent\"]).default(\"echo\"),\n cloudagent: cloudagentSchema.optional(),\n openai: openaiSchema.optional(),\n});\n\nconst middlewareSchema = z.object({\n messageFilter: z.object({\n skipSelfEcho: z.boolean().default(true),\n dedup: z.object({ windowMs: z.number().default(5000) }).default({}),\n }).default({}),\n contentSanitizer: z.object({\n stripBotMention: z.boolean().default(true),\n collapseWhitespace: z.boolean().default(true),\n }).default({}),\n mentionGate: z.object({\n requireMentionInGroup: z.boolean().default(true),\n alwaysAnswerC2C: z.boolean().default(true),\n }).default({}),\n rateLimiter: z.object({\n enabled: z.boolean().default(false),\n perSender: z.object({ max: z.number().default(5), windowMs: z.number().default(10000) }).default({}),\n global: z.object({ max: z.number().default(50), windowMs: z.number().default(60000) }).default({}),\n }).default({}),\n typingIndicator: z.object({\n enabled: z.boolean().default(true),\n /** typing 指示器持续时间(秒)。默认 15 */\n durationSec: z.number().default(15),\n /** keepAlive 重发间隔(ms)。默认根据 durationSec 自动计算 */\n keepAliveIntervalMs: z.number().optional(),\n }).default({}).transform((raw) => ({\n ...raw,\n // 自动计算:比 durationSec 提前 5s 重发,确保 typing 状态不中断\n keepAliveIntervalMs: raw.keepAliveIntervalMs ?? Math.max((raw.durationSec - 5) * 1000, 5000),\n })),\n slashCommands: z.object({\n enabled: z.boolean().default(true),\n prefixes: z.array(z.string()).default([\"/\", \"!\"]),\n /** 指令白名单(用户 OpenID 列表)。为空则所有人可用。 */\n allowFrom: z.array(z.string().nullable()).default([]).transform(\n (arr) => arr.filter((v): v is string => v != null && v !== \"\"),\n ),\n }).default({}),\n concurrency: z.object({\n /** Strategy: queue | drop | abort | merge. Default: merge. */\n strategy: z.enum([\"queue\", \"drop\", \"abort\", \"merge\"]).default(\"merge\"),\n /** Max queued messages per target. Default: 50. */\n maxQueue: z.number().default(50),\n }).default({}),\n}).default({});\n\nconst displaySchema = z.object({\n /** Preset: full | compact | minimal | text-only */\n preset: z.enum([\"full\", \"compact\", \"minimal\", \"text-only\"]).default(\"minimal\"),\n /** Show tool calls */\n tool: z.boolean().optional(),\n /** Show agent thought chunks */\n thought: z.boolean().optional(),\n /** Show execution plan */\n plan: z.boolean().optional(),\n /** Show emoji before tool name */\n toolEmoji: z.boolean().optional(),\n /** Show tool kind label (Search/Fetch/...) */\n toolKind: z.boolean().optional(),\n /** Show tool title (URL, query, command, ...) */\n toolTitle: z.boolean().optional(),\n /** Max display length for tool detail when truncation is enabled. Default: 120 */\n toolDetailMaxLength: z.number().optional(),\n /** Tool kinds whose detail should be truncated. Default: [] (no truncation) */\n toolDetailTruncate: z.array(z.string()).optional(),\n}).default({}).transform((raw) => {\n // Expand preset defaults, then apply explicit overrides\n const base = DISPLAY_PRESET_DEFAULTS[raw.preset] ?? DISPLAY_PRESET_DEFAULTS[\"compact\"];\n return {\n preset: raw.preset,\n tool: raw.tool ?? base.tool,\n thought: raw.thought ?? base.thought,\n plan: raw.plan ?? base.plan,\n toolEmoji: raw.toolEmoji ?? base.toolEmoji,\n toolKind: raw.toolKind ?? base.toolKind,\n toolTitle: raw.toolTitle ?? base.toolTitle,\n toolDetailMaxLength: raw.toolDetailMaxLength,\n toolDetailTruncate: raw.toolDetailTruncate,\n };\n});\n\n/** Preset 默认值表,供 slash 指令切换时重新展开 */\nexport const DISPLAY_PRESET_DEFAULTS: Record<string, { tool: boolean; thought: boolean; plan: boolean; toolEmoji: boolean; toolKind: boolean; toolTitle: boolean }> = {\n \"full\": { tool: true, thought: true, plan: true, toolEmoji: true, toolKind: true, toolTitle: true },\n \"compact\": { tool: true, thought: false, plan: true, toolEmoji: true, toolKind: true, toolTitle: true },\n \"minimal\": { tool: true, thought: false, plan: false, toolEmoji: true, toolKind: true, toolTitle: false },\n \"text-only\": { tool: false, thought: false, plan: false, toolEmoji: false, toolKind: false, toolTitle: false },\n};\n\n/** 根据 preset 名称展开完整的 display 配置 */\nexport function expandDisplayPreset(preset: string): BotConfig[\"message\"][\"display\"] {\n const base = DISPLAY_PRESET_DEFAULTS[preset] ?? DISPLAY_PRESET_DEFAULTS[\"compact\"];\n return { preset: preset as any, ...base, toolDetailMaxLength: undefined, toolDetailTruncate: undefined };\n}\n\nconst streamingSchema = z.object({\n c2c: z.boolean().default(true),\n throttleMs: z.number().default(500),\n}).default({});\n\nconst messageSchema = z.object({\n /** 展示样式配置 */\n display: displaySchema,\n /** 异常兜底文案配置 */\n errorMessages: z.object({\n /**\n * 错误匹配规则,按顺序匹配。\n * 每条 rule: match 为关键词数组(任一命中即匹配,大小写不敏感),reply 为回复文案。\n * 可选 hint: 追加在 reply 后的排查指引(覆盖全局 troubleshootHint)。\n */\n rules: z.array(z.object({\n match: z.array(z.string()),\n reply: z.string(),\n hint: z.string().optional(),\n })).default([]),\n /** Agent 未生成回复 */\n emptyReply: z.string().default(\"⚠️ Agent 未生成回复内容,请换个方式描述或重试。\"),\n /** 所有规则都未命中时的兜底 */\n unknown: z.string().default(\"⚠️ 处理失败,请稍后重试。\"),\n /** 全局排查指引,追加在所有错误消息后面(rule 级别 hint 优先) */\n troubleshootHint: z.string().optional(),\n /** 调试模式:错误消息中追加原始 errMsg。默认 false */\n debug: z.boolean().default(false),\n }).default({}),\n}).default({});\n\nconst sessionSchema = z.object({\n isolation: z.enum([\"per-qualifier\", \"global\"]).default(\"per-qualifier\"),\n persistence: z.object({\n type: z.enum([\"file\", \"memory\"]).default(\"file\"),\n dir: z.string().default(\"./.qqbot-data\"),\n }).default({}),\n}).default({});\n\nconst logSchema = z.object({\n level: z.enum([\"debug\", \"info\", \"warn\", \"error\"]).default(\"info\"),\n /** 控制台输出格式:pretty(人类可读)| json(结构化)。默认 pretty */\n console: z.enum([\"json\", \"pretty\"]).default(\"pretty\"),\n /** 文件日志(滚动) */\n file: z.object({\n enabled: z.boolean().default(false),\n dir: z.string().default(\"./logs\"),\n /** 单文件最大大小,支持 \"10m\" \"1g\" 等 */\n maxSize: z.string().default(\"10m\"),\n /** 保留文件数 */\n maxFiles: z.number().default(7),\n /** 按时间滚动:daily | hourly | weekly */\n frequency: z.enum([\"daily\", \"hourly\", \"weekly\"]).optional(),\n /** 文件名日期格式(需配合 frequency),如 \"yyyy-MM-dd\" */\n dateFormat: z.string().optional(),\n /** 创建 current.log 符号链接指向当前活跃文件 */\n symlink: z.boolean().default(false),\n }).default({}),\n}).default({});\n\nconst mcpSchema = z.object({\n enabled: z.boolean().default(false),\n /** MCP Server 监听地址,默认 127.0.0.1;Docker 容器内需设为 0.0.0.0 */\n host: z.string().default(\"127.0.0.1\"),\n /** MCP Server 监听端口,0 为随机分配 */\n port: z.number().int().min(0).default(0),\n /** 文件路径前缀,拼接在工具接收到的 file_path 之前,用于容器卷映射 */\n pathPrefix: z.string().default(\"\"),\n}).default({ enabled: false, host: \"127.0.0.1\", port: 0, pathPrefix: \"\" });\n\nconst openApiParamSchema = z.object({\n name: z.string(),\n type: z.enum([\"string\", \"number\", \"boolean\", \"string[]\", \"number[]\"]).default(\"string\"),\n desc: z.string(),\n required: z.boolean().default(false),\n default: z.unknown().optional(),\n});\n\nconst openApiItemSchema = z.object({\n name: z.string(),\n desc: z.string(),\n method: z.enum([\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"]).default(\"POST\"),\n path: z.string(),\n fixed_body: z.record(z.unknown()).optional(),\n params: z.array(openApiParamSchema).default([]),\n param_mapping: z.record(z.string()).optional(),\n});\n\nconst openApiSchema = z.object({\n /** 全局超时(ms),默认 10000 */\n timeoutMs: z.number().default(10_000),\n /** 接口声明列表 */\n apis: z.array(openApiItemSchema).default([]),\n}).optional();\n\nconst telemetrySchema = z.object({\n enabled: z.boolean().default(false),\n /** 开启 OTEL 内部诊断日志和控制台指标输出 */\n debug: z.boolean().default(false),\n serviceName: z.string().default(\"qqbot-cli\"),\n endpoint: z.string().default(\"http://localhost:4318\"),\n protocol: z.enum([\"http\", \"grpc\"]).default(\"http\"),\n sampleRate: z.number().min(0).max(1).default(1.0),\n exportIntervalMs: z.number().default(30000),\n attributes: z.record(z.string()).default({}),\n /** 平台扩展配置 */\n galileo: z.object({\n platform: z.string(),\n app: z.string(),\n server: z.string(),\n namespace: z.string().default(\"Production\"),\n envName: z.string().default(\"formal\"),\n }).optional(),\n}).default({});\n\nexport const botConfigSchema = z.object({\n qq: qqSchema,\n backend: backendSchema,\n middleware: middlewareSchema,\n streaming: streamingSchema,\n message: messageSchema,\n session: sessionSchema,\n log: logSchema,\n mcp: mcpSchema,\n openapi: openApiSchema,\n telemetry: telemetrySchema,\n});\n\nexport type BotConfig = z.infer<typeof botConfigSchema>;\n","/**\n * ConfigWatcher — 监听配置文件变化,自动重新加载。\n *\n * 特性:\n * - fs.watch 监听文件变化,500ms debounce\n * - Zod 校验通过后才触发 onChange\n * - 校验失败仅日志报错,保持旧配置\n * - 支持 stop() 停止监听\n * - writeBack() 安全地写回配置文件(自动暂停/恢复监听,避免触发循环重载)\n */\n\nimport * as fs from \"node:fs\";\nimport { parseDocument } from \"yaml\";\nimport { loadConfig } from \"./loader.js\";\nimport type { BotConfig } from \"./schema.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\nexport interface ConfigWatcherOptions {\n /** 配置文件路径 */\n configPath: string;\n /** 当前配置(初始值) */\n currentConfig: BotConfig;\n /** 配置变化回调 */\n onChange: (newConfig: BotConfig, oldConfig: BotConfig) => void;\n /** Logger */\n logger: Logger;\n /** debounce 时间(ms),默认 500 */\n debounceMs?: number;\n}\n\nexport class ConfigWatcher {\n private watcher: fs.FSWatcher | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private currentConfig: BotConfig;\n private readonly opts: ConfigWatcherOptions;\n private paused = false;\n\n constructor(opts: ConfigWatcherOptions) {\n this.opts = opts;\n this.currentConfig = opts.currentConfig;\n }\n\n start(): void {\n const { configPath, logger } = this.opts;\n const debounceMs = this.opts.debounceMs ?? 500;\n\n try {\n this.watcher = fs.watch(configPath, () => {\n if (this.paused) return;\n // Debounce: 编辑器保存可能触发多次 write\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => this.reload(), debounceMs);\n });\n logger.info(`[config] watching ${configPath} for changes`);\n } catch (err) {\n logger.warn?.(\n `[config] failed to watch ${configPath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n stop(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n }\n\n /**\n * 将指定的键值对写回 YAML 配置文件。\n *\n * 使用 yaml `parseDocument` 保留原始注释和格式,\n * 仅修改目标字段,然后重新序列化写入。\n *\n * 写入期间自动暂停文件监听,避免触发循环重载。\n *\n * @param patches - 要写入的路径-值映射,路径用点号分隔(如 \"message.display.preset\")\n * @param currentConfig - 当前内存中的最新配置,同步到 watcher 防止 reload 回退\n */\n writeBack(patches: Record<string, unknown>, currentConfig?: BotConfig): void {\n const { configPath, logger } = this.opts;\n\n try {\n const raw = fs.readFileSync(configPath, \"utf-8\");\n const doc = parseDocument(raw);\n\n for (const [dotPath, value] of Object.entries(patches)) {\n const keys = dotPath.split(\".\");\n doc.setIn(keys, value);\n }\n\n this.paused = true;\n fs.writeFileSync(configPath, doc.toString(), \"utf-8\");\n logger.info(`[config] wrote back: ${Object.keys(patches).join(\", \")}`);\n\n // 同步 watcher 的内部配置,防止后续 reload 用旧值覆盖\n if (currentConfig) {\n this.currentConfig = currentConfig;\n }\n\n // 等文件系统事件稳定后再恢复监听\n setTimeout(() => { this.paused = false; }, 1500);\n } catch (err) {\n this.paused = false;\n logger.error(\n `[config] writeBack failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async reload(): Promise<void> {\n const { configPath, logger, onChange } = this.opts;\n\n try {\n const newConfig = await loadConfig(configPath);\n const oldConfig = this.currentConfig;\n this.currentConfig = newConfig;\n logger.info(\"[config] reloaded successfully\");\n onChange(newConfig, oldConfig);\n } catch (err) {\n logger.error(\n `[config] reload failed, keeping old config: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","/**\n * BotRunner — 核心编排器\n *\n * 组合 QQBot SDK + Middleware + ReplyBackend,实现配置驱动的 AI QQ 机器人。\n * 职责:生命周期管理、中间件装配、配置热更新、消息路由。\n */\n\nimport { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\nconst { version: CLI_VERSION } = require(\"../package.json\") as { version: string };\n\nimport {\n QQBot,\n messageFilter,\n contentSanitizer,\n mentionGate,\n rateLimiter,\n concurrencyGuard,\n quoteRef,\n typingIndicator,\n envelopeFormatter,\n errorHandler,\n type QQBotInboundMessage,\n type MiddlewareContext,\n} from \"@tencent/qqbot-nodejs\";\n\nimport type { BotConfig } from \"./config/schema.js\";\nimport type { ReplyBackend } from \"./backend/types.js\";\nimport { EchoBackend } from \"./backend/echo.js\";\nimport { OpenAIBackend } from \"./backend/openai.js\";\nimport { CloudAgentBackend } from \"./backend/cloudagent.js\";\nimport type { McpServer } from \"@agentclientprotocol/sdk\";\nimport { MCPServerHost, MsgIdCache } from \"./mcp/server.js\";\nimport { createSlashMiddleware } from \"./slash/index.js\";\nimport type { Logger } from \"./utils/logger.js\";\nimport { formatQQBotEnvelope } from \"./envelope.js\";\nimport { streamReply, batchReply, type ReplyContext } from \"./reply.js\";\nimport { telemetryMiddleware } from \"./telemetry/middleware.js\";\nimport { mergeTotal, mergeEventsTotal, dropTotal, slashCommandTotal, envelopeLength, rateLimitRejectedTotal } from \"./telemetry/metrics.js\";\nimport { withClientMetrics } from \"./telemetry/client-interceptor.js\";\n\nexport class BotRunner {\n private bot: QQBot;\n private backend: ReplyBackend;\n private config: BotConfig;\n private logger: Logger;\n private mcpHost?: MCPServerHost;\n private msgIdCache = new MsgIdCache();\n /** 写回配置文件的回调,由外部(cli.ts)注入 */\n private configWriter?: (patches: Record<string, unknown>, currentConfig: BotConfig) => void;\n\n constructor(config: BotConfig, logger: Logger) {\n this.config = config;\n this.logger = logger;\n\n // 1. 创建 QQBot 实例\n this.bot = new QQBot({\n appId: config.qq.appId,\n appSecret: config.qq.appSecret,\n markdownSupport: config.qq.markdown,\n baseUrl: config.qq.baseUrl,\n tokenBaseUrl: config.qq.tokenBaseUrl,\n tokenPrefetch: config.qq.tokenPrefetch,\n userAgent: `${config.qq.userAgent ?? `qqbot-cli/${CLI_VERSION}`} (Node/${process.versions.node})`,\n transport: config.qq.transport,\n ...(config.qq.transport === \"webhook\" ? {\n webhook: {\n port: config.qq.webhook.port,\n path: config.qq.webhook.path,\n },\n } : {}),\n logger,\n });\n\n // 2. 创建 Backend(MCP 配置在 start() 中注入)\n this.backend = this.createBackend(config);\n\n // 3. 装载 Middleware chain\n this.setupMiddleware(config);\n\n // 4. 事件处理\n this.bot.on(\"ready\", () => {\n logger.info(\"🟢 Bot online\");\n });\n this.bot.on(\"resumed\", () => {\n logger.info(\"🟢 Bot resumed\");\n });\n this.bot.on(\"error\", (err) => {\n logger.error(`🔴 ${err.message}`);\n });\n this.bot.on(\"message\", (ctx, msg) => this.handleMessage(ctx, msg));\n }\n\n // ============ 生命周期 ============\n\n async start(signal?: AbortSignal): Promise<void> {\n // 1. 启动内置 MCP Server(如果开启)\n const mcpServers: McpServer[] = [];\n\n if (this.config.mcp.enabled) {\n this.mcpHost = new MCPServerHost();\n await this.mcpHost.start(\n {\n logger: this.logger,\n bot: this.bot,\n pathPrefix: this.config.mcp.pathPrefix,\n msgIdCache: this.msgIdCache,\n },\n this.config.mcp.port,\n this.config.mcp.host,\n this.config.openapi,\n );\n mcpServers.push(this.mcpHost.getAcpEntry());\n this.logger.info(`[runner] MCP Server 已启动 (${this.config.mcp.host}:${this.mcpHost.port})`);\n }\n\n // 2. 合并用户配置的额外 MCP Server(cloudagent.mcpServers)\n const cloudagentCfg = this.config.backend.cloudagent;\n if (cloudagentCfg?.mcpServers) {\n for (const srv of cloudagentCfg.mcpServers) {\n const headers = Object.entries(srv.headers).map(([name, value]) => ({ name, value }));\n mcpServers.push({ type: srv.type, name: srv.name, url: srv.url, headers });\n }\n }\n\n // 3. 注入到 CloudAgent Backend\n if (mcpServers.length > 0 && this.backend instanceof CloudAgentBackend) {\n (this.backend as any).opts.extraMcpServers = mcpServers;\n this.logger.info(`[runner] MCP Servers: ${mcpServers.map((s) => s.name).join(\", \")}`);\n }\n\n // 4. 初始化后端(ACP 建联在这里发生,此时 MCP 已就绪)\n this.logger.info(`[runner] 初始化后端: ${this.backend.name}`);\n await this.backend.init();\n\n // 5. 启动 QQ\n const transport = this.config.qq.transport;\n if (transport === \"webhook\") {\n this.logger.info(`[runner] 后端就绪,启动 Webhook 服务 (port=${this.config.qq.webhook.port}, path=${this.config.qq.webhook.path})...`);\n } else {\n this.logger.info(`[runner] 后端就绪,启动 QQ WebSocket...`);\n }\n await this.bot.start(signal);\n }\n\n async stop(): Promise<void> {\n this.bot.stop();\n await this.backend.shutdown();\n await this.mcpHost?.stop().catch(() => {});\n this.logger.info(`[runner] 已停止`);\n }\n\n // ============ 配置管理 ============\n\n /** 注入配置文件写回能力(由 cli.ts 在创建 ConfigWatcher 后调用) */\n setConfigWriter(writer: (patches: Record<string, unknown>, currentConfig: BotConfig) => void): void {\n this.configWriter = writer;\n }\n\n /**\n * 热更新配置。校验通过后立即生效的字段:\n * - middleware(mentionGate/rateLimiter/concurrency/typingIndicator 等)\n * - message.display(展示样式)\n * - streaming.throttleMs\n * - log.level\n * - backend.cloudagent.acp.eventTimeoutMs\n * - backend.cloudagent.manifest.systemPrompt\n *\n * 需要重启才能生效的字段(仅日志提示):\n * - qq.appId/appSecret/transport\n * - backend.type\n * - backend.cloudagent.sandbox\n */\n applyConfigUpdate(newConfig: BotConfig): void {\n const old = this.config;\n\n // 检测需重启的字段\n const restartNeeded: string[] = [];\n if (old.qq.appId !== newConfig.qq.appId) restartNeeded.push(\"qq.appId\");\n if (old.qq.appSecret !== newConfig.qq.appSecret) restartNeeded.push(\"qq.appSecret\");\n if (old.qq.transport !== newConfig.qq.transport) restartNeeded.push(\"qq.transport\");\n if (old.backend.type !== newConfig.backend.type) restartNeeded.push(\"backend.type\");\n if (JSON.stringify(old.backend.cloudagent?.sandbox) !== JSON.stringify(newConfig.backend.cloudagent?.sandbox)) {\n restartNeeded.push(\"backend.cloudagent.sandbox\");\n }\n\n if (restartNeeded.length > 0) {\n this.logger.warn(\n `[config] 以下配置变更需要重启才能生效: ${restartNeeded.join(\", \")}`,\n );\n }\n\n // 原子替换配置\n this.config = newConfig;\n\n // 日志级别立即生效\n if (old.log.level !== newConfig.log.level) {\n this.logger.info(`[config] log.level: ${old.log.level} → ${newConfig.log.level}`);\n }\n\n this.logger.info(\"[config] hot reload applied\");\n }\n\n /**\n * 通过斜杠指令部分更新配置。\n * 同时写回配置文件(如果 configWriter 已注入)。\n */\n private applyConfigPatch(patch: import(\"./slash/index.js\").PatchableConfig extends infer T\n ? Partial<T> : never): void {\n const c = this.config;\n const filePatches: Record<string, unknown> = {};\n\n if (patch.display) {\n (c.message as any).display = patch.display;\n filePatches[\"message.display.preset\"] = patch.display.preset;\n this.logger.info(`[config] display → ${patch.display.preset} (tool=${patch.display.tool}, thought=${patch.display.thought}, plan=${patch.display.plan})`);\n this.logger.debug(`[config] display verify: preset=${this.config.message.display.preset} thought=${this.config.message.display.thought}`);\n }\n if (patch.logLevel) {\n (c.log as any).level = patch.logLevel;\n filePatches[\"log.level\"] = patch.logLevel;\n this.logger.info(`[config] log.level → ${patch.logLevel}`);\n }\n if (patch.streamingC2c !== undefined) {\n (c.streaming as any).c2c = patch.streamingC2c;\n filePatches[\"streaming.c2c\"] = patch.streamingC2c;\n this.logger.info(`[config] streaming.c2c → ${patch.streamingC2c}`);\n }\n if (patch.streamingThrottleMs !== undefined) {\n (c.streaming as any).throttleMs = patch.streamingThrottleMs;\n filePatches[\"streaming.throttleMs\"] = patch.streamingThrottleMs;\n }\n\n // 写回配置文件\n if (this.configWriter && Object.keys(filePatches).length > 0) {\n this.configWriter(filePatches, this.config);\n }\n }\n\n // ============ Backend 工厂 ============\n\n private createBackend(config: BotConfig): ReplyBackend {\n switch (config.backend.type) {\n case \"echo\":\n return new EchoBackend();\n\n case \"openai\": {\n const opts = config.backend.openai;\n if (!opts) throw new Error(\"backend.openai 配置缺失\");\n return new OpenAIBackend({\n apiKey: opts.apiKey,\n baseUrl: opts.baseUrl,\n model: opts.model,\n systemPrompt: opts.systemPrompt,\n maxTokens: opts.maxTokens,\n temperature: opts.temperature,\n logger: this.logger,\n });\n }\n\n case \"cloudagent\": {\n const opts = config.backend.cloudagent;\n if (!opts) throw new Error(\"backend.cloudagent 配置缺失\");\n return new CloudAgentBackend({\n config: opts,\n appId: config.qq.appId,\n logger: this.logger,\n });\n }\n\n default:\n throw new Error(`未知后端类型: ${config.backend.type}`);\n }\n }\n\n // ============ Middleware 装配 ============\n\n private setupMiddleware(config: BotConfig): void {\n const mw = config.middleware;\n\n // 防御层\n this.bot.use(errorHandler());\n\n // 可观测性(telemetry 未启用时为 no-op,零开销)\n this.bot.use(telemetryMiddleware({ appId: this.config.qq.appId }));\n\n this.bot.use(messageFilter({\n skipSelfEcho: mw.messageFilter.skipSelfEcho,\n dedup: mw.messageFilter.dedup,\n }));\n\n // 网关层\n this.bot.use(contentSanitizer({\n stripBotMention: mw.contentSanitizer.stripBotMention,\n collapseWhitespace: mw.contentSanitizer.collapseWhitespace,\n }));\n this.bot.use(mentionGate({\n requireMentionInGroup: mw.mentionGate.requireMentionInGroup,\n alwaysAnswerC2C: mw.mentionGate.alwaysAnswerC2C,\n }));\n\n // 斜杠指令(在 mentionGate 之后、rateLimiter 之前;匹配后会短路链路,不触发后端 LLM)\n if (mw.slashCommands.enabled) {\n this.bot.use(createSlashMiddleware({\n prefixes: mw.slashCommands.prefixes,\n allowFrom: mw.slashCommands.allowFrom,\n ctx: {\n backend: this.backend,\n logger: this.logger,\n getConfig: () => this.config,\n updateConfig: (patch) => this.applyConfigPatch(patch),\n },\n }));\n }\n\n // 限流(可选)\n if (mw.rateLimiter.enabled) {\n this.bot.use(rateLimiter({\n perSender: mw.rateLimiter.perSender,\n global: mw.rateLimiter.global,\n onLimit: (ctx, tier) => {\n const scopeType = ctx.message.replyTarget.scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n rateLimitRejectedTotal.add(1, { scope: scopeType, tier });\n },\n }));\n }\n\n // 引用消息解析(记录 ref-index + 解析 quoted 消息)\n this.bot.use(quoteRef());\n\n // 消息信封格式化:自定义格式,组装发给 ACP 的上下文\n this.bot.use(envelopeFormatter({\n format: (ctx) => formatQQBotEnvelope(ctx),\n }));\n\n // 并发控制:同一用户/群串行处理(放在 envelopeFormatter 之后,\n // 确保 merge 策略 buffer 中的 ctx 已有完整 envelope)\n this.bot.use(concurrencyGuard({\n strategy: mw.concurrency.strategy,\n maxQueue: mw.concurrency.maxQueue,\n onMerge: (buffered) => {\n // 上报本次合并的消息条数\n const scopeType = buffered[0]!.message.replyTarget.scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n mergeTotal.add(buffered.length, { scope: scopeType });\n\n // 使用最后一条 ctx(最新 msgId,确保被动回复有效)\n const last = buffered[buffered.length - 1]!;\n if (buffered.length === 1) return last;\n\n // 合并 envelope(带时间线分隔)\n const envelopes = buffered\n .map((ctx) => (ctx.state.envelope as string) ?? ctx.message.content ?? \"\")\n .filter(Boolean);\n if (envelopes.length > 0) {\n last.state.envelope = envelopes.join(\"\\n\\n\");\n }\n\n // 合并附件\n const allAttachments = buffered.flatMap((ctx) => ctx.message.attachments ?? []);\n if (allAttachments.length > 0) {\n (last.message as any).attachments = allAttachments;\n }\n\n return last;\n },\n onDispatch: (merged) => {\n const scopeType = merged.message.replyTarget.scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n mergeEventsTotal.add(1, { scope: scopeType });\n return this.handleMessage(merged, merged.message);\n },\n onDrop: (ctx) => {\n const scopeType = ctx.message.replyTarget.scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n dropTotal.add(1, { scope: scopeType });\n },\n }));\n\n // UX 层\n if (mw.typingIndicator.enabled) {\n this.bot.use(typingIndicator({\n durationSec: mw.typingIndicator.durationSec,\n keepAliveIntervalMs: mw.typingIndicator.keepAliveIntervalMs,\n }));\n }\n }\n\n // ============ 消息路由 ============\n\n private async handleMessage(ctx: MiddlewareContext, msg: QQBotInboundMessage): Promise<void> {\n // 标记消息经过了完整 handler(供 telemetry 区分 buffered 消息)\n ctx.state.handled = true;\n\n // envelope 由 envelopeFormatter 中间件组装(含 ASR、引用、附件标签等)\n const envelope = ctx.state.envelope as string | undefined;\n const text = (msg.content ?? \"\").trim();\n if (!envelope && !text && (!msg.attachments || msg.attachments.length === 0)) {\n return;\n }\n\n const qualifier = `${msg.replyTarget.scope}-${msg.replyTarget.targetId}`;\n const extSessionId = this.resolveExtSessionId(msg);\n const scopeType = msg.replyTarget.scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n\n // 上报 envelope 长度\n if (envelope) {\n envelopeLength.record(envelope.length, { scope: scopeType });\n }\n\n // 缓存 msgId,供 MCP send_file 被动回复使用\n const targetKey = `${msg.replyTarget.scope}:${msg.replyTarget.targetId}`;\n if (msg.replyTarget.msgId) {\n this.msgIdCache.push(targetKey, msg.replyTarget.msgId);\n }\n\n const rctx: ReplyContext = {\n bot: this.bot,\n backend: this.backend,\n config: this.config,\n logger: this.logger,\n };\n\n try {\n const sessionId = await this.backend.getOrCreateSession(qualifier, extSessionId);\n\n // 构建附件\n let attachments = msg.attachments?.map((att) => ({\n url: att.url.startsWith(\"//\") ? `https:${att.url}` : att.url,\n mimeType: att.content_type,\n name: att.filename ?? \"file\",\n size: att.size,\n }));\n\n // envelope 优先(含格式化的 sender/scope、ASR、引用等),fallback 到原始 text\n let effectiveText = envelope || text;\n\n // 未被本地指令中间件消费的 /command → 透传为 command:// resource_link 给 ACP\n const cmdMatch = /^\\/(\\S+)(?:\\s+(.*))?$/.exec(text);\n if (cmdMatch && !attachments?.length) {\n const [, cmd, args] = cmdMatch;\n effectiveText = args ?? \"\";\n attachments = [{ url: `command://${cmd}`, mimeType: \"text/x-command\", name: cmd!, size: undefined }];\n }\n\n const replyMethod = (this.config.streaming.c2c && msg.replyTarget.scope === \"c2c\" && msg.replyTarget.msgId)\n ? \"streamReply\" : \"batchReply\";\n\n await withClientMetrics({\n callerMethod: \"reply\",\n calleeService: \"qq-platform\",\n calleeMethod: replyMethod,\n extras: { user_ext1: scopeType },\n }, async () => {\n if (replyMethod === \"streamReply\") {\n await streamReply(rctx, ctx, msg, sessionId, qualifier, effectiveText, attachments);\n } else {\n await batchReply(rctx, ctx, msg, sessionId, qualifier, effectiveText, attachments);\n }\n });\n } catch (err) {\n // abort 导致的错误不发给用户\n if (ctx.aborted) {\n this.logger.debug(`[handler] ${qualifier} aborted, skip error reply`);\n return;\n }\n const errMsg = err instanceof Error ? err.message : String(err);\n this.logger.error(`[handler] ${qualifier} 处理失败: ${errMsg}`);\n try {\n let userMessage = this.formatErrorForUser(errMsg);\n if (this.config.message.errorMessages.debug) {\n userMessage += `\\n\\n[debug] ${errMsg}`;\n }\n await this.bot.sendText(msg.replyTarget, userMessage);\n } catch {\n // ignore\n }\n }\n }\n\n /**\n * 从 messageScene.ext 中提取外部 sessionid。\n * 返回 undefined 表示事件中没有指定 sessionid。\n */\n private resolveExtSessionId(msg: QQBotInboundMessage): string | undefined {\n const ext = (msg as any).messageScene?.ext as string[] | undefined;\n if (ext) {\n for (const entry of ext) {\n if (entry.startsWith(\"sessionid=\")) {\n const sessionId = entry.slice(\"sessionid=\".length);\n if (sessionId) {\n this.logger.debug?.(`[handler] using ext sessionid: ${sessionId}`);\n return sessionId;\n }\n }\n }\n }\n return undefined;\n }\n\n private formatErrorForUser(errMsg: string): string {\n const { rules, unknown, troubleshootHint } = this.config.message.errorMessages;\n const lower = errMsg.toLowerCase();\n for (const rule of rules) {\n if (rule.match.some((keyword) => lower.includes(keyword.toLowerCase()))) {\n const hint = rule.hint ?? troubleshootHint;\n return hint ? `${rule.reply}\\n${hint}` : rule.reply;\n }\n }\n return troubleshootHint ? `${unknown}\\n${troubleshootHint}` : unknown;\n }\n}","/**\n * Echo Backend — 开发测试用,原样回显用户输入\n */\n\nimport type { ReplyBackend, ChatParams, ChatChunk } from \"./types.js\";\n\nexport class EchoBackend implements ReplyBackend {\n readonly name = \"echo\";\n\n async init(): Promise<void> {\n // no-op\n }\n\n async getOrCreateSession(qualifier: string): Promise<string> {\n return `echo-${qualifier}`;\n }\n\n async *chat(params: ChatParams): AsyncIterableIterator<ChatChunk> {\n const reply = params.text\n ? `Echo: ${params.text}`\n : \"(空消息)\";\n\n // 模拟逐字输出\n let buffer = \"\";\n for (const char of reply) {\n buffer += char;\n yield { type: \"text\", content: char };\n await sleep(50);\n }\n yield { type: \"done\", content: \"\", stopReason: \"end\" };\n }\n\n async shutdown(): Promise<void> {\n // no-op\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Telemetry Metrics — 业务指标定义\n *\n * 指标分为:\n * - 被调指标(Server):QQ 消息 → qqbot-cli 处理\n * - 主调指标(Client):qqbot-cli → ACP 调用\n * - 业务指标:merge/drop 等内部计数\n *\n * 每次调用时通过全局 API 获取 meter + createInstrument(OTEL 内部 dedup,零额外开销)。\n * telemetry 未启用时,OTEL API 返回 no-op(零开销)。\n */\n\nimport { metrics, type Attributes, ValueType } from \"@opentelemetry/api\";\nimport { GALILEO_METRICS, METRIC_ATTRS } from \"./constants.js\";\n\n// ============ 业务指标默认维度 ============\n\nlet bizDefaultAttrs: Attributes = {};\n\n/** 设置业务指标默认维度(initTelemetry 中调用) */\nexport function setBizDefaultAttrs(attrs: Attributes): void {\n bizDefaultAttrs = attrs;\n}\n\n/** 为业务指标补全默认维度 */\nfunction fillBizAttrs(attrs?: Attributes): Attributes {\n return { ...bizDefaultAttrs, ...attrs };\n}\n\n// ============ Meter Access ============\n\nfunction getServerMeter() { return metrics.getMeter(\"server_metrics\"); }\nfunction getClientMeter() { return metrics.getMeter(\"client_metrics\"); }\nfunction getBizMeter() { return metrics.getMeter(\"qqbot_biz\"); }\n\n// ============ 主调/被调通用 Attributes 填充 ============\n\n/**\n * 补全主调指标所需的全部 Attributes(缺失字段填空字符串)\n */\nexport function fillClientAttrs(attrs: Attributes): Attributes {\n return {\n [METRIC_ATTRS.CALLER_SERVICE]: \"\",\n [METRIC_ATTRS.CALLER_METHOD]: \"\",\n [METRIC_ATTRS.CALLER_CON_SETID]: \"\",\n [METRIC_ATTRS.CALLEE_SERVICE]: \"\",\n [METRIC_ATTRS.CALLEE_METHOD]: \"\",\n [METRIC_ATTRS.CALLEE_CON_SETID]: \"\",\n [METRIC_ATTRS.CALLEE_IP]: \"\",\n [METRIC_ATTRS.CALLEE_CONTAINER]: \"\",\n [METRIC_ATTRS.CODE]: 0,\n [METRIC_ATTRS.CODE_TYPE]: \"\",\n [METRIC_ATTRS.CALLER_GROUP]: \"\",\n [METRIC_ATTRS.USER_EXT1]: \"\",\n [METRIC_ATTRS.USER_EXT2]: \"\",\n [METRIC_ATTRS.USER_EXT3]: \"\",\n [METRIC_ATTRS.CALLER_SERVER]: \"\",\n [METRIC_ATTRS.CALLEE_SERVER]: \"\",\n ...attrs,\n };\n}\n\n/**\n * 补全被调指标所需的全部 Attributes(缺失字段填空字符串)\n */\nexport function fillServerAttrs(attrs: Attributes): Attributes {\n return {\n [METRIC_ATTRS.CALLER_SERVICE]: \"\",\n [METRIC_ATTRS.CALLER_METHOD]: \"\",\n [METRIC_ATTRS.CALLER_CON_SETID]: \"\",\n caller_ip: \"\",\n caller_container: \"\",\n [METRIC_ATTRS.CALLEE_SERVICE]: \"\",\n [METRIC_ATTRS.CALLEE_METHOD]: \"\",\n [METRIC_ATTRS.CALLEE_CON_SETID]: \"\",\n [METRIC_ATTRS.CODE]: 0,\n [METRIC_ATTRS.CODE_TYPE]: \"\",\n [METRIC_ATTRS.CALLER_GROUP]: \"\",\n [METRIC_ATTRS.USER_EXT1]: \"\",\n [METRIC_ATTRS.USER_EXT2]: \"\",\n [METRIC_ATTRS.USER_EXT3]: \"\",\n [METRIC_ATTRS.CALLER_SERVER]: \"\",\n [METRIC_ATTRS.CALLEE_SERVER]: \"\",\n ...attrs,\n };\n}\n\n// ============ 被调指标(Server: QQ → qqbot-cli) ============\n\nexport const serverHandledSeconds = {\n record(value: number, attrs?: Attributes) {\n getServerMeter().createHistogram(GALILEO_METRICS.SERVER_HANDLED_SECONDS, {\n unit: \"s\", valueType: ValueType.DOUBLE,\n }).record(value, fillServerAttrs(attrs ?? {}));\n },\n};\n\nexport const serverStartedTotal = {\n add(value: number, attrs?: Attributes) {\n getServerMeter().createCounter(GALILEO_METRICS.SERVER_STARTED_TOTAL, {\n valueType: ValueType.INT,\n }).add(value, fillServerAttrs(attrs ?? {}));\n },\n};\n\nexport const serverHandledTotal = {\n add(value: number, attrs?: Attributes) {\n getServerMeter().createCounter(GALILEO_METRICS.SERVER_HANDLED_TOTAL, {\n valueType: ValueType.INT,\n }).add(value, fillServerAttrs(attrs ?? {}));\n },\n};\n\n// ============ 主调指标(Client: qqbot-cli → ACP) ============\n\nexport const clientHandledSeconds = {\n record(value: number, attrs?: Attributes) {\n getClientMeter().createHistogram(GALILEO_METRICS.CLIENT_HANDLED_SECONDS, {\n unit: \"s\", valueType: ValueType.DOUBLE,\n }).record(value, fillClientAttrs(attrs ?? {}));\n },\n};\n\nexport const clientStartedTotal = {\n add(value: number, attrs?: Attributes) {\n getClientMeter().createCounter(GALILEO_METRICS.CLIENT_STARTED_TOTAL, {\n valueType: ValueType.INT,\n }).add(value, fillClientAttrs(attrs ?? {}));\n },\n};\n\nexport const clientHandledTotal = {\n add(value: number, attrs?: Attributes) {\n getClientMeter().createCounter(GALILEO_METRICS.CLIENT_HANDLED_TOTAL, {\n valueType: ValueType.INT,\n }).add(value, fillClientAttrs(attrs ?? {}));\n },\n};\n\n// ============ 业务指标 ============\n\nexport const mergeTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.concurrency.merged\").add(value, fillBizAttrs(attrs));\n },\n};\n\nexport const mergeEventsTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.concurrency.merge_events\").add(value, fillBizAttrs(attrs));\n },\n};\n\nexport const dropTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.concurrency.dropped\").add(value, fillBizAttrs(attrs));\n },\n};\n\nexport const toolCallsTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.acp.tool_calls.total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n// ============ ACP 连接指标 ============\n\n/** ACP 首字节延迟(从 prompt 发出到首个 chunk) */\nexport const acpTtfbSeconds = {\n record(value: number, attrs?: Attributes) {\n getBizMeter().createHistogram(\"qqbot.acp.ttfb_seconds\", {\n unit: \"s\", valueType: ValueType.DOUBLE,\n }).record(value, fillBizAttrs(attrs));\n },\n};\n\n/** ACP 连接建立耗时 */\nexport const acpConnectSeconds = {\n record(value: number, attrs?: Attributes) {\n getBizMeter().createHistogram(\"qqbot.acp.connect_seconds\", {\n unit: \"s\", valueType: ValueType.DOUBLE,\n }).record(value, fillBizAttrs(attrs));\n },\n};\n\n/** ACP 连接重试次数 */\nexport const acpConnectRetries = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.acp.connect_retries\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** chatWithRetry 重试次数 */\nexport const chatRetryTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.acp.chat_retry_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n// ============ 连接池指标 ============\n\n/** 连接池当前大小 */\nexport const poolSize = {\n record(value: number) {\n getBizMeter().createHistogram(\"qqbot.pool.size\", {\n valueType: ValueType.INT,\n }).record(value, fillBizAttrs());\n },\n};\n\n/** 连接池 LRU 淘汰次数 */\nexport const poolEvictTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.pool.evict_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** 连接池断线恢复次数 */\nexport const poolRestoreTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.pool.restore_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** 连接池新建连接耗时 */\nexport const poolCreateSeconds = {\n record(value: number, attrs?: Attributes) {\n getBizMeter().createHistogram(\"qqbot.pool.create_seconds\", {\n unit: \"s\", valueType: ValueType.DOUBLE,\n }).record(value, fillBizAttrs(attrs));\n },\n};\n\n// ============ 沙箱/Session 指标 ============\n\n/** 沙箱启动等待耗时 */\nexport const sandboxStartSeconds = {\n record(value: number, attrs?: Attributes) {\n getBizMeter().createHistogram(\"qqbot.sandbox.start_seconds\", {\n unit: \"s\", valueType: ValueType.DOUBLE,\n }).record(value, fillBizAttrs(attrs));\n },\n};\n\n/** Session 创建+就绪耗时 */\nexport const sessionCreateSeconds = {\n record(value: number, attrs?: Attributes) {\n getBizMeter().createHistogram(\"qqbot.session.create_seconds\", {\n unit: \"s\", valueType: ValueType.DOUBLE,\n }).record(value, fillBizAttrs(attrs));\n },\n};\n\n// ============ 回复指标 ============\n\n/** 空回复兜底次数 */\nexport const replyEmptyTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.reply.empty_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** 流式降级为 batch 次数 */\nexport const replyFallbackTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.reply.fallback_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** 回复 chunk 数量 */\nexport const replyChunksTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.reply.chunks_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** 回复文本长度分布 */\nexport const replyLength = {\n record(value: number, attrs?: Attributes) {\n getBizMeter().createHistogram(\"qqbot.reply.length\", {\n valueType: ValueType.INT,\n }).record(value, fillBizAttrs(attrs));\n },\n};\n\n// ============ 运营指标 ============\n\n/** 斜杠指令调用次数 */\nexport const slashCommandTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.slash.total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** 限流拒绝次数 */\nexport const rateLimitRejectedTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.ratelimit.rejected_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\n/** 发给 LLM 的 envelope 长度 */\nexport const envelopeLength = {\n record(value: number, attrs?: Attributes) {\n getBizMeter().createHistogram(\"qqbot.envelope.length\", {\n valueType: ValueType.INT,\n }).record(value, fillBizAttrs(attrs));\n },\n};\n\n/** SSE 断线次数 */\nexport const transportDisconnectTotal = {\n add(value: number, attrs?: Attributes) {\n getBizMeter().createCounter(\"qqbot.transport.disconnect_total\").add(value, fillBizAttrs(attrs));\n },\n};\n\nexport { METRIC_ATTRS } from \"./constants.js\";\n","/**\n * Telemetry Constants — OpenTelemetry 常量定义\n *\n * 独立模块,避免循环依赖。\n */\n\n// ============ Galileo Resource Attributes ============\n\nexport const GALILEO_RESOURCE = {\n TARGET: \"target\",\n SERVICE_NAME: \"service_name\",\n NAMESPACE: \"namespace\",\n ENV_NAME: \"env_name\",\n INSTANCE: \"instance\",\n CONTAINER_NAME: \"container_name\",\n VERSION: \"version\",\n CON_SETID: \"con_setid\",\n APP_ID: \"app_id\",\n SDK_LANGUAGE: \"telemetry.sdk.language\",\n SDK_NAME: \"telemetry.sdk.name\",\n} as const;\n\n// ============ Galileo Metric Names ============\n\nexport const GALILEO_METRICS = {\n /** 被调处理耗时 */\n SERVER_HANDLED_SECONDS: \"rpc_server_handled_seconds\",\n /** 被调请求计数 */\n SERVER_STARTED_TOTAL: \"rpc_server_started_total\",\n /** 被调完成计数 */\n SERVER_HANDLED_TOTAL: \"rpc_server_handled_total\",\n /** 主调耗时 */\n CLIENT_HANDLED_SECONDS: \"rpc_client_handled_seconds\",\n /** 主调请求计数 */\n CLIENT_STARTED_TOTAL: \"rpc_client_started_total\",\n /** 主调完成计数 */\n CLIENT_HANDLED_TOTAL: \"rpc_client_handled_total\",\n} as const;\n\n// ============ Galileo Metric Attributes ============\n\nexport const METRIC_ATTRS = {\n CALLER_SERVICE: \"caller_service\",\n CALLER_METHOD: \"caller_method\",\n CALLER_CON_SETID: \"caller_con_setid\",\n CALLEE_SERVICE: \"callee_service\",\n CALLEE_METHOD: \"callee_method\",\n CALLEE_CON_SETID: \"callee_con_setid\",\n CALLEE_IP: \"callee_ip\",\n CALLEE_CONTAINER: \"callee_container\",\n CALLER_SERVER: \"caller_server\",\n CALLEE_SERVER: \"callee_server\",\n CODE: \"code\",\n CODE_TYPE: \"code_type\",\n CALLER_GROUP: \"caller_group\",\n USER_EXT1: \"user_ext1\",\n USER_EXT2: \"user_ext2\",\n USER_EXT3: \"user_ext3\",\n} as const;\n","/**\n * OpenAI 兼容 API 后端 — 支持流式 SSE\n */\n\nimport type { ReplyBackend, ChatParams, ChatChunk } from \"./types.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { clientStartedTotal, clientHandledTotal, clientHandledSeconds } from \"../telemetry/metrics.js\";\nimport { METRIC_ATTRS } from \"../telemetry/constants.js\";\n\nexport interface OpenAIBackendOptions {\n apiKey: string;\n baseUrl: string;\n model: string;\n systemPrompt: string;\n maxTokens: number;\n temperature: number;\n logger: Logger;\n}\n\ninterface Message {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport class OpenAIBackend implements ReplyBackend {\n readonly name = \"openai\";\n private opts: OpenAIBackendOptions;\n /** qualifier → 对话历史 */\n private histories = new Map<string, Message[]>();\n\n constructor(opts: OpenAIBackendOptions) {\n this.opts = opts;\n }\n\n async init(): Promise<void> {\n this.opts.logger.info(`[openai] 初始化: model=${this.opts.model} baseUrl=${this.opts.baseUrl}`);\n }\n\n async getOrCreateSession(qualifier: string): Promise<string> {\n if (!this.histories.has(qualifier)) {\n this.histories.set(qualifier, []);\n }\n return qualifier;\n }\n\n async *chat(params: ChatParams): AsyncIterableIterator<ChatChunk> {\n const clientAttrs = {\n [METRIC_ATTRS.CALLER_SERVICE]: \"qqbot-cli\",\n [METRIC_ATTRS.CALLER_METHOD]: \"chat\",\n [METRIC_ATTRS.CALLER_SERVER]: \"qqbot-cli\",\n [METRIC_ATTRS.CALLEE_SERVICE]: \"openai\",\n [METRIC_ATTRS.CALLEE_METHOD]: \"chat/completions\",\n [METRIC_ATTRS.CALLEE_SERVER]: \"openai\",\n [METRIC_ATTRS.CODE]: 0,\n [METRIC_ATTRS.CODE_TYPE]: \"success\",\n };\n\n clientStartedTotal.add(1, clientAttrs);\n const startTime = Date.now();\n let hasError = false;\n\n try {\n const history = this.histories.get(params.qualifier) ?? [];\n history.push({ role: \"user\", content: params.text });\n\n // 保留最近 20 条\n if (history.length > 20) {\n history.splice(0, history.length - 20);\n }\n\n const messages: Message[] = [\n { role: \"system\", content: this.opts.systemPrompt },\n ...history,\n ];\n\n const response = await fetch(`${this.opts.baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.opts.apiKey}`,\n },\n body: JSON.stringify({\n model: this.opts.model,\n messages,\n max_tokens: this.opts.maxTokens,\n temperature: this.opts.temperature,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenAI API ${response.status}: ${text.slice(0, 200)}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error(\"OpenAI API 无响应体\");\n }\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let fullReply = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || !trimmed.startsWith(\"data: \")) continue;\n const data = trimmed.slice(6);\n if (data === \"[DONE]\") continue;\n\n try {\n const parsed = JSON.parse(data);\n const delta = parsed.choices?.[0]?.delta?.content;\n if (delta) {\n fullReply += delta;\n yield { type: \"text\", content: delta };\n }\n } catch {\n // 忽略解析失败的行\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // 记录 assistant 回复到历史\n if (fullReply) {\n history.push({ role: \"assistant\", content: fullReply });\n }\n\n yield { type: \"done\", content: \"\", stopReason: \"stop\" };\n } catch (err) {\n hasError = true;\n clientHandledTotal.add(1, { ...clientAttrs, [METRIC_ATTRS.CODE]: 1, [METRIC_ATTRS.CODE_TYPE]: \"error\" });\n throw err;\n } finally {\n if (!hasError) {\n clientHandledTotal.add(1, clientAttrs);\n }\n clientHandledSeconds.record((Date.now() - startTime) / 1000, clientAttrs);\n }\n }\n\n async shutdown(): Promise<void> {\n this.histories.clear();\n }\n}\n","/**\n * ACP 协议客户端(完整版)\n *\n * 基于 @agentclientprotocol/sdk 的 ClientSideConnection,通过自定义 transport\n * 实现完整的 ACP 双 SSE 流通信。\n *\n * 能力对齐 qqbot-cloudagent:\n * ✅ GET SSE 持久通知流(session/update 实时推送)\n * ✅ POST SSE prompt 响应流\n * ✅ DELETE 优雅关闭\n * ✅ 工具调用权限自动批准(requestPermission)\n * ✅ 协议版本协商(protocolVersion)\n * ✅ agentCapabilities 解析\n * ✅ session/new + session/load\n * ✅ session/cancel\n * ✅ session/set_mode\n * ✅ session/set_model\n * ✅ 连接重试(可配置次数 + 间隔)\n * ✅ 双流时序补偿(通过 onSessionUpdate 回调 + 外部 waitForStable)\n */\n\nimport {\n ClientSideConnection,\n PROTOCOL_VERSION,\n type SessionNotification,\n type McpServer,\n} from \"@agentclientprotocol/sdk\";\n\nimport type { Logger } from \"../utils/logger.js\";\nimport { createTransport, type AcpTransport } from \"./acp-transport.js\";\nimport type { AcpEvent } from \"./types.js\";\nimport { acpConnectSeconds, acpConnectRetries } from \"../telemetry/metrics.js\";\n\n// ============ Public Types ============\n\nexport interface PromptBlock {\n type: \"text\" | \"image\" | \"resource_link\";\n text?: string;\n /** Base64 图片数据(image 类型必填) */\n data?: string;\n /** 资源 URL */\n uri?: string;\n /** 资源名 */\n name?: string;\n /** MIME 类型 */\n mimeType?: string;\n /** 字节数 */\n size?: number;\n /** 描述 */\n description?: string;\n}\n\nexport interface AcpClientOptions {\n endpoint: string;\n authToken: string;\n maxRetries: number;\n retryIntervalMs: number;\n /** 等待下一个 ACP 事件的超时时间(ms)。默认 180_000 */\n eventTimeoutMs?: number;\n logger: Logger;\n /** MCP Server 配置(传给 session/new 和 session/load) */\n extraMcpServers?: McpServer[];\n /** session/update 实时通知回调 */\n onSessionUpdate?: (n: SessionNotification) => void;\n /** 连接意外断开时的回调。用于触发上层重连逻辑。 */\n onDisconnect?: () => void;\n /** 工具调用权限请求回调。默认自动批准第一个选项。 */\n onRequestPermission?: (params: any) => Promise<{\n outcome: { outcome: \"selected\"; optionId: string };\n }>;\n}\n\nexport type AcpMode = \"default\" | \"acceptEdits\" | \"bypassPermissions\" | \"plan\";\n\n// ============ Client ============\n\nexport class AcpClient {\n private opts: AcpClientOptions;\n private transport?: AcpTransport;\n private connection?: ClientSideConnection;\n private _connected = false;\n /** Agent 能力集(initialize 后填充) */\n private agentCapabilities: unknown = null;\n /** 内部事件缓冲:sessionUpdate 推送的 chunk 暂存于此 */\n private eventBuffer: AcpEvent[] = [];\n private eventWaiters: Array<(ev: AcpEvent | null) => void> = [];\n private promptDone = false;\n /** Only accept chunks when actively prompting (ignore session resume replay). */\n private prompting = false;\n /** Last time any ACP activity was received (for idle timeout). */\n private lastActivityAt = 0;\n\n constructor(opts: AcpClientOptions) {\n this.opts = opts;\n }\n\n get isConnected(): boolean {\n return this._connected;\n }\n\n // ============ 连接 ============\n\n /**\n * 建立 SSE + initialize 握手。\n * 自动重试(默认 20 次 × 3s),触发沙箱唤醒。\n */\n async connect(): Promise<void> {\n const { logger, endpoint, authToken, maxRetries, retryIntervalMs } = this.opts;\n logger.info(`[acp] connecting to ${endpoint} ...`);\n const connectStart = Date.now();\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n this.transport = createTransport({ endpoint, authToken, logger });\n this.connection = new ClientSideConnection(\n () => ({\n sessionUpdate: async (params: SessionNotification) => {\n try {\n this.handleSessionUpdate(params);\n this.opts.onSessionUpdate?.(params);\n } catch (e: any) {\n logger.error(`[acp] onSessionUpdate error: ${e?.message ?? e}`);\n }\n },\n requestPermission: async (params: any) => {\n if (this.opts.onRequestPermission) {\n return this.opts.onRequestPermission(params);\n }\n // 默认自动同意第一个选项\n const first = params.options?.[0];\n logger.debug?.(\n `[acp] auto-approve permission: ${first?.optionId ?? \"approve\"}`,\n );\n return {\n outcome: {\n outcome: \"selected\" as const,\n optionId: first?.optionId ?? \"approve\",\n },\n };\n },\n // 处理 SDK 未内置的扩展通知(消除 \"Method not found\" 警告)\n extNotification: async (method: string, params: any) => {\n if (!this.prompting) return;\n switch (method) {\n case \"session/endTurn\": {\n const stopReason = params?.stopReason ?? \"end_turn\";\n logger.debug?.(`[acp] endTurn: stopReason=${stopReason}`);\n this.promptDone = true;\n // 将 stopReason 作为 done 事件入队,供上层感知结束原因\n const doneEvent: AcpEvent = { type: \"done\", text: \"\", stopReason };\n if (this.eventWaiters.length > 0) {\n this.eventWaiters.shift()!(doneEvent);\n } else {\n this.eventBuffer.push(doneEvent);\n }\n break;\n }\n default:\n logger.debug?.(`[acp] unknown notification: ${method}`);\n break;\n }\n },\n }),\n this.transport,\n );\n\n await this.transport.ready;\n const initResp = await this.connection.initialize({\n protocolVersion: PROTOCOL_VERSION,\n clientCapabilities: {\n fs: { readTextFile: false, writeTextFile: false },\n },\n });\n this.agentCapabilities = initResp.agentCapabilities;\n this._connected = true;\n acpConnectSeconds.record((Date.now() - connectStart) / 1000, { result: \"success\" });\n if (attempt > 1) {\n acpConnectRetries.add(attempt - 1, { result: \"success\" });\n }\n logger.info(\n `[acp] initialized (attempt=${attempt}, capabilities=${JSON.stringify(initResp.agentCapabilities)})`,\n );\n return;\n } catch (e: any) {\n this.transport = undefined;\n this.connection = undefined;\n if (attempt >= maxRetries) {\n acpConnectSeconds.record((Date.now() - connectStart) / 1000, { result: \"fail\" });\n acpConnectRetries.add(attempt, { result: \"fail\" });\n throw new Error(\n `ACP connect failed after ${maxRetries} attempts: ${e?.message ?? e}`,\n );\n }\n logger.info(\n `[acp] attempt ${attempt}/${maxRetries} failed: ${e?.message ?? e}, retrying in ${retryIntervalMs / 1000}s`,\n );\n await new Promise((r) => setTimeout(r, retryIntervalMs));\n }\n }\n }\n\n // ============ Session 管理 ============\n\n /** 创建新 ACP session */\n async createSession(cwd = \"/workspace\"): Promise<string> {\n if (!this.connection) throw new Error(\"ACP not connected\");\n const mcpServers = this.opts.extraMcpServers ?? [];\n const resp = await this.connection.newSession({ cwd, mcpServers });\n this.opts.logger.info(\n `[acp] session created: ${resp.sessionId} (cwd=${cwd}, mcp=${mcpServers.length})`,\n );\n this.opts.logger.debug?.(`[acp] newSession response: ${JSON.stringify(resp)}`);\n return resp.sessionId;\n }\n\n /** 加载已有 session(含历史回放) */\n async loadSession(sessionId: string, cwd = \"/workspace\"): Promise<void> {\n if (!this.connection) throw new Error(\"ACP not connected\");\n const mcpServers = this.opts.extraMcpServers ?? [];\n const resp = await this.connection.loadSession({ sessionId, cwd, mcpServers });\n this.opts.logger.info(`[acp] session loaded: ${sessionId}`);\n this.opts.logger.debug?.(`[acp] loadSession response: ${JSON.stringify(resp)}`);\n }\n\n /** 取消当前正在执行的 prompt */\n cancelPrompt(sessionId: string): void {\n if (!this.connection) return;\n this.connection.cancel({ sessionId }).catch((err: any) => {\n this.opts.logger.debug?.(`[acp] cancel error: ${err?.message ?? err}`);\n });\n this.opts.logger.info(`[acp] cancel sent for session=${sessionId}`);\n }\n\n /** 切换权限模式 */\n async setMode(sessionId: string, modeId: AcpMode): Promise<void> {\n if (!this.connection) throw new Error(\"ACP not connected\");\n await (this.connection as any).request?.(\"session/set_mode\", { sessionId, modeId });\n this.opts.logger.info(`[acp] mode set to ${modeId} for session=${sessionId}`);\n }\n\n /** 切换模型 */\n async setModel(sessionId: string, modelId: string): Promise<void> {\n if (!this.connection) throw new Error(\"ACP not connected\");\n await (this.connection as any).request?.(\"session/set_model\", { sessionId, modelId });\n this.opts.logger.info(`[acp] model set to ${modelId} for session=${sessionId}`);\n }\n\n // ============ Prompt(流式输出) ============\n\n /**\n * 发送 prompt 并流式接收回复。\n *\n * 同时消费:\n * - POST SSE(prompt 直接响应流)\n * - GET SSE(session/update 推送的 agent_message_chunk 等)\n *\n * 通过 eventBuffer + waitForStable 实现双流时序补偿。\n */\n async *promptStream(\n sessionId: string,\n blocks: PromptBlock[],\n ): AsyncIterableIterator<AcpEvent> {\n if (!this.connection) throw new Error(\"ACP not connected\");\n\n // 清空事件缓冲\n this.eventBuffer = [];\n this.eventWaiters = [];\n this.promptDone = false;\n this.prompting = true;\n this.lastActivityAt = Date.now();\n\n // 启动 prompt(异步,响应通过 GET/POST SSE 到达 sessionUpdate 回调)\n const promptPromise = this.connection.prompt({\n sessionId,\n prompt: blocks as any,\n });\n // prompt reject 时主动唤醒 nextEvent 循环,生成 error done 事件\n promptPromise.catch((err) => {\n this.promptDone = true;\n const errorEvent: AcpEvent = {\n type: \"done\",\n text: err?.message ?? String(err),\n stopReason: \"error\",\n };\n if (this.eventWaiters.length > 0) {\n this.eventWaiters.shift()!(errorEvent);\n } else {\n this.eventBuffer.push(errorEvent);\n }\n });\n\n // 流式消费 eventBuffer 中的事件\n try {\n while (true) {\n const event = await this.nextEvent();\n if (event === null) {\n // idle timeout — 生成 timeout done 事件\n yield { type: \"done\", text: \"\", stopReason: \"timeout\" } as AcpEvent;\n break;\n }\n yield event;\n if (event.type === \"done\") break;\n }\n } finally {\n // 确保 prompt Promise 被消费\n try {\n const result = await promptPromise;\n // prompt 结束后等待尾部 chunk(双流时序补偿)\n await this.waitForStable();\n // 排空剩余 buffer\n while (this.eventBuffer.length > 0) {\n const ev = this.eventBuffer.shift()!;\n if (ev.type !== \"done\") {\n // 注意:generator 已经退出 yield 循环,这里只是确保不丢数据\n // 实际场景由上层 accumulator 处理\n }\n }\n if (!this.promptDone) {\n this.promptDone = true;\n }\n } catch (e: any) {\n this.opts.logger.error(`[acp] prompt error: ${e?.message ?? e}`);\n throw e;\n } finally {\n this.prompting = false;\n }\n }\n }\n\n /**\n * 发送 prompt(非流式,等待完成后返回 stopReason)。\n * 适合不需要流式输出的场景。\n */\n async prompt(sessionId: string, input: string | PromptBlock[]): Promise<string> {\n if (!this.connection) throw new Error(\"ACP not connected\");\n const blocks: PromptBlock[] =\n typeof input === \"string\" ? [{ type: \"text\", text: input }] : input;\n const resp = await this.connection.prompt({\n sessionId,\n prompt: blocks as any,\n });\n return resp.stopReason;\n }\n\n // ============ 关闭 ============\n\n async close(): Promise<void> {\n if (this.transport) {\n await this.transport.close();\n this.transport = undefined;\n }\n this.connection = undefined;\n this._connected = false;\n // 唤醒所有 waiters\n while (this.eventWaiters.length > 0) {\n this.eventWaiters.shift()!(null);\n }\n this.opts.logger.info(\"[acp] closed\");\n }\n\n /**\n * 标记连接已断开(由外部错误处理调用)。\n * 下次 ensureAcpReady 会触发重连。\n */\n markDisconnected(): void {\n this._connected = false;\n // 唤醒所有等待中的 prompt waiters\n while (this.eventWaiters.length > 0) {\n this.eventWaiters.shift()!(null);\n }\n }\n\n // ============ 内部 ============\n\n /**\n * 处理 GET SSE 推送的 session/update 通知。\n * 将解析后的事件入队到 eventBuffer,供 promptStream 消费。\n */\n private handleSessionUpdate(n: SessionNotification): void {\n const update = (n as any).update ?? {};\n const t = update.sessionUpdate ?? update.type;\n\n // Ignore chunks outside of active prompt (e.g. session resume replay)\n if (!this.prompting) return;\n\n // Any ACP activity resets the idle timeout (including filtered events)\n this.lastActivityAt = Date.now();\n\n this.opts.logger.debug?.(\n `[acp:raw] type=${t} ${JSON.stringify(update)}`,\n );\n\n let event: AcpEvent | null = null;\n\n switch (t) {\n case \"agent_message_chunk\": {\n const txt = update.content?.text ?? \"\";\n if (txt) event = { type: \"agent_message_chunk\", text: txt };\n break;\n }\n case \"agent_thought_chunk\": {\n const txt = update.content?.text ?? \"\";\n if (txt) event = { type: \"agent_thought_chunk\", text: txt };\n break;\n }\n case \"tool_call\": {\n event = {\n type: \"tool_call\",\n text: \"\",\n title: update.title,\n toolCallId: update.toolCallId,\n kind: update.kind,\n status: update.status,\n rawInput: update.rawInput,\n };\n break;\n }\n case \"tool_call_update\": {\n // completed/failed 状态需要通知上层;pending 是参数逐字流入,静默\n if (update.status === \"completed\" || update.status === \"failed\") {\n event = {\n type: \"tool_call_update\",\n text: \"\",\n toolCallId: update.toolCallId,\n status: update.status,\n };\n }\n break;\n }\n case \"plan\": {\n event = { type: \"plan\", text: \"\", entries: update.entries };\n break;\n }\n default:\n break;\n }\n\n if (event) {\n if (this.eventWaiters.length > 0) {\n this.eventWaiters.shift()!(event);\n } else {\n this.eventBuffer.push(event);\n }\n }\n }\n\n /** 从 eventBuffer 取下一个事件(阻塞等待) */\n private nextEvent(): Promise<AcpEvent | null> {\n if (this.eventBuffer.length > 0) {\n return Promise.resolve(this.eventBuffer.shift()!);\n }\n if (this.promptDone) {\n return Promise.resolve(null);\n }\n const timeoutMs = this.opts.eventTimeoutMs ?? 180_000;\n return new Promise((resolve) => {\n this.eventWaiters.push(resolve);\n // Idle-based timeout: checks elapsed since last ACP activity.\n // This keeps alive when tools stream pending updates without\n // producing queued events.\n const checkInterval = setInterval(() => {\n const idx = this.eventWaiters.indexOf(resolve as any);\n if (idx < 0) {\n // Already resolved by incoming event\n clearInterval(checkInterval);\n return;\n }\n const idle = Date.now() - this.lastActivityAt;\n if (idle >= timeoutMs) {\n clearInterval(checkInterval);\n this.eventWaiters.splice(idx, 1);\n this.opts.logger.debug?.(`[acp] nextEvent idle timeout (${timeoutMs / 1000}s), returning null`);\n resolve(null);\n }\n }, 5_000);\n });\n }\n\n /**\n * 双流时序补偿:等待 GET SSE 中可能还在路上的 chunk 落地。\n * prompt POST SSE 返回后,GET SSE 可能还有 ~80ms 延迟的 chunk。\n */\n private async waitForStable(quietMs = 300, maxWaitMs = 1500): Promise<void> {\n const start = Date.now();\n let lastEventAt = Date.now();\n\n while (Date.now() - start < maxWaitMs) {\n if (this.eventBuffer.length > 0) {\n lastEventAt = Date.now();\n await new Promise((r) => setTimeout(r, 50));\n continue;\n }\n const silent = Date.now() - lastEventAt;\n if (silent >= quietMs) return;\n await new Promise((r) => setTimeout(r, quietMs - silent));\n }\n }\n}\n\nexport type { SessionNotification };\n","/**\n * ACP Streamable HTTP Transport\n *\n * 从 qqbot-cloudagent/src/acp/transport.ts 移植。\n * 实现 @agentclientprotocol/sdk 所需的 Stream 接口(双 SSE 流模型)。\n *\n * 协议:\n * GET {endpoint} → SSE 长连,响应头 Acp-Connection-Id\n * POST {endpoint} → JSON-RPC 消息,带 Acp-Connection-Id\n * DELETE {endpoint} → 优雅关闭\n */\n\nimport type { AnyMessage, Stream } from \"@agentclientprotocol/sdk\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { transportDisconnectTotal } from \"../telemetry/metrics.js\";\n\nexport interface TransportOptions {\n endpoint: string;\n authToken: string;\n logger?: Logger;\n}\n\nexport interface AcpTransport extends Stream {\n readonly ready: Promise<void>;\n close(): Promise<void>;\n}\n\nexport function createTransport(options: TransportOptions): AcpTransport {\n const { endpoint, authToken, logger } = options;\n\n let connectionId: string | undefined;\n let closed = false;\n const abortController = new AbortController();\n\n let resolveReady!: () => void;\n let rejectReady!: (e: Error) => void;\n const ready = new Promise<void>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n });\n\n const queue: AnyMessage[] = [];\n const waiters: Array<(m: AnyMessage | null) => void> = [];\n\n const enqueue = (m: AnyMessage) => {\n if (waiters.length > 0) waiters.shift()!(m);\n else queue.push(m);\n };\n const dequeue = (): Promise<AnyMessage | null> => {\n if (closed && queue.length === 0) return Promise.resolve(null);\n if (queue.length > 0) return Promise.resolve(queue.shift()!);\n return new Promise((resolve) => waiters.push(resolve));\n };\n const closeAll = () => {\n closed = true;\n while (waiters.length > 0) waiters.shift()!(null);\n };\n\n const baseHeaders = (): Record<string, string> => ({\n Authorization: `Bearer ${authToken}`,\n });\n\n // --- GET SSE: 持久通知流 ---\n async function startSSE() {\n try {\n const headers = baseHeaders();\n headers[\"Accept\"] = \"text/event-stream\";\n const res = await fetch(endpoint, {\n method: \"GET\",\n headers,\n signal: abortController.signal,\n });\n if (!res.ok) {\n throw new Error(`SSE GET failed: HTTP ${res.status} ${res.statusText}`);\n }\n const id = res.headers.get(\"Acp-Connection-Id\");\n if (!id) throw new Error(\"Missing Acp-Connection-Id header\");\n connectionId = id;\n resolveReady();\n logger?.info?.(`[acp:transport] SSE connected, connectionId=${id}`);\n\n const reader = res.body?.getReader();\n if (!reader) throw new Error(\"No SSE body reader\");\n const decoder = new TextDecoder();\n let buf = \"\";\n let evtData = \"\";\n let evtType = \"\";\n\n while (!closed) {\n const { value, done } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() ?? \"\";\n for (const line of lines) {\n if (line === \"\") {\n if (evtData && evtType !== \"connected\") {\n try {\n const msg = JSON.parse(evtData);\n if (msg && typeof msg === \"object\" && \"jsonrpc\" in msg) {\n enqueue(msg as AnyMessage);\n }\n } catch {\n /* ignore non-JSON */\n }\n }\n evtData = \"\";\n evtType = \"\";\n continue;\n }\n if (line.startsWith(\":\")) continue; // 心跳或注释\n const idx = line.indexOf(\":\");\n if (idx === -1) continue;\n const field = line.slice(0, idx);\n let val = line.slice(idx + 1);\n if (val.startsWith(\" \")) val = val.slice(1);\n if (field === \"event\") evtType = val;\n if (field === \"data\") evtData = (evtData || \"\") + val;\n }\n }\n } catch (err: any) {\n if (!closed && err?.name !== \"AbortError\") {\n transportDisconnectTotal.add(1);\n logger?.error?.(`[acp:transport] SSE error: ${err?.message ?? err}`);\n rejectReady(err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n closeAll();\n }\n }\n\n // --- POST: 发送 JSON-RPC 消息 ---\n async function sendMessage(message: AnyMessage): Promise<void> {\n if (closed) throw new Error(\"Transport closed\");\n await ready;\n const headers = baseHeaders();\n headers[\"Content-Type\"] = \"application/json\";\n headers[\"Accept\"] = \"application/json, text/event-stream\";\n headers[\"Acp-Connection-Id\"] = connectionId!;\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(message),\n });\n if (!res.ok) {\n const t = await res.text().catch(() => \"\");\n throw new Error(`POST failed: HTTP ${res.status} ${t.slice(0, 200)}`);\n }\n const ct = res.headers.get(\"Content-Type\") ?? \"\";\n if (ct.includes(\"text/event-stream\")) {\n // POST SSE(prompt 响应流)—— 异步消费并入队\n const reader = res.body?.getReader();\n if (reader) {\n processPostSSE(reader).catch((e) =>\n logger?.error?.(`[acp:transport] POST SSE error: ${e?.message ?? e}`),\n );\n }\n } else if (ct.includes(\"application/json\")) {\n const data = (await res.json()) as unknown;\n if (data && typeof data === \"object\" && \"jsonrpc\" in (data as object)) {\n enqueue(data as AnyMessage);\n }\n }\n // 202 No body -> 响应通过 GET SSE 异步到达\n }\n\n async function processPostSSE(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n ): Promise<void> {\n const decoder = new TextDecoder();\n let buf = \"\";\n let data = \"\";\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() ?? \"\";\n for (const line of lines) {\n if (line === \"\") {\n if (data) {\n try {\n const m = JSON.parse(data);\n if (m && typeof m === \"object\" && \"jsonrpc\" in m) {\n enqueue(m as AnyMessage);\n }\n } catch {\n /* ignore */\n }\n }\n data = \"\";\n continue;\n }\n if (line.startsWith(\":\")) continue;\n const idx = line.indexOf(\":\");\n if (idx === -1) continue;\n const f = line.slice(0, idx);\n let v = line.slice(idx + 1);\n if (v.startsWith(\" \")) v = v.slice(1);\n if (f === \"data\") data = (data || \"\") + v;\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n // --- DELETE: 优雅关闭 ---\n async function close(): Promise<void> {\n if (closed) return;\n if (connectionId) {\n try {\n const headers = baseHeaders();\n headers[\"Acp-Connection-Id\"] = connectionId;\n await fetch(endpoint, {\n method: \"DELETE\",\n headers,\n signal: AbortSignal.timeout(5000),\n });\n logger?.debug?.(`[acp:transport] DELETE sent`);\n } catch {\n /* ignore */\n }\n }\n abortController.abort();\n closeAll();\n }\n\n // --- Stream 接口 ---\n const readable = new ReadableStream<AnyMessage>({\n async pull(controller) {\n const m = await dequeue();\n if (m === null) controller.close();\n else controller.enqueue(m);\n },\n cancel() {\n closeAll();\n abortController.abort();\n },\n });\n\n const writable = new WritableStream<AnyMessage>({\n async write(m) {\n await sendMessage(m);\n },\n close() {\n closeAll();\n },\n abort() {\n closeAll();\n abortController.abort();\n },\n });\n\n // 启动 GET SSE 长连\n startSSE();\n\n return { readable, writable, ready, close };\n}\n","/**\n * AgentOS REST API — 沙箱生命周期管理\n *\n * 从 qqbot-cloudagent/src/agentos/client.ts 移植精简。\n */\n\nimport JSONBig from \"json-bigint\";\nimport type { Logger } from \"../utils/logger.js\";\nimport type { ApiResponse, RuntimeResponse, SessionResponse } from \"./types.js\";\nimport { sandboxStartSeconds, sessionCreateSeconds } from \"../telemetry/metrics.js\";\n\nconst JSONB = JSONBig({ storeAsString: true });\n\nexport interface CreateSandboxParams {\n runtimeName: string;\n apiKey: string;\n endpoint: string;\n systemPrompt?: string;\n logger?: Logger;\n}\n\nexport async function createSandbox(params: CreateSandboxParams): Promise<RuntimeResponse> {\n const { runtimeName, apiKey, endpoint, systemPrompt, logger } = params;\n const url = `${endpoint}/agentos/runtimes`;\n const body = JSON.stringify({ runtimeName, agentManifest: {\n id: runtimeName,\n name: runtimeName,\n manifestVersion: \"1.0\",\n system_prompt: systemPrompt ?? \"You are a helpful assistant running inside a QQ Bot.\",\n secrets: [{ key: \"CODEBUDDY_API_KEY\", value: apiKey }],\n }});\n\n logger?.debug?.(`[agentos] >>> POST ${url}`);\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"x-api-key\": apiKey, \"X-Sandbox-Type\": \"AGS\" },\n body,\n });\n\n return parseApiResponse<RuntimeResponse>(res, `POST ${url}`, logger);\n}\n\nexport async function getRuntime(\n runtimeId: string,\n apiKey: string,\n endpoint: string,\n logger?: Logger,\n): Promise<RuntimeResponse> {\n const url = `${endpoint}/agentos/runtimes/${runtimeId}`;\n logger?.debug?.(`[agentos] >>> GET ${url}`);\n\n const res = await fetch(url, {\n method: \"GET\",\n headers: { \"x-api-key\": apiKey },\n });\n\n return parseApiResponse<RuntimeResponse>(res, `GET ${url}`, logger);\n}\n\nexport async function waitForRunning(\n runtimeId: string,\n apiKey: string,\n endpoint: string,\n opts: { maxWaitMs?: number; intervalMs?: number; logger?: Logger } = {},\n): Promise<RuntimeResponse> {\n const maxWaitMs = opts.maxWaitMs ?? 180_000;\n const intervalMs = opts.intervalMs ?? 3_000;\n const start = Date.now();\n\n while (Date.now() - start < maxWaitMs) {\n const rt = await getRuntime(runtimeId, apiKey, endpoint, opts.logger);\n if (rt.status === \"RUNNING\") {\n sandboxStartSeconds.record((Date.now() - start) / 1000);\n return rt;\n }\n if (rt.status === \"FAILED\") {\n throw new Error(`Runtime ${runtimeId} FAILED: ${rt.failureReason ?? \"unknown\"}`);\n }\n const elapsed = Math.round((Date.now() - start) / 1000);\n opts.logger?.info?.(`[sandbox] status=${rt.status}, waiting... (${elapsed}s)`);\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n throw new Error(`Runtime ${runtimeId} not ready within ${maxWaitMs / 1000}s`);\n}\n\n// ============ Session 管理(控制面) ============\n\nexport async function createControlPlaneSession(\n runtimeId: string,\n sessionId: string,\n apiKey: string,\n endpoint: string,\n logger?: Logger,\n): Promise<SessionResponse> {\n const url = `${endpoint}/agentos/runtimes/${runtimeId}/sessions`;\n const body = JSON.stringify({\n sessionId,\n agentManifest: {\n id: \"qqbot-cli\",\n name: \"QQBot-CLI\",\n manifestVersion: \"1.0\",\n },\n });\n\n logger?.debug?.(`[agentos] >>> POST ${url} body=${body}`);\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"x-api-key\": apiKey },\n body,\n });\n\n return parseApiResponse<SessionResponse>(res, `POST ${url}`, logger);\n}\n\n/**\n * 列出 runtime 下的 sessions,支持 status 过滤。\n */\nexport async function listSessions(\n runtimeId: string,\n apiKey: string,\n endpoint: string,\n opts: { sessionStatus?: string; logger?: Logger } = {},\n): Promise<SessionResponse[]> {\n const params = new URLSearchParams();\n if (opts.sessionStatus) {\n params.set(\"session_status\", opts.sessionStatus);\n }\n const qs = params.toString();\n const url = `${endpoint}/agentos/runtimes/${runtimeId}/sessions${qs ? `?${qs}` : \"\"}`;\n opts.logger?.debug?.(`[agentos] >>> GET ${url}`);\n\n const res = await fetch(url, {\n method: \"GET\",\n headers: { \"x-api-key\": apiKey },\n });\n\n const data = await parseApiResponse<{ items: SessionResponse[] }>(res, `GET ${url}`, opts.logger);\n return data.items ?? [];\n}\n\n/**\n * 查询指定 sessionId 的详情。\n * 找不到时返回 null(404)。\n */\nexport async function getSession(\n runtimeId: string,\n sessionId: string,\n apiKey: string,\n endpoint: string,\n logger?: Logger,\n): Promise<SessionResponse | null> {\n const url = `${endpoint}/agentos/runtimes/${runtimeId}/sessions/${sessionId}`;\n logger?.debug?.(`[agentos] >>> GET ${url}`);\n\n const res = await fetch(url, {\n method: \"GET\",\n headers: { \"x-api-key\": apiKey },\n });\n\n if (res.status === 404) {\n const text = await res.text().catch(() => \"\");\n logger?.debug?.(`[agentos] <<< 404 ${text}`);\n return null;\n }\n\n return parseApiResponse<SessionResponse>(res, `GET ${url}`, logger);\n}\n\n/**\n * 等待 session 状态变为 RUNNING(或其他就绪状态)。\n * 控制面创建 session 后状态为 CREATING,需要轮询等待就绪。\n */\nexport async function waitForSessionReady(\n runtimeId: string,\n sessionId: string,\n apiKey: string,\n endpoint: string,\n opts: { maxWaitMs?: number; intervalMs?: number; logger?: Logger } = {},\n): Promise<SessionResponse> {\n const maxWaitMs = opts.maxWaitMs ?? 30_000;\n const intervalMs = opts.intervalMs ?? 1_000;\n const start = Date.now();\n\n while (Date.now() - start < maxWaitMs) {\n const sess = await getSession(runtimeId, sessionId, apiKey, endpoint, opts.logger);\n if (!sess) {\n await new Promise((r) => setTimeout(r, intervalMs));\n continue;\n }\n const status = sess.sessionStatus.toUpperCase();\n if (status === \"RUNNING\" || status === \"READY\" || status === \"ACTIVE\") {\n sessionCreateSeconds.record((Date.now() - start) / 1000);\n return sess;\n }\n if (status === \"FAILED\" || status === \"ERROR\") {\n throw new Error(`Session ${sessionId} failed: status=${sess.sessionStatus}`);\n }\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n throw new Error(`Session ${sessionId} not ready within ${maxWaitMs / 1000}s`);\n}\n\nexport async function deleteControlPlaneSession(\n runtimeId: string,\n sessionId: string,\n apiKey: string,\n endpoint: string,\n logger?: Logger,\n): Promise<void> {\n const url = `${endpoint}/agentos/runtimes/${runtimeId}/sessions/${sessionId}/delete`;\n logger?.debug?.(`[agentos] >>> POST ${url}`);\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"x-api-key\": apiKey },\n signal: AbortSignal.timeout(5000),\n });\n\n if (!res.ok) {\n const t = await res.text().catch(() => \"\");\n logger?.debug?.(`[agentos] <<< ${res.status} ${t}`);\n throw new Error(`deleteSession HTTP ${res.status}: ${t}`);\n }\n logger?.debug?.(`[agentos] <<< ${res.status} OK`);\n}\n\n// ============ Internal ============\n\nasync function parseApiResponse<T>(res: Response, path: string, logger?: Logger): Promise<T> {\n const text = await res.text().catch(() => \"\");\n logger?.debug?.(`[agentos] <<< ${res.status} ${text}`);\n\n if (!res.ok) {\n throw new Error(`AgentOS HTTP ${res.status}: ${text} [${path}]`);\n }\n let json: ApiResponse<T>;\n try {\n json = JSONB.parse(text) as ApiResponse<T>;\n } catch {\n throw new Error(`AgentOS response parse failed [${path}]`);\n }\n if (json.code !== 0) {\n throw new Error(`AgentOS error [${path}] code=${json.code}: ${json.msg}`);\n }\n if (!json.data) {\n throw new Error(`AgentOS empty data [${path}]`);\n }\n return json.data;\n}\n","/**\n * Client Interceptor — 主调拦截器\n *\n * 统一拦截所有外部调用,自动记录:\n * - 主调指标(clientStartedTotal / clientHandledTotal / clientHandledSeconds)\n * - 主调 span(SpanKind.CLIENT,自动传播 traceId)\n *\n * 业务代码无需关心埋点逻辑,只需通过 `withClientMetrics` 包装异步函数即可。\n */\n\nimport { trace, SpanKind, SpanStatusCode } from \"@opentelemetry/api\";\nimport { METRIC_ATTRS } from \"./constants.js\";\nimport { clientStartedTotal, clientHandledTotal, clientHandledSeconds } from \"./metrics.js\";\n\nconst tracer = trace.getTracer(\"qqbot-cli\");\n\n// ============ Types ============\n\nexport interface ClientCallOptions {\n /** 主调方法名 */\n callerMethod: string;\n /** 被调服务 */\n calleeService: string;\n /** 被调方法 */\n calleeMethod: string;\n /** 被调服务名(默认与 calleeService 相同) */\n calleeServer?: string;\n /** 额外维度 */\n extras?: Record<string, string>;\n}\n\n// ============ 一次性调用 ============\n\n/**\n * 包装一个异步调用,自动上报主调指标 + span。\n */\nexport async function withClientMetrics<T>(\n opts: ClientCallOptions,\n fn: () => Promise<T>,\n): Promise<T> {\n const attrs = buildAttrs(opts);\n const spanName = `${opts.calleeService}/${opts.calleeMethod}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n \"rpc.system\": \"custom\",\n \"rpc.service\": opts.calleeService,\n \"rpc.method\": opts.calleeMethod,\n \"caller.service\": \"qqbot-cli\",\n \"caller.method\": opts.callerMethod,\n ...opts.extras,\n },\n },\n async (span) => {\n clientStartedTotal.add(1, attrs);\n const startTime = Date.now();\n\n try {\n const result = await fn();\n span.setStatus({ code: SpanStatusCode.OK });\n clientHandledTotal.add(1, attrs);\n return result;\n } catch (err) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err instanceof Error ? err.message : String(err),\n });\n span.recordException(err instanceof Error ? err : new Error(String(err)));\n clientHandledTotal.add(1, {\n ...attrs,\n [METRIC_ATTRS.CODE]: 1,\n [METRIC_ATTRS.CODE_TYPE]: \"error\",\n });\n throw err;\n } finally {\n span.end();\n clientHandledSeconds.record((Date.now() - startTime) / 1000, attrs);\n }\n },\n );\n}\n\n// ============ 函数包装器 ============\n\n/**\n * 将一个异步函数包装为带主调指标 + span 的版本。\n * 返回的函数签名与原函数一致。\n */\nexport function interceptClient<TArgs extends unknown[], TResult>(\n opts: ClientCallOptions,\n fn: (...args: TArgs) => Promise<TResult>,\n): (...args: TArgs) => Promise<TResult> {\n return (...args: TArgs) => withClientMetrics(opts, () => fn(...args));\n}\n\n// ============ 内部 ============\n\nfunction buildAttrs(opts: ClientCallOptions) {\n return {\n [METRIC_ATTRS.CALLER_SERVICE]: \"qqbot-cli\",\n [METRIC_ATTRS.CALLER_METHOD]: opts.callerMethod,\n [METRIC_ATTRS.CALLER_SERVER]: \"qqbot-cli\",\n [METRIC_ATTRS.CALLEE_SERVICE]: opts.calleeService,\n [METRIC_ATTRS.CALLEE_METHOD]: opts.calleeMethod,\n [METRIC_ATTRS.CALLEE_SERVER]: opts.calleeServer ?? opts.calleeService,\n [METRIC_ATTRS.CODE]: 0,\n [METRIC_ATTRS.CODE_TYPE]: \"success\",\n ...opts.extras,\n };\n}\n","/**\n * AcpConnectionPool — 多用户 ACP 连接池\n *\n * 每个 qualifier(用户/群)维护独立的 ACP SSE 连接 + Session,\n * 支持真正的多 Session 并发。\n *\n * 特性:\n * - 按 qualifier 隔离连接(独立 SSE + sessionId)\n * - 并发安全(pendingCreates 去重)\n * - LRU 淘汰超限连接\n * - 定时清理空闲连接\n * - Soft-close 保留服务端 session(下次 load 恢复上下文)\n * - 断线自动恢复\n */\n\nimport { AcpClient } from \"./acp-client.js\";\nimport {\n createControlPlaneSession,\n deleteControlPlaneSession,\n getSession,\n waitForSessionReady,\n} from \"./sandbox.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport type { McpServer } from \"@agentclientprotocol/sdk\";\nimport { poolSize, poolEvictTotal, poolRestoreTotal, poolCreateSeconds } from \"../telemetry/metrics.js\";\nimport { withClientMetrics } from \"../telemetry/client-interceptor.js\";\n\n\n// ─── Types ───\n\nexport type PoolEntryStatus = \"creating\" | \"active\" | \"evicted\" | \"closing\";\n\nexport interface PoolEntry {\n qualifier: string;\n sessionId: string;\n client: AcpClient;\n status: PoolEntryStatus;\n createdAt: number;\n lastActivityAt: number;\n}\n\nexport interface ConnectionPoolConfig {\n /** 最大并发连接数。超限时 LRU 淘汰。默认 20 */\n maxConnections: number;\n /** 是否启用空闲清理。默认 true */\n enableCleanup: boolean;\n /** 连接空闲超时(ms)。超时后 soft-close。默认 30min */\n idleTimeoutMs: number;\n /** 清理扫描间隔(ms)。默认 60s */\n cleanupIntervalMs: number;\n /** soft-close 时是否保留服务端 Session。默认 true */\n preserveOnEvict: boolean;\n /** ACP 端点 URL */\n acpEndpoint: string;\n /** ACP 认证 token */\n acpToken: string;\n /** ACP 连接重试次数 */\n acpConnectRetries: number;\n /** ACP 连接重试间隔(ms) */\n acpRetryIntervalMs: number;\n /** ACP 事件等待超时(ms) */\n eventTimeoutMs: number;\n /** MCP Servers 传给每个 session */\n mcpServers: McpServer[];\n /** 控制面参数(auto/manual 模式有值,direct 模式为 undefined) */\n controlPlane?: {\n runtimeId: string;\n apiKey: string;\n endpoint: string;\n };\n logger: Logger;\n}\n\n// ─── ConnectionPool ───\n\nexport class AcpConnectionPool {\n private entries = new Map<string, PoolEntry>();\n /** soft-close 的 session(qualifier → sessionId),恢复时用 */\n private evicted = new Map<string, string>();\n /** 并发创建去重 */\n private pendingCreates = new Map<string, Promise<PoolEntry>>();\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\n private cleaning = false;\n private readonly config: ConnectionPoolConfig;\n\n constructor(config: ConnectionPoolConfig) {\n this.config = config;\n if (config.enableCleanup) {\n this.startCleanup();\n }\n }\n\n /** 当前活跃连接数 */\n get size(): number {\n return this.entries.size;\n }\n\n /** 获取 qualifier 对应的连接和 sessionId */\n get(qualifier: string): PoolEntry | undefined {\n return this.entries.get(qualifier);\n }\n\n /**\n * 获取或创建 qualifier 对应的连接。\n * extSessionId: 外部指定的会话 ID(用于 session/load),undefined 则直接 session/new。\n */\n async getOrCreate(qualifier: string, extSessionId?: string): Promise<{ client: AcpClient; sessionId: string }> {\n // 命中 active\n const existing = this.entries.get(qualifier);\n if (existing && existing.status === \"active\") {\n existing.lastActivityAt = Date.now();\n return { client: existing.client, sessionId: existing.sessionId };\n }\n\n // 命中 creating → await pending\n const pending = this.pendingCreates.get(qualifier);\n if (pending) {\n const entry = await pending;\n return { client: entry.client, sessionId: entry.sessionId };\n }\n\n // 未命中 → ensureSession(查控制面 → create or load)\n const createPromise = this.ensureSession(qualifier, extSessionId);\n this.pendingCreates.set(qualifier, createPromise);\n try {\n const entry = await createPromise;\n return { client: entry.client, sessionId: entry.sessionId };\n } finally {\n this.pendingCreates.delete(qualifier);\n }\n }\n\n /** 刷新活跃时间 */\n touch(qualifier: string): void {\n const entry = this.entries.get(qualifier);\n if (entry) {\n entry.lastActivityAt = Date.now();\n }\n }\n\n /**\n * 恢复断线的连接(外部调用,如 chat 捕获到 connection error)。\n * 关闭旧连接 → ensureSession 重新建立。\n */\n async restore(qualifier: string): Promise<{ client: AcpClient; sessionId: string }> {\n const entry = this.entries.get(qualifier);\n if (entry) {\n await entry.client.close().catch(() => {});\n this.entries.delete(qualifier);\n }\n\n try {\n const restored = await this.ensureSession(qualifier);\n poolRestoreTotal.add(1, { result: \"success\" });\n return { client: restored.client, sessionId: restored.sessionId };\n } catch (err) {\n poolRestoreTotal.add(1, { result: \"fail\" });\n throw err;\n }\n }\n\n /** 主动关闭某个 qualifier 的连接 */\n async close(qualifier: string): Promise<void> {\n const entry = this.entries.get(qualifier);\n if (!entry) return;\n entry.status = \"closing\";\n await entry.client.close().catch(() => {});\n this.entries.delete(qualifier);\n\n // 控制面删除 session(静默失败)\n if (this.config.controlPlane) {\n const { runtimeId, apiKey, endpoint } = this.config.controlPlane;\n await deleteControlPlaneSession(runtimeId, entry.sessionId, apiKey, endpoint, this.config.logger).catch((err) => {\n this.config.logger.debug(\n `[pool] deleteSession failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n }\n\n /** 关闭所有连接(graceful shutdown) */\n async closeAll(): Promise<void> {\n this.stopCleanup();\n const qualifiers = [...this.entries.keys()];\n await Promise.allSettled(qualifiers.map((q) => this.close(q)));\n this.entries.clear();\n this.evicted.clear();\n }\n\n // ─── 内部方法 ───\n\n /** 创建新连接 + 新 session */\n private async createEntry(qualifier: string, extSessionId?: string): Promise<PoolEntry> {\n await this.ensureCapacity();\n\n const now = Date.now();\n const { logger } = this.config;\n let sessionId = extSessionId ?? qualifier;\n\n // 新建 AcpClient 连接\n const client = this.createClient();\n await withClientMetrics({\n callerMethod: \"connect\",\n calleeService: \"cloudagent-acp\",\n calleeMethod: \"connect\",\n }, () => client.connect());\n\n if (this.config.controlPlane) {\n // 有控制面:控制面创建 session → 等就绪 → loadSession 绑定\n const { runtimeId, apiKey, endpoint } = this.config.controlPlane;\n let alreadyExists = false;\n try {\n await withClientMetrics({\n callerMethod: \"session\",\n calleeService: \"agentos\",\n calleeMethod: \"createSession\",\n }, () => createControlPlaneSession(runtimeId, sessionId, apiKey, endpoint, logger));\n } catch (err) {\n // session already exists → 幂等\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes(\"already exists\")) {\n throw err;\n }\n alreadyExists = true;\n logger.info(`[pool] session already exists: ${sessionId}, will load`);\n }\n\n if (!alreadyExists) {\n // 新创建的 session 需要等就绪\n await waitForSessionReady(runtimeId, sessionId, apiKey, endpoint, { logger });\n }\n\n // loadSession 绑定\n await withClientMetrics({\n callerMethod: \"session\",\n calleeService: \"cloudagent-acp\",\n calleeMethod: \"loadSession\",\n }, () => client.loadSession(sessionId));\n } else {\n // direct 模式:有外部 sessionId 则 load,否则直接 new\n if (extSessionId) {\n try {\n await client.loadSession(extSessionId);\n sessionId = extSessionId;\n logger.info(`[pool] direct session/load: ${sessionId}`);\n } catch {\n sessionId = await client.createSession(\"/workspace\");\n logger.info(`[pool] direct session/new (load failed): ${sessionId}`);\n }\n } else {\n sessionId = await client.createSession(\"/workspace\");\n logger.info(`[pool] direct session/new: ${sessionId}`);\n }\n }\n\n const entry: PoolEntry = {\n qualifier,\n sessionId,\n client,\n status: \"active\",\n createdAt: now,\n lastActivityAt: now,\n };\n this.entries.set(qualifier, entry);\n poolCreateSeconds.record((Date.now() - now) / 1000);\n poolSize.record(this.size);\n logger.info(`[pool] created: qualifier=${qualifier} sessionId=${sessionId} (active=${this.size})`);\n\n return entry;\n }\n\n /**\n * 确保 session 存在并连接。\n * 1. 控制面 getSession 查是否已存在\n * 2. 存在 → connect + loadSession\n * 3. 不存在 → 控制面 create → 等就绪 → connect + loadSession\n */\n private async ensureSession(qualifier: string, extSessionId?: string): Promise<PoolEntry> {\n await this.ensureCapacity();\n\n const { logger } = this.config;\n const sessionId = extSessionId ?? qualifier;\n this.evicted.delete(qualifier);\n\n let sessionExists = false;\n\n // 查控制面 session 是否已存在\n if (this.config.controlPlane) {\n const { runtimeId, apiKey, endpoint } = this.config.controlPlane;\n const sess = await getSession(runtimeId, sessionId, apiKey, endpoint, logger);\n if (sess) {\n const status = sess.sessionStatus.toUpperCase();\n sessionExists = status !== \"FAILED\" && status !== \"ERROR\";\n logger.info(`[pool] session exists: ${sessionId} status=${sess.sessionStatus}`);\n } else {\n logger.info(`[pool] session not found: ${sessionId}, will create`);\n }\n }\n\n // 不存在 → 创建\n if (!sessionExists) {\n return this.createEntry(qualifier, extSessionId);\n }\n\n // 存在 → 直接连接 + load\n const client = this.createClient();\n await withClientMetrics({\n callerMethod: \"connect\",\n calleeService: \"cloudagent-acp\",\n calleeMethod: \"connect\",\n }, () => client.connect());\n await withClientMetrics({\n callerMethod: \"session\",\n calleeService: \"cloudagent-acp\",\n calleeMethod: \"loadSession\",\n }, () => client.loadSession(sessionId));\n\n const now = Date.now();\n const entry: PoolEntry = {\n qualifier,\n sessionId,\n client,\n status: \"active\",\n createdAt: now,\n lastActivityAt: now,\n };\n this.entries.set(qualifier, entry);\n logger.info(`[pool] restored: qualifier=${qualifier} sessionId=${sessionId} (active=${this.size})`);\n\n return entry;\n }\n\n /** 确保有容量,超限则 LRU 淘汰 */\n private async ensureCapacity(): Promise<void> {\n const activeCount = [...this.entries.values()].filter((e) => e.status === \"active\").length;\n if (activeCount >= this.config.maxConnections) {\n await this.evictLRU();\n }\n }\n\n /** LRU 淘汰最久未活跃的连接 */\n private async evictLRU(): Promise<void> {\n let oldest: PoolEntry | null = null;\n for (const entry of this.entries.values()) {\n if (entry.status !== \"active\") continue;\n if (!oldest || entry.lastActivityAt < oldest.lastActivityAt) {\n oldest = entry;\n }\n }\n if (oldest) {\n poolEvictTotal.add(1);\n this.config.logger.info(\n `[pool] evicting LRU: qualifier=${oldest.qualifier} idle=${Date.now() - oldest.lastActivityAt}ms`,\n );\n if (this.config.preserveOnEvict) {\n this.softClose(oldest.qualifier);\n } else {\n await this.close(oldest.qualifier);\n }\n }\n }\n\n /** Soft-close:关闭 SSE 连接但保留服务端 session */\n private softClose(qualifier: string): void {\n const entry = this.entries.get(qualifier);\n if (!entry) return;\n this.config.logger.info(\n `[pool] soft-close: qualifier=${qualifier} sessionId=${entry.sessionId}`,\n );\n entry.client.close().catch(() => {});\n this.evicted.set(qualifier, entry.sessionId);\n this.entries.delete(qualifier);\n }\n\n /** 创建 AcpClient 实例(不连接) */\n private createClient(): AcpClient {\n return new AcpClient({\n endpoint: this.config.acpEndpoint,\n authToken: this.config.acpToken,\n maxRetries: this.config.acpConnectRetries,\n retryIntervalMs: this.config.acpRetryIntervalMs,\n eventTimeoutMs: this.config.eventTimeoutMs,\n extraMcpServers: this.config.mcpServers,\n logger: this.config.logger,\n });\n }\n\n // ─── 定时清理 ───\n\n private startCleanup(): void {\n if (this.cleanupTimer) return;\n this.cleanupTimer = setInterval(() => {\n void this.runCleanup();\n }, this.config.cleanupIntervalMs);\n }\n\n private stopCleanup(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n private async runCleanup(): Promise<void> {\n if (this.cleaning) return;\n this.cleaning = true;\n\n try {\n const now = Date.now();\n const expired: string[] = [];\n\n for (const [qualifier, entry] of this.entries) {\n if (\n entry.status === \"active\" &&\n now - entry.lastActivityAt > this.config.idleTimeoutMs\n ) {\n expired.push(qualifier);\n }\n }\n\n if (expired.length > 0) {\n this.config.logger.info(\n `[pool] cleanup: ${expired.length} idle connections (preserve=${this.config.preserveOnEvict})`,\n );\n if (this.config.preserveOnEvict) {\n for (const q of expired) {\n this.softClose(q);\n }\n } else {\n await Promise.allSettled(expired.map((q) => this.close(q)));\n }\n }\n } finally {\n this.cleaning = false;\n }\n }\n}\n","/**\n * CloudAgent ACP Backend — 通过 ACP 协议与 CloudAgent 沙箱交互\n *\n * 基于 AcpConnectionPool 实现多用户并发:\n * - 每个 qualifier(用户/群)独立 ACP 连接 + Session\n * - LRU 淘汰 + 空闲清理\n * - 断线自动恢复\n * - MCP Server 注入\n */\n\nimport type { ReplyBackend, ChatParams, ChatChunk, ResourceAttachment } from \"./types.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport type { PromptBlock, AcpMode } from \"../cloudagent/acp-client.js\";\nimport { AcpConnectionPool, type ConnectionPoolConfig } from \"../cloudagent/connection-pool.js\";\nimport { createSandbox, getRuntime, waitForRunning } from \"../cloudagent/sandbox.js\";\nimport type { BotConfig } from \"../config/schema.js\";\nimport type { McpServer } from \"@agentclientprotocol/sdk\";\nimport { clientStartedTotal, clientHandledTotal, clientHandledSeconds, toolCallsTotal, acpTtfbSeconds, chatRetryTotal } from \"../telemetry/metrics.js\";\nimport { METRIC_ATTRS } from \"../telemetry/constants.js\";\nimport { trace, SpanKind, SpanStatusCode } from \"@opentelemetry/api\";\n\nconst tracer = trace.getTracer(\"qqbot-cli\");\n\nexport interface CloudAgentBackendOptions {\n config: NonNullable<BotConfig[\"backend\"][\"cloudagent\"]>;\n appId: string;\n logger: Logger;\n /** MCP Server 配置(透传给每个 ACP 连接) */\n extraMcpServers?: McpServer[];\n}\n\nexport class CloudAgentBackend implements ReplyBackend {\n readonly name = \"cloudagent\";\n private opts: CloudAgentBackendOptions;\n private pool: AcpConnectionPool | null = null;\n private runtimeId: string | null = null;\n private acpEndpoint: string | null = null;\n private acpToken: string | null = null;\n\n constructor(opts: CloudAgentBackendOptions) {\n this.opts = opts;\n }\n\n async init(): Promise<void> {\n const { config, logger } = this.opts;\n logger.info(`[cloudagent] 初始化: endpoint=${config.endpoint} sandbox.mode=${config.sandbox.mode}`);\n\n if (config.sandbox.mode === \"direct\") {\n if (!config.sandbox.acpEndpoint) {\n throw new Error(\"sandbox.mode=direct 时,sandbox.acpEndpoint 必填\");\n }\n this.acpEndpoint = config.sandbox.acpEndpoint;\n this.acpToken = config.sandbox.acpToken ?? config.apiKey ?? \"\";\n logger.info(`[cloudagent] 直连 ACP: ${this.acpEndpoint}`);\n } else if (config.sandbox.mode === \"manual\" && config.sandbox.runtimeId) {\n if (!config.apiKey) {\n throw new Error(\"sandbox.mode=manual 时,backend.cloudagent.apiKey 必填\");\n }\n this.runtimeId = config.sandbox.runtimeId;\n const rt = await getRuntime(config.sandbox.runtimeId, config.apiKey, config.endpoint, logger);\n this.acpEndpoint = rt.links.acpLink.url;\n this.acpToken = rt.links.acpLink.token;\n logger.info(`[cloudagent] 使用已有 runtime: ${this.runtimeId}`);\n } else {\n if (!config.apiKey) {\n throw new Error(\"sandbox.mode=auto 时,backend.cloudagent.apiKey 必填\");\n }\n const runtimeName = config.sandbox.runtimeName ?? `qqbot-${this.opts.appId}-${Date.now()}`;\n logger.info(`[cloudagent] 创建沙箱: ${runtimeName}`);\n\n const rt = await createSandbox({\n runtimeName,\n apiKey: config.apiKey,\n endpoint: config.endpoint,\n systemPrompt: config.manifest.systemPrompt,\n logger,\n });\n\n this.runtimeId = rt.id;\n logger.info(`[cloudagent] 沙箱已创建: id=${rt.id} status=${rt.status}`);\n\n if (rt.status !== \"RUNNING\") {\n logger.info(`[cloudagent] 等待 Runtime RUNNING...`);\n const ready = await waitForRunning(rt.id, config.apiKey, config.endpoint, { logger });\n this.acpEndpoint = ready.links.acpLink.url;\n this.acpToken = ready.links.acpLink.token;\n } else {\n this.acpEndpoint = rt.links.acpLink.url;\n this.acpToken = rt.links.acpLink.token;\n }\n }\n\n // 创建连接池\n const poolConfig: ConnectionPoolConfig = {\n maxConnections: config.session.maxConnections,\n enableCleanup: config.session.enableCleanup,\n idleTimeoutMs: config.session.idleTimeoutMs,\n cleanupIntervalMs: config.session.cleanupIntervalMs,\n preserveOnEvict: config.session.preserveOnEvict,\n acpEndpoint: this.acpEndpoint!,\n acpToken: this.acpToken!,\n acpConnectRetries: config.acp.maxRetries,\n acpRetryIntervalMs: config.acp.retryIntervalMs,\n eventTimeoutMs: config.acp.eventTimeoutMs,\n mcpServers: this.opts.extraMcpServers ?? [],\n controlPlane: this.runtimeId && config.apiKey\n ? { runtimeId: this.runtimeId, apiKey: config.apiKey, endpoint: config.endpoint }\n : undefined,\n logger,\n };\n this.pool = new AcpConnectionPool(poolConfig);\n logger.info(`[cloudagent] 连接池就绪 (max=${poolConfig.maxConnections})`);\n }\n\n async getOrCreateSession(qualifier: string, extSessionId?: string): Promise<string> {\n const { sessionId } = await this.pool!.getOrCreate(qualifier, extSessionId);\n return sessionId;\n }\n\n async *chat(params: ChatParams): AsyncIterableIterator<ChatChunk> {\n const scopeType = params.qualifier.startsWith(\"group\") ? \"group\" : \"c2c\";\n const hasAttachments = (params.attachments?.length ?? 0) > 0;\n\n const clientAttrs = {\n [METRIC_ATTRS.CALLER_SERVICE]: \"qqbot-cli\",\n [METRIC_ATTRS.CALLER_METHOD]: \"chat\",\n [METRIC_ATTRS.CALLER_SERVER]: \"qqbot-cli\",\n [METRIC_ATTRS.CALLEE_SERVICE]: \"cloudagent-acp\",\n [METRIC_ATTRS.CALLEE_METHOD]: \"prompt\",\n [METRIC_ATTRS.CALLEE_SERVER]: \"cloudagent-acp\",\n [METRIC_ATTRS.CODE]: 0,\n [METRIC_ATTRS.CODE_TYPE]: \"success\",\n [METRIC_ATTRS.USER_EXT1]: scopeType,\n [METRIC_ATTRS.USER_EXT2]: hasAttachments ? \"multimodal\" : \"text\",\n };\n\n const span = tracer.startSpan(\"cloudagent-acp/prompt\", {\n kind: SpanKind.CLIENT,\n attributes: {\n \"rpc.system\": \"acp\",\n \"rpc.service\": \"cloudagent-acp\",\n \"rpc.method\": \"prompt\",\n \"caller.method\": \"chat\",\n \"msg.scope\": scopeType,\n \"msg.input_type\": hasAttachments ? \"multimodal\" : \"text\",\n },\n });\n\n clientStartedTotal.add(1, clientAttrs);\n const startTime = Date.now();\n let hasError = false;\n let firstChunkReceived = false;\n\n try {\n for await (const chunk of this.chatWithRetry(params, 1)) {\n if (!firstChunkReceived) {\n firstChunkReceived = true;\n acpTtfbSeconds.record((Date.now() - startTime) / 1000, { scope: scopeType });\n span.addEvent(\"first_chunk\", { ttfb_ms: Date.now() - startTime });\n }\n if (chunk.type === \"tool\" && chunk.status === \"in_progress\") {\n toolCallsTotal.add(1, { \"tool.kind\": chunk.kind ?? \"other\", scope: scopeType });\n }\n yield chunk;\n }\n } catch (err) {\n hasError = true;\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err instanceof Error ? err.message : String(err),\n });\n span.recordException(err instanceof Error ? err : new Error(String(err)));\n clientHandledTotal.add(1, {\n ...clientAttrs,\n [METRIC_ATTRS.CODE]: 1,\n [METRIC_ATTRS.CODE_TYPE]: \"error\",\n });\n throw err;\n } finally {\n if (!hasError) {\n span.setStatus({ code: SpanStatusCode.OK });\n clientHandledTotal.add(1, clientAttrs);\n }\n span.end();\n clientHandledSeconds.record((Date.now() - startTime) / 1000, clientAttrs);\n }\n }\n\n private async *chatWithRetry(\n params: ChatParams,\n retriesLeft: number,\n ): AsyncIterableIterator<ChatChunk> {\n const { qualifier, text, attachments } = params;\n try {\n const { client, sessionId } = await this.pool!.getOrCreate(qualifier);\n const blocks = this.buildPromptBlocks(qualifier, text, attachments);\n this.opts.logger.debug?.(`[acp:prompt] session=${sessionId} ${JSON.stringify(blocks)}`);\n\n for await (const event of client.promptStream(sessionId, blocks)) {\n switch (event.type) {\n case \"agent_message_chunk\":\n yield { type: \"text\", content: event.text };\n break;\n case \"agent_thought_chunk\":\n yield { type: \"thought\", content: event.text };\n break;\n case \"tool_call\": {\n const kind = event.kind ?? \"other\";\n const title = event.title ?? \"\";\n if (event.status === \"in_progress\" || event.status === \"completed\" || event.status === \"failed\") {\n yield {\n type: \"tool\",\n content: title,\n status: event.status,\n toolCallId: event.toolCallId,\n kind,\n detail: summarizeRawInput(kind, title, event.rawInput),\n };\n }\n break;\n }\n case \"tool_call_update\":\n if (event.status === \"completed\" || event.status === \"failed\") {\n yield {\n type: \"tool\",\n content: \"\",\n status: event.status,\n toolCallId: event.toolCallId,\n };\n }\n break;\n case \"plan\":\n yield { type: \"plan\", content: this.formatPlan(event.entries) };\n break;\n case \"done\": {\n // 连接错误类 stopReason → throw 触发 chatWithRetry 的重试逻辑\n if (event.stopReason === \"error\" && this.isConnectionError(new Error(event.text))) {\n throw new Error(event.text);\n }\n yield { type: \"done\", content: \"\", stopReason: event.stopReason };\n break;\n }\n }\n }\n this.pool!.touch(qualifier);\n } catch (err) {\n if (retriesLeft > 0 && this.isConnectionError(err)) {\n chatRetryTotal.add(1, { result: \"retry\" });\n this.opts.logger.warn(\n `[cloudagent] 连接错误,恢复后重试: ${err instanceof Error ? err.message : String(err)}`,\n );\n const { sessionId: newSessionId } = await this.pool!.restore(qualifier);\n yield* this.chatWithRetry(\n { ...params, sessionId: newSessionId },\n retriesLeft - 1,\n );\n } else {\n if (retriesLeft <= 0 && this.isConnectionError(err)) {\n chatRetryTotal.add(1, { result: \"exhausted\" });\n }\n throw err;\n }\n }\n }\n\n private isConnectionError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return msg.includes(\"agent not alive\")\n || msg.includes(\"connection closed\")\n || msg.includes(\"ACP connection closed\")\n || msg.includes(\"Transport closed\")\n || msg.includes(\"session not bound\")\n || msg.includes(\"session not found\")\n || msg.includes(\"session expired\");\n }\n\n /** 取消当前 prompt */\n cancel(qualifier: string): void {\n const entry = this.pool?.get(qualifier);\n if (entry) {\n entry.client.cancelPrompt(entry.sessionId);\n }\n }\n\n /** 切换权限模式 */\n async setMode(qualifier: string, mode: AcpMode): Promise<void> {\n const entry = this.pool?.get(qualifier);\n if (entry) {\n await entry.client.setMode(entry.sessionId, mode);\n }\n }\n\n /** 切换模型 */\n async setModel(qualifier: string, modelId: string): Promise<void> {\n const entry = this.pool?.get(qualifier);\n if (entry) {\n await entry.client.setModel(entry.sessionId, modelId);\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.pool) {\n await this.pool.closeAll();\n this.pool = null;\n }\n }\n\n private formatPlan(entries?: unknown[]): string {\n if (!entries || entries.length === 0) return \"\";\n return entries\n .map((e: any, i) => `${i + 1}. ${e.content ?? e.title ?? `step ${i + 1}`}`)\n .join(\"\\n\");\n }\n\n private buildPromptBlocks(\n _qualifier: string,\n text: string,\n attachments?: ResourceAttachment[],\n ): PromptBlock[] {\n const blocks: PromptBlock[] = [];\n\n if (text) {\n blocks.push({ type: \"text\", text });\n }\n if (attachments) {\n for (const att of attachments) {\n blocks.push({\n type: \"resource_link\",\n uri: att.url,\n name: att.name,\n mimeType: att.mimeType,\n ...(att.size ? { size: att.size } : {}),\n });\n }\n }\n if (blocks.length === 0) {\n blocks.push({ type: \"text\", text: \"(空消息)\" });\n }\n return blocks;\n }\n}\n\n// ============ Helpers ============\n\nfunction summarizeRawInput(\n kind: string,\n title: string,\n rawInput?: Record<string, unknown>,\n): string {\n if (!rawInput) return \"\";\n\n switch (kind) {\n case \"search\":\n return str(rawInput.query ?? rawInput.pattern ?? rawInput.regex);\n case \"read\":\n return str(rawInput.filePath ?? rawInput.path ?? rawInput.file);\n case \"edit\":\n case \"write\":\n return str(rawInput.filePath ?? rawInput.path ?? rawInput.file);\n case \"delete\":\n return str(rawInput.filePath ?? rawInput.path);\n case \"fetch\":\n return str(rawInput.url ?? rawInput.uri);\n case \"execute\":\n return str(rawInput.command ?? rawInput.cmd);\n case \"think\":\n return \"\";\n default:\n break;\n }\n\n const s = rawInput.skill ?? rawInput.command ?? rawInput.tool;\n const args = rawInput.args ?? rawInput.arguments ?? rawInput.input;\n if (s) {\n return args ? truncate(`${s}: ${typeof args === \"string\" ? args : JSON.stringify(args)}`) : str(s);\n }\n\n for (const v of Object.values(rawInput)) {\n if (typeof v === \"string\" && v.length > 0 && v.length < 120) {\n return truncate(v);\n }\n }\n return \"\";\n}\n\nfunction str(v: unknown): string {\n return typeof v === \"string\" ? truncate(v) : \"\";\n}\n\nfunction truncate(s: string): string {\n return s;\n}\n","/**\n * MCP Server Host\n *\n * 在 qqbot-cli 进程内启动一个 HTTP+SSE MCP Server,\n * 供 CloudAgent 里的 Agent 通过 ACP mcpServers 注入后调用。\n *\n * 使用 McpServer 高级 API(推荐),通过 registerTool() 注册工具。\n * 工具注册表(TOOLS)设计思路:\n * - 每个工具的 schema + handler 写在一起\n * - 通过遍历 TOOLS 自动注册\n * - 加新工具只需在 TOOLS 对象里加一项\n */\n\nimport { McpServer as MCP } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { createServer, type Server as HttpServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { randomBytes } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\nimport { URL } from \"node:url\";\nimport { z } from \"zod\";\nimport type { Logger } from \"../utils/logger.js\";\nimport type { McpServer } from \"@agentclientprotocol/sdk\";\nimport type { QQBot, ReplyTarget } from \"@tencent/qqbot-nodejs\";\nimport { withClientMetrics } from \"../telemetry/client-interceptor.js\";\nimport { buildOpenApiTools, type OpenApiConfig } from \"./openapi-tools.js\";\n\n// ─────────── 工具上下文(按需扩展) ───────────\n\nexport interface ToolDeps {\n logger: Logger;\n /** QQBot 实例,用于发送消息/文件 */\n bot: QQBot;\n /** 文件路径前缀,拼接在工具接收到的路径之前,用于容器卷映射 */\n pathPrefix: string;\n /** 最近消息 ID 缓存(按 target key),用于 send_file 被动回复 */\n msgIdCache: MsgIdCache;\n}\n\n// ─────────── MsgId 缓存 ───────────\n\nconst MSG_ID_CACHE_SIZE = 10;\nconst MSG_ID_TTL_MS = 60 * 60 * 1000; // 1 小时有效期\nconst MSG_ID_MAX_TARGETS = 200; // 最多缓存的 target 数量\n\ninterface CachedMsgId {\n msgId: string;\n timestamp: number;\n}\n\nexport class MsgIdCache {\n private cache = new Map<string, CachedMsgId[]>();\n\n /** 记录一条消息 ID(LRU:访问即提升到最新) */\n push(targetKey: string, msgId: string): void {\n // LRU: 删除再重新插入,保持 Map 插入顺序 = 访问顺序\n const existing = this.cache.get(targetKey);\n if (existing) {\n this.cache.delete(targetKey);\n existing.push({ msgId, timestamp: Date.now() });\n if (existing.length > MSG_ID_CACHE_SIZE) {\n existing.shift();\n }\n this.cache.set(targetKey, existing);\n } else {\n this.cache.set(targetKey, [{ msgId, timestamp: Date.now() }]);\n // 淘汰最久未访问的 target\n if (this.cache.size > MSG_ID_MAX_TARGETS) {\n const oldest = this.cache.keys().next().value;\n if (oldest) this.cache.delete(oldest);\n }\n }\n }\n\n /** 获取最近的有效 msgId(未过期),过期返回 undefined */\n getLatest(targetKey: string): string | undefined {\n const list = this.cache.get(targetKey);\n if (!list || list.length === 0) return undefined;\n const now = Date.now();\n for (let i = list.length - 1; i >= 0; i--) {\n if (now - list[i].timestamp < MSG_ID_TTL_MS) {\n return list[i].msgId;\n }\n }\n return undefined;\n }\n}\n\n// ─────────── 工具定义 ───────────\n\ninterface ToolDef {\n description: string;\n inputSchema: z.ZodRawShape;\n timeoutMs: number;\n handler: (args: any, deps: ToolDeps) => Promise<unknown>;\n}\n\n// ─────────── 工具注册表:加新工具就在这里加一项 ───────────\n\nconst TOOLS: Record<string, ToolDef> = {\n send_file: {\n description:\n \"将本地文件发送给 QQ 用户或群。支持图片、视频、语音和通用文件。\",\n inputSchema: {\n file_path: z\n .string()\n .describe(\"本地文件的绝对路径,例如 /tmp/report.pdf\"),\n target: z\n .string()\n .describe(\"发送目标,格式为 scope:openid,例如 c2c:xxx 或 group:xxx\"),\n },\n timeoutMs: 120_000,\n handler: async (\n args: { file_path: string; target: string },\n deps: ToolDeps,\n ) => {\n const { bot, logger, pathPrefix, msgIdCache } = deps;\n const resolvedPath = pathPrefix\n ? join(pathPrefix, args.file_path)\n : args.file_path;\n\n // 1. 解析目标\n const [scope, targetId] = args.target.split(\":\", 2);\n if (!targetId || (scope !== \"c2c\" && scope !== \"group\")) {\n throw new Error(`target 格式错误,需要 c2c:openid 或 group:openid,收到: ${args.target}`);\n }\n // 使用缓存的 msgId 进行被动回复;无缓存则走主动消息\n const msgId = msgIdCache.getLatest(args.target);\n const target: ReplyTarget = { scope: scope as \"c2c\" | \"group\", targetId, msgId };\n logger.debug?.(`[mcp/send_file] target=${args.target} msgId=${msgId ?? \"(主动消息)\"}`);\n\n // 2. 校验文件\n if (!existsSync(resolvedPath)) {\n throw new Error(`文件不存在: ${resolvedPath}`);\n }\n const fileStat = await stat(resolvedPath);\n if (!fileStat.isFile()) {\n throw new Error(`路径不是普通文件: ${resolvedPath}`);\n }\n\n const fileName = basename(resolvedPath);\n const ext = resolvedPath.slice(resolvedPath.lastIndexOf(\".\")).toLowerCase();\n const sendMethod = IMAGE_EXTS.has(ext)\n ? \"image\"\n : VIDEO_EXTS.has(ext)\n ? \"video\"\n : VOICE_EXTS.has(ext)\n ? \"voice\"\n : \"file\";\n\n logger.info(\n `[mcp/send_file] 发送${sendMethod}: ${fileName} (${fileStat.size} bytes) → ${target.scope}:${target.targetId}`,\n );\n\n // 3. 根据文件类型选择发送方式\n const source = { localPath: resolvedPath };\n const result = await withClientMetrics({\n callerMethod: \"mcp_send_file\",\n calleeService: \"qq-platform\",\n calleeMethod: `send${sendMethod.charAt(0).toUpperCase()}${sendMethod.slice(1)}`,\n }, async () => {\n return sendMethod === \"image\"\n ? await bot.sendImage(target, source)\n : sendMethod === \"video\"\n ? await bot.sendVideo(target, source)\n : sendMethod === \"voice\"\n ? await bot.sendVoice(target, source)\n : await bot.sendFile(target, source, { fileName });\n });\n\n return {\n success: true,\n fileName,\n fileSize: fileStat.size,\n target: `${target.scope}:${target.targetId}`,\n fileUuid: result.upload.file_uuid,\n messageId: result.message?.id,\n };\n },\n },\n};\n\n// ─────────── MCP Server Host ───────────\n\n/**\n * MCP Server 同时支持两种 transport(按 MCP 2025-03-26 规范):\n *\n * 1. Streamable HTTP (现代) POST /mcp + GET /mcp + DELETE /mcp\n * - 每个 initialize 请求创建独立的 transport + session\n * - 通过 Mcp-Session-Id 头路由后续请求\n *\n * 2. SSE (旧版向后兼容) GET /sse + POST /messages\n * - 兼容 2024-11-05 规范的客户端(如部分 IDE 插件)\n */\nexport class MCPServerHost {\n private http?: HttpServer;\n private deps!: ToolDeps;\n /** Streamable HTTP sessions: sessionId → transport */\n private sessions = new Map<string, StreamableHTTPServerTransport>();\n /** Legacy SSE sessions: sessionId → transport */\n private sseSessions = new Map<string, SSEServerTransport>();\n /** 动态生成的 OpenAPI tools(从配置加载) */\n private dynamicTools: Record<string, ToolDef> = {};\n port = 0;\n private host = \"127.0.0.1\";\n\n async start(deps: ToolDeps, listenPort = 0, listenHost = \"127.0.0.1\", openApiConfig?: OpenApiConfig): Promise<void> {\n this.deps = deps;\n this.host = listenHost;\n\n // 根据 openapi 配置动态生成 tools\n if (openApiConfig?.apis?.length) {\n this.dynamicTools = buildOpenApiTools(openApiConfig);\n deps.logger.info(`[mcp] 已加载 ${Object.keys(this.dynamicTools).length} 个 OpenAPI tools: ${Object.keys(this.dynamicTools).join(\", \")}`);\n }\n\n this.http = createServer(async (req, res) => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const path = url.pathname;\n\n try {\n if (path === \"/mcp\") {\n await this.handleStreamableHTTP(req, res);\n } else if (path === \"/sse\") {\n await this.handleSSEConnect(req, res);\n } else if (path === \"/messages\") {\n await this.handleSSEMessage(req, res);\n } else {\n res.writeHead(404).end(\"Not Found\");\n }\n } catch (err) {\n deps.logger.error(`[mcp] request error: ${err instanceof Error ? err.message : String(err)}`);\n if (!res.headersSent) {\n res.writeHead(500).end(\"Internal Server Error\");\n }\n }\n });\n\n await new Promise<void>((resolve) =>\n this.http!.listen(listenPort, listenHost, () => resolve()),\n );\n this.port = (this.http!.address() as any).port;\n deps.logger.info(`[mcp] listening ${listenHost}:${this.port}`);\n }\n\n // ── Streamable HTTP:每个 initialize 创建新 session ──\n\n private async handleStreamableHTTP(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n\n if (sessionId && this.sessions.has(sessionId)) {\n // 已有 session:路由到对应 transport\n const transport = this.sessions.get(sessionId)!;\n await transport.handleRequest(req, res);\n return;\n }\n\n if (req.method === \"POST\") {\n // 可能是 initialize 请求 → 创建新 transport\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => randomBytes(16).toString(\"hex\"),\n onsessioninitialized: (id) => {\n this.sessions.set(id, transport);\n this.deps.logger.info(`[mcp] streamable session created: ${id}`);\n },\n });\n\n transport.onclose = () => {\n const id = transport.sessionId;\n if (id) {\n this.sessions.delete(id);\n this.deps.logger.info(`[mcp] streamable session closed: ${id}`);\n }\n };\n\n const mcp = this.createMcpServer();\n await mcp.connect(transport);\n await transport.handleRequest(req, res);\n return;\n }\n\n // 无 session 的 GET/DELETE → 400\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Bad Request: No valid session. Send an initialize request first.\" },\n id: null,\n }));\n }\n\n // ── Legacy SSE:GET /sse 建立流,POST /messages 发消息 ──\n\n private async handleSSEConnect(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (req.method !== \"GET\") {\n res.writeHead(405).end(\"Method Not Allowed\");\n return;\n }\n\n const transport = new SSEServerTransport(\"/messages\", res);\n const sessionId = transport.sessionId;\n this.sseSessions.set(sessionId, transport);\n this.deps.logger.info(`[mcp] SSE session created: ${sessionId}`);\n\n transport.onclose = () => {\n this.sseSessions.delete(sessionId);\n this.deps.logger.info(`[mcp] SSE session closed: ${sessionId}`);\n };\n\n const mcp = this.createMcpServer();\n await mcp.connect(transport);\n }\n\n private async handleSSEMessage(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (req.method !== \"POST\") {\n res.writeHead(405).end(\"Method Not Allowed\");\n return;\n }\n\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const sessionId = url.searchParams.get(\"sessionId\");\n if (!sessionId || !this.sseSessions.has(sessionId)) {\n res.writeHead(400).end(\"Invalid or missing sessionId\");\n return;\n }\n\n const transport = this.sseSessions.get(sessionId)!;\n await transport.handlePostMessage(req, res);\n }\n\n // ── 创建带工具注册的 MCP Server 实例 ──\n\n private createMcpServer(): MCP {\n const mcp = new MCP({ name: \"qqbot-tools\", version: \"0.1.0\" });\n\n // 合并静态工具 + 动态 OpenAPI 工具\n const allTools: Record<string, ToolDef> = { ...TOOLS, ...this.dynamicTools };\n\n for (const [name, tool] of Object.entries(allTools)) {\n const toolDeps = this.deps;\n const toolDef = tool;\n\n mcp.registerTool(\n name,\n {\n description: tool.description,\n inputSchema: tool.inputSchema,\n },\n async (args) => {\n const t0 = Date.now();\n try {\n const result = await withTimeout(\n toolDef.handler(args, toolDeps),\n toolDef.timeoutMs,\n );\n toolDeps.logger.info(`[mcp] ${name} ok ${Date.now() - t0}ms`);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\n };\n } catch (e: any) {\n toolDeps.logger.error(`[mcp] ${name} fail ${Date.now() - t0}ms: ${e?.message ?? e}`);\n return {\n isError: true as const,\n content: [{ type: \"text\" as const, text: e?.message ?? String(e) }],\n };\n }\n },\n );\n }\n\n return mcp;\n }\n\n /** 给 ACP 用的 mcpServers 配置项 */\n getAcpEntry(): McpServer {\n // 0.0.0.0 是 listen 通配,ACP 回调需要具体地址\n const callbackHost = this.host === \"0.0.0.0\" ? \"127.0.0.1\" : this.host;\n return {\n type: \"http\",\n name: \"qqbot-tools\",\n url: `http://${callbackHost}:${this.port}/mcp`,\n headers: [],\n };\n }\n\n async stop(): Promise<void> {\n for (const transport of this.sessions.values()) {\n await transport.close?.().catch(() => {});\n }\n for (const transport of this.sseSessions.values()) {\n await transport.close?.().catch(() => {});\n }\n this.sessions.clear();\n this.sseSessions.clear();\n await new Promise<void>((resolve) =>\n this.http?.close(() => resolve()) ?? resolve(),\n );\n }\n}\n\n// ─────────── 工具函数 ───────────\n\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`timeout ${ms}ms`)), ms);\n p.then(\n (v) => { clearTimeout(timer); resolve(v); },\n (e) => { clearTimeout(timer); reject(e); },\n );\n });\n}\n\nconst IMAGE_EXTS = new Set([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\"]);\nconst VIDEO_EXTS = new Set([\".mp4\", \".mov\", \".avi\", \".mkv\", \".webm\"]);\nconst VOICE_EXTS = new Set([\".mp3\", \".wav\", \".ogg\", \".aac\", \".silk\", \".amr\"]);\n","/**\n * OpenAPI MCP Tools\n *\n * 根据 bot.yaml 中的 openapi.apis[] 配置,动态生成 MCP 工具。\n * 每个接口声明自动变为一个 MCP Tool,AI 通过 desc 字段理解何时调用。\n *\n * 所有接口统一通过 bot.api 调用 QQ 开放平台 REST API(含 /workbuddy/proxy 等),\n * SDK 自动管理 Token 注入、刷新和错误处理。\n */\n\nimport { z } from \"zod\";\nimport type { ToolDeps } from \"./server.js\";\nimport { withClientMetrics } from \"../telemetry/client-interceptor.js\";\n\n// ─────────── 配置类型定义 ───────────\n\nexport interface OpenApiParamConfig {\n /** 参数名(MCP tool 展示给 AI 的名称) */\n name: string;\n /** 参数类型 */\n type: 'string' | 'number' | 'boolean' | 'string[]' | 'number[]';\n /** 参数描述(给 AI 看,用于理解参数含义和填充策略) */\n desc: string;\n /** 是否必填,默认 false */\n required?: boolean;\n /** 默认值 */\n default?: unknown;\n}\n\nexport interface OpenApiItemConfig {\n /** 工具名称,生成的 MCP tool name 为 \"openapi_<name>\" */\n name: string;\n /** 工具描述(给 AI 看),应包含:功能说明 + 触发场景关键词 */\n desc: string;\n /** HTTP 方法,默认 POST */\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n /** API 路径(开平已注册的接口路径) */\n path: string;\n /** 固定请求体参数(自动注入,AI 不可见) */\n fixed_body?: Record<string, unknown>;\n /** AI 可填写的动态参数列表 */\n params?: OpenApiParamConfig[];\n /** 参数名映射:tool param name → 实际 body/query field name */\n param_mapping?: Record<string, string>;\n}\n\nexport interface OpenApiConfig {\n /** 全局超时(ms),默认 10000 */\n timeoutMs?: number;\n /** 接口声明列表 */\n apis: OpenApiItemConfig[];\n}\n\n// ─────────── ToolDef 类型(与 server.ts 保持一致) ───────────\n\ninterface ToolDef {\n description: string;\n inputSchema: z.ZodRawShape;\n timeoutMs: number;\n handler: (args: any, deps: ToolDeps) => Promise<unknown>;\n}\n\n// ─────────── 动态构建 Zod Schema ───────────\n\nfunction buildParamSchema(param: OpenApiParamConfig): z.ZodTypeAny {\n let schema: z.ZodTypeAny;\n\n switch (param.type) {\n case 'string':\n schema = z.string();\n break;\n case 'number':\n schema = z.number();\n break;\n case 'boolean':\n schema = z.boolean();\n break;\n case 'string[]':\n schema = z.array(z.string());\n break;\n case 'number[]':\n schema = z.array(z.number());\n break;\n default:\n schema = z.string();\n }\n\n schema = schema.describe(param.desc);\n\n if (!param.required) {\n schema = schema.optional();\n }\n\n return schema;\n}\n\nfunction buildInputSchema(params: OpenApiParamConfig[]): z.ZodRawShape {\n const shape: z.ZodRawShape = {};\n for (const param of params) {\n shape[param.name] = buildParamSchema(param);\n }\n return shape;\n}\n\n// ─────────── 构建请求体 ───────────\n\nfunction buildRequestBody(\n args: Record<string, unknown>,\n config: OpenApiItemConfig,\n): Record<string, unknown> {\n const body: Record<string, unknown> = { ...config.fixed_body };\n const params = config.params ?? [];\n const mapping = config.param_mapping ?? {};\n\n for (const param of params) {\n const value = args[param.name] ?? param.default;\n if (value === undefined) continue;\n\n const fieldName = mapping[param.name] ?? param.name;\n body[fieldName] = value;\n }\n\n return body;\n}\n\n// ─────────── 主入口:根据配置生成 MCP ToolDef 列表 ───────────\n\n/**\n * 根据 openapi 配置动态构建 MCP 工具定义。\n * 每条 api 配置生成一个 tool,tool name 格式为 \"openapi_<name>\"。\n * 所有接口统一通过 bot.api 调用开平 REST API。\n */\nexport function buildOpenApiTools(config: OpenApiConfig): Record<string, ToolDef> {\n const tools: Record<string, ToolDef> = {};\n const globalTimeout = config.timeoutMs ?? 10_000;\n\n for (const api of config.apis) {\n const toolName = api.name;\n const method = (api.method ?? 'POST').toUpperCase();\n\n tools[toolName] = {\n description: api.desc,\n inputSchema: buildInputSchema(api.params ?? []),\n timeoutMs: globalTimeout,\n\n handler: async (args: Record<string, unknown>, deps: ToolDeps) => {\n const { bot, logger } = deps;\n const body = buildRequestBody(args, api);\n\n logger.info(`[mcp/openapi] ${toolName} → ${method} ${api.path} body=${JSON.stringify(body)}`);\n\n return withClientMetrics({\n callerMethod: `mcp_${toolName}`,\n calleeService: 'qq-openapi',\n calleeMethod: api.path,\n }, async () => {\n switch (method) {\n case 'GET': {\n const query: Record<string, string | number | boolean> = {};\n for (const [k, v] of Object.entries(body)) {\n if (v !== undefined && v !== null && typeof v !== 'object') {\n query[k] = v as string | number | boolean;\n }\n }\n return bot.api.get(api.path, Object.keys(query).length > 0 ? query : undefined);\n }\n case 'POST':\n return bot.api.post(api.path, Object.keys(body).length > 0 ? body : undefined);\n case 'PUT':\n return bot.api.put(api.path, Object.keys(body).length > 0 ? body : undefined);\n case 'PATCH':\n return bot.api.patch(api.path, Object.keys(body).length > 0 ? body : undefined);\n case 'DELETE':\n return bot.api.delete(api.path);\n default:\n throw new Error(`不支持的 HTTP 方法: ${method}`);\n }\n });\n },\n };\n }\n\n return tools;\n}\n","/**\n * 斜杠指令注册中心\n *\n * - 通过 `createSlashMiddleware(...)` 一次性产出 SDK 中间件,挂载到 QQBot。\n * - 新增指令时,直接往 `buildCommands(...)` 返回的数组里追加 `SlashCommand` 即可;\n * 命令多了再按业务拆到 `commands/<name>.ts`。\n */\n\nimport {\n slashCommand,\n type Middleware,\n type SlashCommand,\n} from \"@tencent/qqbot-nodejs\";\n\nimport type { ReplyBackend } from \"../backend/types.js\";\nimport { expandDisplayPreset, type BotConfig } from \"../config/schema.js\";\nimport type { Logger } from \"../utils/logger.js\";\nimport { slashCommandTotal } from \"../telemetry/metrics.js\";\n\nexport interface SlashContext {\n backend: ReplyBackend;\n logger: Logger;\n /** 获取当前运行配置 */\n getConfig: () => BotConfig;\n /** 更新配置(热更新) */\n updateConfig: (patch: Partial<PatchableConfig>) => void;\n}\n\n/** 可通过指令修改的配置子集 */\nexport interface PatchableConfig {\n display: BotConfig[\"message\"][\"display\"];\n logLevel: BotConfig[\"log\"][\"level\"];\n streamingC2c: boolean;\n streamingThrottleMs: number;\n}\n\nexport interface CreateSlashMiddlewareOptions {\n prefixes: string[];\n /** 指令白名单(用户 OpenID)。为空则所有人可用。 */\n allowFrom: string[];\n ctx: SlashContext;\n}\n\nexport function createSlashMiddleware(opts: CreateSlashMiddlewareOptions): Middleware {\n const slash = slashCommand({\n prefixes: opts.prefixes,\n autoHelp: false,\n allowFrom: opts.allowFrom,\n });\n\n for (const cmd of buildCommands(opts.ctx, slash.list)) {\n const originalHandler = cmd.handler;\n cmd.handler = (ctx) => {\n slashCommandTotal.add(1, { command: cmd.name });\n return originalHandler(ctx);\n };\n slash.register(cmd);\n }\n\n return slash.middleware;\n}\n\nconst DISPLAY_PRESETS = [\"full\", \"compact\", \"minimal\", \"text-only\"] as const;\n\nfunction buildCommands(\n ctx: SlashContext,\n listCommands: () => SlashCommand[],\n): SlashCommand[] {\n return [\n {\n name: \"bot-help\",\n description: \"QQ Bot 帮助指令\",\n scope: \"c2c\",\n usage: [\n `/bot-help`,\n ``,\n `查看所有可用的内置命令及其简要说明。`,\n ].join(\"\\n\"),\n handler: ({ message }) => {\n const msgKind = message.kind;\n const isC2C = msgKind === \"c2c\";\n const isGroup = msgKind === \"group\";\n\n const lines = [`### 🤖 QQ Bot 帮助指令`, ``];\n for (const cmd of listCommands()) {\n if (cmd.hidden) continue;\n const cmdScope = cmd.scope ?? \"all\";\n if (cmdScope === \"c2c\" && !isC2C) continue;\n if (cmdScope === \"group\" && !isGroup) continue;\n const name = Array.isArray(cmd.name) ? cmd.name[0] : cmd.name;\n const desc = cmd.description ?? \"\";\n lines.push(`<qqbot-cmd-input text=\"/${name}\" show=\"/${name}\"/> ${desc}`);\n }\n return lines.join(\"\\n\");\n },\n },\n {\n name: \"bot-me\",\n description: \"查看当前用户的 OpenID\",\n scope: \"c2c\",\n usage: [\n `/bot-me`,\n ``,\n `显示当前用户的 OpenID。`,\n ].join(\"\\n\"),\n handler: ({ message }) => {\n const lines = [`👤 **${message.senderId}**`];\n if (message.groupOpenid) {\n lines.push(`👥 群: **${message.groupOpenid}**`);\n }\n return lines.join(\"\\n\");\n },\n },\n {\n name: \"bot-ping\",\n description: \"测试 Agent 服务与 QQ 间网络延迟\",\n scope: \"c2c\",\n usage: [\n `/bot-ping`,\n ``,\n `测试 Agent 服务与 QQ 服务器之间的网络延迟。`,\n `返回网络传输耗时和处理耗时。`,\n ].join(\"\\n\"),\n handler: (ctx) => {\n const now = Date.now();\n const eventTime = new Date(ctx.message.timestamp).getTime();\n if (Number.isNaN(eventTime)) {\n return `✅ pong!`;\n }\n const totalMs = now - eventTime;\n const qqToSdk = ctx.receivedAt - eventTime;\n const sdkProcess = now - ctx.receivedAt;\n return [\n `✅ pong!`,\n ``,\n `⏱ 延迟:${totalMs}ms`,\n ` ├ 网络传输:${qqToSdk}ms`,\n ` └ 处理耗时:${sdkProcess}ms`,\n ].join(\"\\n\");\n },\n },\n {\n name: \"bot-msg-mode\",\n description: \"切换消息展示模式\",\n scope: \"c2c\",\n usage: [\n `/bot-msg-mode <mode> 切换展示模式`,\n `/bot-msg-mode 查看当前模式`,\n ``,\n `可选模式: ${DISPLAY_PRESETS.join(\" | \")}`,\n ].join(\"\\n\"),\n handler: ({ command }) => {\n const preset = command.args[0];\n if (!preset) {\n const cur = ctx.getConfig().message.display.preset;\n return [\n `当前模式:**${cur}**`,\n ``,\n `<qqbot-cmd-input text=\"/bot-msg-mode full\" show=\"full\"/> 🔍 详细模式 — 展示 AI 的每一步思考和操作过程`,\n `<qqbot-cmd-input text=\"/bot-msg-mode compact\" show=\"compact\"/> 📋 普通模式 — 只展示关键操作和结果`,\n `<qqbot-cmd-input text=\"/bot-msg-mode minimal\" show=\"minimal\"/> 💬 简洁模式 — 只显示操作名称,内容折叠`,\n `<qqbot-cmd-input text=\"/bot-msg-mode text-only\" show=\"text-only\"/> ✨ 纯净模式 — 只看对话,隐藏所有过程`,\n ].join(\"\\n\");\n }\n if (!DISPLAY_PRESETS.includes(preset as any)) {\n return [\n `❌ 无效的模式: ${preset}`,\n ``,\n `可选: ${DISPLAY_PRESETS.join(\" | \")}`,\n ].join(\"\\n\");\n }\n ctx.updateConfig({ display: expandDisplayPreset(preset) });\n return `✅ 已切换为 **${preset}** 模式`;\n },\n },\n {\n name: \"bot-streaming\",\n description: \"开关流式消息\",\n scope: \"c2c\",\n usage: [\n `/bot-streaming on 开启流式消息`,\n `/bot-streaming off 关闭流式消息`,\n `/bot-streaming 查看当前状态`,\n ``,\n `开启后,AI 回复以流式形式逐步显示。`,\n ].join(\"\\n\"),\n handler: ({ command }) => {\n const val = command.args[0];\n const currentOn = ctx.getConfig().streaming.c2c;\n if (!val) {\n return [\n `📡 流式消息状态:${currentOn ? \"✅ 已开启\" : \"❌ 已关闭\"}`,\n ``,\n `<qqbot-cmd-input text=\"/bot-streaming on\" show=\"on\"/> 开启`,\n `<qqbot-cmd-input text=\"/bot-streaming off\" show=\"off\"/> 关闭`,\n ].join(\"\\n\");\n }\n if (val !== \"on\" && val !== \"off\") {\n return [\n `❌ 参数错误,请使用 on 或 off`,\n ``,\n `示例:/bot-streaming on`,\n ].join(\"\\n\");\n }\n const wantOn = val === \"on\";\n if (wantOn === currentOn) {\n return `📡 流式消息已经是${wantOn ? \"开启\" : \"关闭\"}状态,无需操作`;\n }\n ctx.updateConfig({ streamingC2c: wantOn });\n return [\n `✅ 流式消息已${wantOn ? \"开启\" : \"关闭\"}`,\n ``,\n wantOn ? `AI 的回复将以流式形式逐步显示。` : `AI 的回复将恢复为完整发送。`,\n ].join(\"\\n\");\n },\n },\n {\n name: \"bot-config\",\n description: \"查看当前运行配置\",\n scope: \"c2c\",\n usage: [\n `/bot-config`,\n ``,\n `查看当前运行时的关键配置项。`,\n ].join(\"\\n\"),\n handler: () => {\n const c = ctx.getConfig();\n const presetLabels: Record<string, string> = {\n full: \"详细模式\",\n compact: \"普通模式\",\n minimal: \"简洁模式\",\n \"text-only\": \"纯净模式\",\n };\n const presetLabel = `${presetLabels[c.message.display.preset] ?? c.message.display.preset} (${c.message.display.preset})`;\n return [\n `### ⚙️ 当前运行配置`,\n ``,\n `| 配置项 | 值 |`,\n `| --- | --- |`,\n `| 消息模式 | ${presetLabel} |`,\n `| 流式消息 | ${c.streaming.c2c ? \"✅ 开启\" : \"❌ 关闭\"} |`,\n ].join(\"\\n\");\n },\n },\n ];\n}\n","/**\n * Envelope — QQ Bot 消息信封格式化\n *\n * 将 QQBot SDK 的 MiddlewareContext 组装为发给 ACP/LLM 的文本上下文。\n *\n * 输出示例(私聊文本):\n * <routing target=\"c2c:openid\" />\n * 你好\n *\n * 输出示例(群聊语音,ASR 转写):\n * <routing target=\"group:groupid\" />\n * <sender name=\"用户名\" />\n * [语音转文字] 你好呀,能听到吗?\n *\n * 输出示例(带引用回复):\n * <routing target=\"c2c:openid\" />\n * [引用] 之前的消息内容...\n * 我的回复\n */\n\nimport type { MiddlewareContext } from \"@tencent/qqbot-nodejs\";\n\nexport function formatQQBotEnvelope(ctx: MiddlewareContext): string {\n const parts: string[] = [];\n const msg = ctx.message;\n const content = (msg.content ?? \"\").trim();\n\n // 斜杠指令不需要 target 标签(不会发给 LLM)\n const isCommand = content.startsWith(\"/\");\n\n // 消息来源(用 XML 自闭合标签,避免在 <user_query> 内被模型误解为用户发言)\n if (!isCommand) {\n if (msg.kind === \"group\") {\n parts.push(`<routing target=\"group:${msg.groupOpenid ?? \"\"}\" />`);\n } else {\n parts.push(`<routing target=\"c2c:${msg.senderId}\" />`);\n }\n }\n\n // 引用消息\n const quote = ctx.state.quote as { text?: string } | undefined;\n if (quote?.text) {\n parts.push(`[引用] ${quote.text}`);\n }\n\n // 群聊标注发送者(标签格式,不混入正文)\n if (msg.kind === \"group\" && !isCommand) {\n const sender = msg.senderName || msg.senderId;\n parts.push(`<sender name=\"${sender}\" />`);\n }\n\n if (content) {\n parts.push(content);\n }\n\n // 附件:语音 ASR 转写 + 文件名标记\n if (msg.attachments && msg.attachments.length > 0) {\n for (const att of msg.attachments) {\n if (att.asr_refer_text) {\n parts.push(`[语音转文字] ${att.asr_refer_text}`);\n } else {\n const name = att.filename ?? att.content_type ?? \"file\";\n parts.push(`[附件] ${name}`);\n }\n }\n }\n\n // 群聊 @机器人 标记\n if (msg.kind === \"group\") {\n const mentioned = Array.isArray(msg.mentions)\n && msg.mentions.some((m: { is_you?: boolean }) => m?.is_you === true);\n if (mentioned) {\n parts.push(\"(@you)\");\n }\n }\n\n return parts.join(\"\\n\");\n}\n","/**\n * Display — Tool 展示格式化\n *\n * 负责 tool_call / thought / plan 在消息中的展示格式。\n */\n\nconst TOOL_EMOJI: Record<string, string> = {\n search: \"🔍\",\n fetch: \"🌐\",\n execute: \"⚡\",\n read: \"📖\",\n edit: \"✏️\",\n think: \"💭\",\n delete: \"🗑️\",\n other: \"🔧\",\n};\n\n/** Secondary emoji lookup by title (when kind=other). Case-insensitive prefix match. */\nconst TITLE_EMOJI: Array<[string, string]> = [\n [\"skill\", \"🧩\"],\n [\"mcp\", \"🔌\"],\n [\"bash\", \"⚡\"],\n [\"terminal\", \"⚡\"],\n [\"shell\", \"⚡\"],\n [\"browser\", \"🌐\"],\n [\"web\", \"🌐\"],\n [\"file\", \"📄\"],\n [\"write\", \"✏️\"],\n [\"create\", \"✏️\"],\n [\"list\", \"📋\"],\n [\"analyze\", \"🔬\"],\n [\"deploy\", \"🚀\"],\n [\"install\", \"📦\"],\n [\"test\", \"🧪\"],\n [\"git\", \"📌\"],\n [\"image\", \"🖼️\"],\n [\"upload\", \"📤\"],\n [\"download\", \"📥\"],\n [\"database\", \"🗄️\"],\n [\"sql\", \"🗄️\"],\n [\"api\", \"🔌\"],\n];\n\nfunction resolveEmoji(kind: string, title?: string): string {\n if (kind !== \"other\" || !title) return TOOL_EMOJI[kind] ?? \"🔧\";\n const lower = title.toLowerCase();\n for (const [prefix, emoji] of TITLE_EMOJI) {\n if (lower.startsWith(prefix) || lower.includes(prefix)) return emoji;\n }\n return \"🔧\";\n}\n\n/** Extract a URL from a title string like \"Fetch https://...\" */\nfunction extractUrl(title: string): string | undefined {\n const match = title.match(/https?:\\/\\/\\S+/);\n return match?.[0];\n}\n\n/** Shorten a URL to domain + truncated path for display */\nfunction shortenUrl(url: string): string {\n try {\n const parsed = new URL(url);\n const host = parsed.hostname.replace(/^www\\./, \"\");\n const pathname = parsed.pathname;\n if (pathname.length <= 1 && !parsed.search) {\n return host;\n }\n const shortPath = pathname.length > 20\n ? `${pathname.slice(0, 20)}…`\n : pathname;\n return `${host}${shortPath}`;\n } catch {\n // Fallback: truncate raw URL\n return url.length > 40 ? `${url.slice(0, 40)}…` : url;\n }\n}\n\nexport interface DisplayConfig {\n tool: boolean;\n thought: boolean;\n plan: boolean;\n toolEmoji: boolean;\n toolKind: boolean;\n toolTitle: boolean;\n /** Max display length for tool detail when truncation is enabled. Default: 120 */\n toolDetailMaxLength?: number;\n /** Tool kinds whose detail should be truncated. Default: [] (no truncation) */\n toolDetailTruncate?: string[];\n}\n\n/** Format tool call text based on display config */\nexport function formatTool(display: DisplayConfig, kind?: string, title?: string, detail?: string): string {\n const parts: string[] = [];\n const k = kind ?? \"other\";\n\n if (display.toolEmoji) {\n parts.push(resolveEmoji(k, title));\n }\n\n if (display.toolKind) {\n // When kind=other, prefer title as the label (e.g. \"Skill\" instead of \"Other\")\n const label = k === \"other\" && title\n ? title\n : k.charAt(0).toUpperCase() + k.slice(1);\n parts.push(label);\n }\n\n if (display.toolTitle && title) {\n // execute 类型:用代码块展示 command\n if (k === \"execute\" && detail) {\n const shouldTruncate = display.toolDetailTruncate?.includes(k);\n const maxLen = shouldTruncate ? (display.toolDetailMaxLength ?? 120) : 0;\n const cmd = truncateDetail(detail, maxLen);\n const header = parts.join(\" \");\n return `${header}\\n\\`\\`\\`\\n${cmd}\\n\\`\\`\\``;\n }\n\n // fetch 类型:提取 URL 并以超链接缩写展示\n if (k === \"fetch\") {\n const url = extractUrl(title);\n if (url) {\n parts.push(`[${shortenUrl(url)}](${url})`);\n return parts.join(\" \");\n }\n }\n\n // Avoid duplicating kind/title in the output\n const labelUsed = k === \"other\" && display.toolKind;\n if (!labelUsed) {\n const t = title.toLowerCase().startsWith(k.toLowerCase())\n ? (display.toolKind ? title.slice(k.length).trim() : title)\n : title;\n if (t) parts.push(t);\n }\n }\n\n // detail: show in compact/full (when toolTitle is enabled), skip if redundant with title\n if (display.toolTitle && detail && detail.trim()) {\n const titleLower = (title ?? \"\").toLowerCase().trim();\n const detailLower = detail.toLowerCase().trim();\n // Strip surrounding quotes for comparison (title may wrap detail in quotes)\n const titleNorm = titleLower.replace(/[\"\"\"''`]/g, \"\").trim();\n const detailNorm = detailLower.replace(/[\"\"\"''`]/g, \"\").trim();\n const isRedundant = titleNorm === detailNorm\n || titleNorm.includes(detailNorm)\n || detailNorm.includes(titleNorm);\n if (!isRedundant) {\n const shouldTruncate = display.toolDetailTruncate?.includes(k);\n const maxLen = shouldTruncate ? (display.toolDetailMaxLength ?? 120) : 0;\n const truncated = truncateDetail(detail, maxLen);\n parts.push(`\\`${truncated}\\``);\n }\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Truncate detail text uniformly (keep head).\n * @param maxLen - 0 means no truncation\n */\nfunction truncateDetail(detail: string, maxLen: number): string {\n if (maxLen <= 0 || detail.length <= maxLen) return detail;\n return `${detail.slice(0, maxLen - 1)}…`;\n}\n","/**\n * Reply — 流式/批量回复处理\n *\n * 将 Backend 的 ChatChunk 流消费并输出到 QQ 消息(流式 or 批量)。\n */\n\nimport type { QQBot, MiddlewareContext, QQBotInboundMessage } from \"@tencent/qqbot-nodejs\";\nimport type { ReplyBackend } from \"./backend/types.js\";\nimport type { BotConfig } from \"./config/schema.js\";\nimport type { Logger } from \"./utils/logger.js\";\nimport { formatTool, type DisplayConfig } from \"./display.js\";\nimport { replyEmptyTotal, replyFallbackTotal, replyChunksTotal, replyLength } from \"./telemetry/metrics.js\";\n\nexport interface ReplyContext {\n bot: QQBot;\n backend: ReplyBackend;\n config: BotConfig;\n logger: Logger;\n}\n\nexport async function streamReply(\n rctx: ReplyContext,\n ctx: MiddlewareContext,\n msg: QQBotInboundMessage,\n sessionId: string,\n qualifier: string,\n text: string,\n attachments?: Array<{ url: string; mimeType: string; name: string; size?: number }>,\n): Promise<void> {\n const { bot, backend, config, logger } = rctx;\n const emptyReplyMsg = config.message.errorMessages.emptyReply;\n const stream = bot.openStream({\n target: msg.replyTarget,\n throttleMs: config.streaming.throttleMs,\n });\n\n let replyText = \"\";\n const seenTools = new Set<string>();\n let planShown = false;\n let chunkCount = 0;\n const display = config.message.display as DisplayConfig;\n const scopeType = msg.replyTarget.scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n\n try {\n for await (const chunk of backend.chat({ sessionId, qualifier, text, attachments })) {\n // 检查是否已被 concurrencyGuard abort\n if (ctx.signal.aborted) {\n logger.debug(`[stream] ${qualifier} aborted, stopping`);\n backend.cancel?.(qualifier);\n stream.cancel();\n return;\n }\n\n switch (chunk.type) {\n case \"text\":\n chunkCount++;\n replyText += chunk.content;\n await stream.update(replyText);\n break;\n case \"thought\":\n if (display.thought) {\n replyText += chunk.content;\n await stream.update(replyText);\n }\n break;\n case \"tool\": {\n if (!display.tool) break;\n const tid = chunk.toolCallId ?? chunk.content;\n if (chunk.status === \"in_progress\" && !seenTools.has(tid)) {\n seenTools.add(tid);\n replyText += `\\n${formatTool(display, chunk.kind, chunk.content, chunk.detail)}\\n`;\n await stream.update(replyText);\n }\n break;\n }\n case \"plan\":\n if (display.plan && !planShown && chunk.content) {\n planShown = true;\n replyText += `\\n📋 执行计划:\\n${chunk.content}\\n`;\n await stream.update(replyText);\n }\n break;\n case \"done\": {\n // 检查 stopReason — 非正常结束时抛出错误走 errorMessages 规则\n const stopReason = chunk.stopReason ?? \"end_turn\";\n if (stopReason !== \"end_turn\" && stopReason !== \"cancelled\") {\n // 已有输出内容 → 先正常展示,错误信息追加在末尾\n if (replyText) {\n replyChunksTotal.add(chunkCount, { scope: scopeType });\n replyLength.record(replyText.length, { scope: scopeType });\n await stream.complete();\n logger.info(`[stream] ${qualifier} 完成(${stopReason}) (len=${replyText.length})`);\n return;\n }\n // 无输出 → 取消流,抛错让 runner.formatErrorForUser 处理\n stream.cancel();\n throw new Error(`[${stopReason}] ${chunk.content || \"\"}`);\n }\n // 正常完成\n replyChunksTotal.add(chunkCount, { scope: scopeType });\n if (replyText) {\n replyLength.record(replyText.length, { scope: scopeType });\n await stream.complete();\n } else {\n replyEmptyTotal.add(1, { scope: scopeType });\n stream.cancel();\n await bot.sendText(msg.replyTarget, emptyReplyMsg);\n }\n logger.info(`[stream] ${qualifier} 完成 (len=${replyText.length})`);\n return;\n }\n }\n }\n // 兜底:循环正常结束但未收到 done\n if (!ctx.signal.aborted) {\n replyChunksTotal.add(chunkCount, { scope: scopeType });\n if (replyText) {\n replyLength.record(replyText.length, { scope: scopeType });\n await stream.complete();\n } else {\n replyEmptyTotal.add(1, { scope: scopeType });\n stream.cancel();\n await bot.sendText(msg.replyTarget, emptyReplyMsg);\n }\n logger.info(`[stream] ${qualifier} 完成 (len=${replyText.length})`);\n } else {\n backend.cancel?.(qualifier);\n stream.cancel();\n logger.debug(`[stream] ${qualifier} aborted after loop`);\n }\n } catch (err) {\n stream.cancel();\n if (replyText && !ctx.signal.aborted) {\n replyFallbackTotal.add(1, { scope: scopeType });\n await bot.sendText(msg.replyTarget, replyText);\n }\n throw err;\n }\n}\n\nexport async function batchReply(\n rctx: ReplyContext,\n ctx: MiddlewareContext,\n msg: QQBotInboundMessage,\n sessionId: string,\n qualifier: string,\n text: string,\n attachments?: Array<{ url: string; mimeType: string; name: string; size?: number }>,\n): Promise<void> {\n const { bot, backend, config, logger } = rctx;\n const emptyReplyMsg = config.message.errorMessages.emptyReply;\n let replyText = \"\";\n const seenTools = new Set<string>();\n let planShown = false;\n let chunkCount = 0;\n const display = config.message.display as DisplayConfig;\n const scopeType = msg.replyTarget.scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n\n for await (const chunk of backend.chat({ sessionId, qualifier, text, attachments })) {\n // 检查是否已被 concurrencyGuard abort\n if (ctx.signal.aborted) {\n logger.debug(`[batch] ${qualifier} aborted, stopping`);\n backend.cancel?.(qualifier);\n return;\n }\n\n switch (chunk.type) {\n case \"text\":\n chunkCount++;\n replyText += chunk.content;\n break;\n case \"thought\":\n if (display.thought) {\n replyText += chunk.content;\n }\n break;\n case \"tool\": {\n if (!display.tool) break;\n const tid = chunk.toolCallId ?? chunk.content;\n if (chunk.status === \"in_progress\" && !seenTools.has(tid)) {\n seenTools.add(tid);\n replyText += `\\n${formatTool(display, chunk.kind, chunk.content, chunk.detail)}\\n`;\n }\n break;\n }\n case \"plan\":\n if (display.plan && !planShown && chunk.content) {\n planShown = true;\n replyText += `\\n📋 执行计划:\\n${chunk.content}\\n`;\n }\n break;\n case \"done\": {\n const stopReason = chunk.stopReason ?? \"end_turn\";\n if (stopReason !== \"end_turn\" && stopReason !== \"cancelled\") {\n if (replyText) break; // 有输出 → 正常展示\n throw new Error(`[${stopReason}] ${chunk.content || \"\"}`);\n }\n break;\n }\n }\n }\n if (ctx.signal.aborted) {\n backend.cancel?.(qualifier);\n logger.debug(`[batch] ${qualifier} aborted after loop`);\n return;\n }\n const reply = replyText.trim() || emptyReplyMsg;\n replyChunksTotal.add(chunkCount, { scope: scopeType });\n if (!replyText.trim()) {\n replyEmptyTotal.add(1, { scope: scopeType });\n } else {\n replyLength.record(reply.length, { scope: scopeType });\n }\n await bot.sendText(msg.replyTarget, reply);\n logger.info(`[batch] ${qualifier} 发送 (len=${reply.length})`);\n}\n","/**\n * Telemetry Middleware — 自动埋点中间件\n *\n * 放在中间件链头部,自动为每条消息:\n * - 创建 root span\n * - 记录 serverStartedTotal(被调开始)\n * - 记录 serverHandledTotal(被调完成)\n * - 记录 serverHandledSeconds(被调耗时,秒)\n *\n * 业务代码无需感知 telemetry 存在(零侵入)。\n */\n\nimport type { Middleware } from \"@tencent/qqbot-nodejs\";\nimport { trace, SpanStatusCode } from \"@opentelemetry/api\";\nimport { METRIC_ATTRS } from \"./constants.js\";\nimport {\n serverStartedTotal,\n serverHandledTotal,\n serverHandledSeconds,\n} from \"./metrics.js\";\n\nconst tracer = trace.getTracer(\"qqbot-cli\");\n\nexport interface TelemetryMiddlewareOptions {\n appId: string;\n}\n\nexport function telemetryMiddleware(opts: TelemetryMiddlewareOptions): Middleware {\n return async (ctx, next) => {\n const msg = ctx.message;\n const scope = msg.replyTarget.scope;\n const kind = msg.kind ?? \"unknown\";\n const scopeType = scope.startsWith(\"group\") ? \"group\" : \"c2c\";\n\n // 被调 attributes(基础部分,不含结果维度)\n const attrs = {\n [METRIC_ATTRS.CALLER_SERVICE]: \"qq-platform\",\n [METRIC_ATTRS.CALLER_METHOD]: kind,\n [METRIC_ATTRS.CALLER_SERVER]: \"qq-platform\",\n [METRIC_ATTRS.CALLEE_SERVICE]: \"qqbot-cli\",\n [METRIC_ATTRS.CALLEE_METHOD]: \"handleMessage\",\n [METRIC_ATTRS.CALLEE_SERVER]: \"qqbot-cli\",\n [METRIC_ATTRS.USER_EXT1]: scopeType,\n };\n\n const startTime = Date.now();\n await tracer.startActiveSpan(\n \"message\",\n {\n attributes: {\n \"bot.app_id\": opts.appId,\n \"msg.kind\": kind,\n \"msg.scope\": scope,\n \"msg.sender\": msg.senderId ?? \"\",\n \"msg.content.length\": (msg.content ?? \"\").length,\n },\n },\n async (span) => {\n let hasError = false;\n try {\n await next();\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (err) {\n hasError = true;\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err instanceof Error ? err.message : String(err),\n });\n span.recordException(err instanceof Error ? err : new Error(String(err)));\n throw err;\n } finally {\n span.end();\n\n // 区分是否经过完整 handler 处理\n const handleType = ctx.state.handled ? \"handled\" : \"buffered\";\n const baseAttrs = {\n ...attrs,\n [METRIC_ATTRS.USER_EXT2]: handleType,\n };\n\n // startedTotal: 纯请求计数,code 固定为 success\n serverStartedTotal.add(1, { ...baseAttrs, [METRIC_ATTRS.CODE]: 0, [METRIC_ATTRS.CODE_TYPE]: \"success\" });\n // handledTotal + handledSeconds: 带实际结果\n const resultAttrs = { ...baseAttrs, [METRIC_ATTRS.CODE]: hasError ? 1 : 0, [METRIC_ATTRS.CODE_TYPE]: hasError ? \"error\" : \"success\" };\n serverHandledTotal.add(1, resultAttrs);\n serverHandledSeconds.record((Date.now() - startTime) / 1000, resultAttrs);\n }\n },\n );\n };\n}\n"],"mappings":"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","names":["fs","resolve","resolve","path","trace","SpanKind","SpanStatusCode","tracer","existsSync","URL","z","z","z","z","existsSync","URL","path","resolve","ctx","trace","SpanStatusCode","tracer","trace","SpanStatusCode","require"]}