@huyooo/ai-chat-core 0.3.7 → 0.3.8

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.
Files changed (220) hide show
  1. package/dist/adapter/index.d.ts +0 -1
  2. package/dist/adapter/model-adapter.d.ts +0 -1
  3. package/dist/adapter/model-options.d.ts +0 -1
  4. package/dist/adapter/types.d.ts +0 -1
  5. package/dist/chat-runtime.d.ts +0 -1
  6. package/dist/constants.d.ts +0 -1
  7. package/dist/events.d.ts +0 -1
  8. package/dist/extension/index.d.ts +0 -1
  9. package/dist/extension/types.d.ts +0 -1
  10. package/dist/families/index.d.ts +0 -1
  11. package/dist/families/presets.d.ts +0 -1
  12. package/dist/families/resolver.d.ts +0 -1
  13. package/dist/families/types.d.ts +0 -1
  14. package/dist/governance/command-safety.d.ts +0 -1
  15. package/dist/governance/governance.d.ts +0 -1
  16. package/dist/governance/index.d.ts +0 -1
  17. package/dist/governance/types.d.ts +0 -1
  18. package/dist/index.d.ts +0 -1
  19. package/dist/internal/management-args.d.ts +0 -1
  20. package/dist/internal/management-results.d.ts +0 -1
  21. package/dist/llm-config.d.ts +0 -1
  22. package/dist/logger/core.d.ts +0 -1
  23. package/dist/logger/index.d.ts +0 -1
  24. package/dist/orchestrator/compression-handler.d.ts +0 -1
  25. package/dist/orchestrator/context-compressor.d.ts +0 -1
  26. package/dist/orchestrator/context-summarizer.d.ts +0 -1
  27. package/dist/orchestrator/index.d.ts +0 -1
  28. package/dist/orchestrator/orchestrator.d.ts +0 -1
  29. package/dist/orchestrator/types.d.ts +0 -1
  30. package/dist/parts/index.d.ts +0 -1
  31. package/dist/parts/registry.d.ts +0 -1
  32. package/dist/parts/summaries.d.ts +0 -1
  33. package/dist/parts/types.d.ts +0 -1
  34. package/dist/platform.d.ts +0 -1
  35. package/dist/protocols/anthropic.d.ts +0 -1
  36. package/dist/protocols/ark.d.ts +0 -1
  37. package/dist/protocols/deepseek.d.ts +0 -1
  38. package/dist/protocols/error-utils.d.ts +0 -1
  39. package/dist/protocols/gemini.d.ts +0 -1
  40. package/dist/protocols/glm.d.ts +0 -1
  41. package/dist/protocols/grok.d.ts +0 -1
  42. package/dist/protocols/index.d.ts +0 -1
  43. package/dist/protocols/minimax.d.ts +0 -1
  44. package/dist/protocols/moonshot.d.ts +0 -1
  45. package/dist/protocols/openai-sse.d.ts +0 -1
  46. package/dist/protocols/openai.d.ts +0 -1
  47. package/dist/protocols/qwen.d.ts +0 -1
  48. package/dist/protocols/responses-sse.d.ts +0 -1
  49. package/dist/protocols/sse-reader.d.ts +0 -1
  50. package/dist/protocols/tool-arguments.d.ts +0 -1
  51. package/dist/protocols/types.d.ts +0 -1
  52. package/dist/protocols/vercel-gateway.d.ts +0 -1
  53. package/dist/runtime.d.ts +0 -1
  54. package/dist/skills/index.d.ts +0 -1
  55. package/dist/skills/management/admin.d.ts +0 -1
  56. package/dist/skills/management/index.d.ts +0 -1
  57. package/dist/skills/management/inputs.d.ts +0 -1
  58. package/dist/skills/management/operations.d.ts +0 -1
  59. package/dist/skills/management/types.d.ts +0 -1
  60. package/dist/skills/registry.d.ts +0 -1
  61. package/dist/skills/summaries.d.ts +0 -1
  62. package/dist/skills/types.d.ts +0 -1
  63. package/dist/test-utils/mock-sse.d.ts +0 -1
  64. package/dist/tool-manager/define-tool.d.ts +0 -1
  65. package/dist/tool-manager/formats.d.ts +0 -1
  66. package/dist/tool-manager/identity.d.ts +0 -1
  67. package/dist/tool-manager/in-process-provider.d.ts +0 -1
  68. package/dist/tool-manager/index.d.ts +0 -1
  69. package/dist/tool-manager/manager.d.ts +0 -1
  70. package/dist/tool-manager/mcp-provider.d.ts +0 -1
  71. package/dist/tool-manager/summaries.d.ts +0 -1
  72. package/dist/tool-manager/types.d.ts +0 -1
  73. package/dist/types.d.ts +0 -1
  74. package/package.json +2 -3
  75. package/dist/adapter/index.d.ts.map +0 -1
  76. package/dist/adapter/model-adapter.d.ts.map +0 -1
  77. package/dist/adapter/model-options.d.ts.map +0 -1
  78. package/dist/adapter/types.d.ts.map +0 -1
  79. package/dist/chat-runtime.d.ts.map +0 -1
  80. package/dist/constants.d.ts.map +0 -1
  81. package/dist/events.d.ts.map +0 -1
  82. package/dist/extension/index.d.ts.map +0 -1
  83. package/dist/extension/types.d.ts.map +0 -1
  84. package/dist/families/index.d.ts.map +0 -1
  85. package/dist/families/presets.d.ts.map +0 -1
  86. package/dist/families/resolver.d.ts.map +0 -1
  87. package/dist/families/types.d.ts.map +0 -1
  88. package/dist/governance/command-safety.d.ts.map +0 -1
  89. package/dist/governance/governance.d.ts.map +0 -1
  90. package/dist/governance/index.d.ts.map +0 -1
  91. package/dist/governance/types.d.ts.map +0 -1
  92. package/dist/index.d.ts.map +0 -1
  93. package/dist/internal/management-args.d.ts.map +0 -1
  94. package/dist/internal/management-results.d.ts.map +0 -1
  95. package/dist/llm-config.d.ts.map +0 -1
  96. package/dist/logger/core.d.ts.map +0 -1
  97. package/dist/logger/index.d.ts.map +0 -1
  98. package/dist/orchestrator/compression-handler.d.ts.map +0 -1
  99. package/dist/orchestrator/context-compressor.d.ts.map +0 -1
  100. package/dist/orchestrator/context-summarizer.d.ts.map +0 -1
  101. package/dist/orchestrator/index.d.ts.map +0 -1
  102. package/dist/orchestrator/orchestrator.d.ts.map +0 -1
  103. package/dist/orchestrator/types.d.ts.map +0 -1
  104. package/dist/parts/index.d.ts.map +0 -1
  105. package/dist/parts/registry.d.ts.map +0 -1
  106. package/dist/parts/summaries.d.ts.map +0 -1
  107. package/dist/parts/types.d.ts.map +0 -1
  108. package/dist/platform.d.ts.map +0 -1
  109. package/dist/protocols/anthropic.d.ts.map +0 -1
  110. package/dist/protocols/ark.d.ts.map +0 -1
  111. package/dist/protocols/deepseek.d.ts.map +0 -1
  112. package/dist/protocols/error-utils.d.ts.map +0 -1
  113. package/dist/protocols/gemini.d.ts.map +0 -1
  114. package/dist/protocols/glm.d.ts.map +0 -1
  115. package/dist/protocols/grok.d.ts.map +0 -1
  116. package/dist/protocols/index.d.ts.map +0 -1
  117. package/dist/protocols/minimax.d.ts.map +0 -1
  118. package/dist/protocols/moonshot.d.ts.map +0 -1
  119. package/dist/protocols/openai-sse.d.ts.map +0 -1
  120. package/dist/protocols/openai.d.ts.map +0 -1
  121. package/dist/protocols/qwen.d.ts.map +0 -1
  122. package/dist/protocols/responses-sse.d.ts.map +0 -1
  123. package/dist/protocols/sse-reader.d.ts.map +0 -1
  124. package/dist/protocols/tool-arguments.d.ts.map +0 -1
  125. package/dist/protocols/types.d.ts.map +0 -1
  126. package/dist/protocols/vercel-gateway.d.ts.map +0 -1
  127. package/dist/runtime.d.ts.map +0 -1
  128. package/dist/skills/index.d.ts.map +0 -1
  129. package/dist/skills/management/admin.d.ts.map +0 -1
  130. package/dist/skills/management/index.d.ts.map +0 -1
  131. package/dist/skills/management/inputs.d.ts.map +0 -1
  132. package/dist/skills/management/operations.d.ts.map +0 -1
  133. package/dist/skills/management/types.d.ts.map +0 -1
  134. package/dist/skills/registry.d.ts.map +0 -1
  135. package/dist/skills/summaries.d.ts.map +0 -1
  136. package/dist/skills/types.d.ts.map +0 -1
  137. package/dist/test-utils/mock-sse.d.ts.map +0 -1
  138. package/dist/tool-manager/define-tool.d.ts.map +0 -1
  139. package/dist/tool-manager/formats.d.ts.map +0 -1
  140. package/dist/tool-manager/identity.d.ts.map +0 -1
  141. package/dist/tool-manager/in-process-provider.d.ts.map +0 -1
  142. package/dist/tool-manager/index.d.ts.map +0 -1
  143. package/dist/tool-manager/manager.d.ts.map +0 -1
  144. package/dist/tool-manager/mcp-provider.d.ts.map +0 -1
  145. package/dist/tool-manager/summaries.d.ts.map +0 -1
  146. package/dist/tool-manager/types.d.ts.map +0 -1
  147. package/dist/types.d.ts.map +0 -1
  148. package/src/adapter/index.ts +0 -25
  149. package/src/adapter/model-adapter.ts +0 -196
  150. package/src/adapter/model-options.ts +0 -143
  151. package/src/adapter/types.ts +0 -41
  152. package/src/chat-runtime.ts +0 -515
  153. package/src/constants.ts +0 -32
  154. package/src/events.ts +0 -1084
  155. package/src/extension/index.ts +0 -24
  156. package/src/extension/types.ts +0 -49
  157. package/src/families/index.ts +0 -28
  158. package/src/families/presets.ts +0 -124
  159. package/src/families/resolver.ts +0 -22
  160. package/src/families/types.ts +0 -55
  161. package/src/governance/command-safety.ts +0 -224
  162. package/src/governance/governance.ts +0 -125
  163. package/src/governance/index.ts +0 -38
  164. package/src/governance/types.ts +0 -44
  165. package/src/index.ts +0 -426
  166. package/src/internal/management-args.ts +0 -39
  167. package/src/internal/management-results.ts +0 -60
  168. package/src/llm-config.ts +0 -137
  169. package/src/logger/core.ts +0 -96
  170. package/src/logger/index.ts +0 -8
  171. package/src/orchestrator/compression-handler.ts +0 -137
  172. package/src/orchestrator/context-compressor.ts +0 -249
  173. package/src/orchestrator/context-summarizer.ts +0 -123
  174. package/src/orchestrator/index.ts +0 -20
  175. package/src/orchestrator/orchestrator.ts +0 -1002
  176. package/src/orchestrator/types.ts +0 -70
  177. package/src/parts/index.ts +0 -20
  178. package/src/parts/registry.ts +0 -95
  179. package/src/parts/summaries.ts +0 -40
  180. package/src/parts/types.ts +0 -63
  181. package/src/platform.ts +0 -73
  182. package/src/protocols/anthropic.ts +0 -377
  183. package/src/protocols/ark.ts +0 -300
  184. package/src/protocols/deepseek.ts +0 -192
  185. package/src/protocols/error-utils.ts +0 -71
  186. package/src/protocols/gemini.ts +0 -352
  187. package/src/protocols/glm.ts +0 -212
  188. package/src/protocols/grok.ts +0 -98
  189. package/src/protocols/index.ts +0 -48
  190. package/src/protocols/minimax.ts +0 -308
  191. package/src/protocols/moonshot.ts +0 -186
  192. package/src/protocols/openai-sse.ts +0 -156
  193. package/src/protocols/openai.ts +0 -97
  194. package/src/protocols/qwen.ts +0 -358
  195. package/src/protocols/responses-sse.ts +0 -224
  196. package/src/protocols/sse-reader.ts +0 -54
  197. package/src/protocols/tool-arguments.ts +0 -32
  198. package/src/protocols/types.ts +0 -198
  199. package/src/protocols/vercel-gateway.ts +0 -391
  200. package/src/runtime.ts +0 -167
  201. package/src/skills/index.ts +0 -29
  202. package/src/skills/management/admin.ts +0 -170
  203. package/src/skills/management/index.ts +0 -27
  204. package/src/skills/management/inputs.ts +0 -79
  205. package/src/skills/management/operations.ts +0 -256
  206. package/src/skills/management/types.ts +0 -57
  207. package/src/skills/registry.ts +0 -120
  208. package/src/skills/summaries.ts +0 -48
  209. package/src/skills/types.ts +0 -65
  210. package/src/test-utils/mock-sse.ts +0 -32
  211. package/src/tool-manager/define-tool.ts +0 -201
  212. package/src/tool-manager/formats.ts +0 -146
  213. package/src/tool-manager/identity.ts +0 -80
  214. package/src/tool-manager/in-process-provider.ts +0 -164
  215. package/src/tool-manager/index.ts +0 -63
  216. package/src/tool-manager/manager.ts +0 -562
  217. package/src/tool-manager/mcp-provider.ts +0 -509
  218. package/src/tool-manager/summaries.ts +0 -136
  219. package/src/tool-manager/types.ts +0 -389
  220. package/src/types.ts +0 -1142
@@ -1,143 +0,0 @@
1
- /**
2
- * 模型选项与上下文展示配置
3
- *
4
- * - 从 LLMConfig 推导前端下拉模型列表(capabilities、定价文案、上下文窗口)
5
- * - formatPricing / formatContextWindow:人类可读展示
6
- */
7
-
8
- import type { LLMConfig, ModelConfig, ModelPricing } from '../llm-config';
9
- import { resolveModelFamilyConfig, type ModelFamilyConfig } from '../families';
10
-
11
- // ==================== 工具函数 ====================
12
-
13
- /** 将 ModelPricing 格式化为展示用字符串数组:["¥2/M 输入", "¥3/M 输出"] */
14
- export function formatPricing(pricing: ModelPricing): string[] {
15
- const sym = pricing.currency === 'CNY' ? '¥' : '$';
16
- const fmtNum = (n: number) => Number.isInteger(n) ? String(n) : n.toFixed(2).replace(/0+$/, '').replace(/\.$/, '');
17
- const result: string[] = [];
18
-
19
- result.push(`${sym}${fmtNum(pricing.input)}/M 输入`);
20
-
21
- if (Array.isArray(pricing.output)) {
22
- result.push(`${sym}${fmtNum(pricing.output[0])}~${fmtNum(pricing.output[1])}/M 输出`);
23
- } else {
24
- result.push(`${sym}${fmtNum(pricing.output)}/M 输出`);
25
- }
26
-
27
- if (pricing.cached != null) {
28
- result.push(`${sym}${fmtNum(pricing.cached)}/M 缓存`);
29
- }
30
-
31
- return result;
32
- }
33
-
34
- /** 将 token 数自动推导为人类可读格式:"256K" / "1M" / "10M" */
35
- export function formatContextWindow(tokens: number): string {
36
- if (tokens >= 1_000_000 && tokens % 1_000_000 === 0) {
37
- return `${tokens / 1_000_000}M`;
38
- }
39
- if (tokens >= 1_000_000) {
40
- const m = tokens / 1_000_000;
41
- return Number.isInteger(m) ? `${m}M` : `${parseFloat(m.toFixed(1))}M`;
42
- }
43
- const k = tokens / 1_000;
44
- return Number.isInteger(k) ? `${k}K` : `${parseFloat(k.toFixed(1))}K`;
45
- }
46
-
47
- // ==================== ModelOption(前端显示用) ====================
48
-
49
- export interface ModelOption {
50
- modelId: string;
51
- displayName: string;
52
- supportsThinking: boolean;
53
- thinkingAlwaysOn?: boolean;
54
- supportsVision: boolean;
55
- /**
56
- * 模型上下文窗口(token)。
57
- * 前端据此为 @ 资源区块、历史消息等分配 token 预算,避免拍脑袋硬编码。
58
- * 与 {@link ModelContextConfig.contextWindowTokens} 来自同一 ModelConfig 字段。
59
- */
60
- contextWindowTokens: number;
61
- /**
62
- * 单次生成允许的最大输出 token。
63
- * 前端在估算可用 prompt 预算时需要从 context window 中扣除这部分。
64
- */
65
- maxOutputTokens: number;
66
- tooltip?: {
67
- features?: string[];
68
- cost?: string[];
69
- description?: string;
70
- };
71
- }
72
-
73
- /**
74
- * 从 LLMConfig 动态构建前端模型列表
75
- *
76
- * 只返回 visible !== false 的模型。
77
- * 所有元数据只从 ModelConfig + familyConfig 取,不查预设库。
78
- */
79
- export function buildModelOptions(config: LLMConfig): ModelOption[] {
80
- const result: ModelOption[] = [];
81
-
82
- for (const [modelId, modelConfig] of Object.entries(config.models)) {
83
- if (!modelConfig || modelConfig.visible === false) continue;
84
-
85
- const familyConfig = resolveModelFamilyConfig(modelId, modelConfig, config);
86
-
87
- const displayName = modelConfig.displayName ?? modelId;
88
- const supportsThinking = modelConfig.supportsThinking;
89
- const supportsVision = modelConfig.supportsVision;
90
- const thinkingAlwaysOn = familyConfig?.thinkingAlwaysOn ?? false;
91
-
92
- const features: string[] = [];
93
- if (supportsVision) features.push('多模态');
94
- if (supportsThinking) {
95
- features.push(thinkingAlwaysOn ? '深度思考(始终开启)' : '深度思考');
96
- }
97
- if (modelConfig.contextWindowTokens) {
98
- features.push(`长上下文(${formatContextWindow(modelConfig.contextWindowTokens)})`);
99
- }
100
-
101
- result.push({
102
- modelId,
103
- displayName,
104
- supportsThinking,
105
- thinkingAlwaysOn,
106
- supportsVision,
107
- contextWindowTokens: modelConfig.contextWindowTokens,
108
- maxOutputTokens: modelConfig.maxOutputTokens,
109
- tooltip: {
110
- features: features.length > 0 ? features : undefined,
111
- cost: modelConfig.pricing ? formatPricing(modelConfig.pricing) : undefined,
112
- },
113
- });
114
- }
115
-
116
- return result;
117
- }
118
-
119
- // ==================== ModelContextConfig(运行时 LLMConfig 感知) ====================
120
-
121
- export interface ModelContextConfig {
122
- contextWindowTokens: number;
123
- maxOutputTokens: number;
124
- }
125
-
126
- /**
127
- * 获取模型的 context 配置(从 LLMConfig 感知)
128
- *
129
- * 只从 ModelConfig 取,不做注册表 fallback。
130
- * contextWindowTokens 和 maxOutputTokens 均为必填字段。
131
- */
132
- export function getModelContextConfigFromLLM(
133
- modelId: string,
134
- config: LLMConfig,
135
- ): ModelContextConfig | undefined {
136
- const modelConfig = config.models[modelId];
137
- if (!modelConfig) return undefined;
138
-
139
- return {
140
- contextWindowTokens: modelConfig.contextWindowTokens,
141
- maxOutputTokens: modelConfig.maxOutputTokens,
142
- };
143
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * Adapter 层类型定义
3
- *
4
- * 仅包含适配器接口和配置,不含编排器类型。
5
- * 编排器类型定义在 orchestrator/types.ts
6
- */
7
-
8
- import type {
9
- RawEvent,
10
- ProtocolMessage,
11
- ProtocolToolDefinition,
12
- } from '../protocols/types';
13
-
14
- export interface AdapterConfig {
15
- apiKey: string;
16
- apiUrl?: string;
17
- }
18
-
19
- export interface StreamOnceOptions {
20
- model: string;
21
- enableThinking?: boolean;
22
- signal: AbortSignal;
23
- }
24
-
25
- /**
26
- * Provider Adapter 接口
27
- *
28
- * 职责:协议路由 + 消息格式转换 + 返回 RawEvent 流
29
- */
30
- export interface ProviderAdapter {
31
- readonly name: string;
32
- readonly supportedModels: string[];
33
-
34
- streamOnce(
35
- messages: ProtocolMessage[],
36
- tools: ProtocolToolDefinition[],
37
- options: StreamOnceOptions
38
- ): AsyncGenerator<RawEvent>;
39
-
40
- supportsModel(model: string): boolean;
41
- }
@@ -1,515 +0,0 @@
1
- /**
2
- * ChatRuntime - 聊天运行时
3
- *
4
- * 新架构(ToolRuntimeManager 工具运行时管理):
5
- * - Core Runtime:`tools` 配置注入的内核 in-process 能力
6
- * - Local Assets:由 asset 管理链创建并扫描的 `tools/parts/skills/mcp-servers`
7
- * - External Providers:外部 MCP 接入层
8
- * - ModelAdapter / ChatOrchestrator / ToolRuntimeManager 负责把三层能力收口到运行时
9
- */
10
-
11
- import type {
12
- AgentConfig,
13
- ToolExecutor,
14
- ChatOptions,
15
- ThinkingMode,
16
- Tool,
17
- ToolContext,
18
- ToolConfigItem,
19
- DataEngineContext,
20
- ToolExecutionAuditHooks,
21
- } from './types';
22
- import { resolveTools } from './types';
23
- import type { ChatEvent } from './events';
24
- import { createApiError } from './events';
25
- import { DEFAULT_MODEL, AGENT_MODE_PROMPT } from './constants';
26
- import { buildModelOptions } from './adapter';
27
- import { resolveModelFamilyConfig } from './families';
28
- import type { ModelFamilyConfig } from './families';
29
- import type { ModelOption } from './adapter';
30
- import type { McpServerConfig, McpConnectionInfo, ToolRuntimeManager } from './tool-manager';
31
- import { createToolRuntimeManager, createInProcessProvider, createMcpProvider } from './tool-manager';
32
- import type { LLMConfig } from './llm-config';
33
-
34
- import type { OrchestratorContext, ToolExecutionHooks } from './orchestrator/types';
35
- import type { ProtocolToolDefinition } from './protocols';
36
- import { ChatOrchestrator } from './orchestrator';
37
- import { ModelAdapter } from './adapter';
38
-
39
- /** 运行时配置 */
40
- export interface RuntimeConfig {
41
- llmConfig: LLMConfig;
42
- cwd: string;
43
- maxIterations?: number;
44
- maxDurationMs?: number;
45
- maxToolCalls?: number;
46
- maxTotalTokens?: number;
47
- dataEngine?: DataEngineContext;
48
- audit?: ToolExecutionAuditHooks;
49
- }
50
-
51
- function createAuditTraceId(): string {
52
- return `tool-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
53
- }
54
-
55
- /**
56
- * 聊天运行时
57
- *
58
- * 职责:
59
- * 1. 管理 ModelAdapter(模型适配器)
60
- * 2. 使用 ChatOrchestrator 统一处理工具调用
61
- * 3. 通过 ToolRuntimeManager 统一管理所有工具
62
- */
63
- export class ChatRuntime {
64
- private config: RuntimeConfig;
65
- private adapter: ModelAdapter;
66
- private orchestrator: ChatOrchestrator;
67
- private toolExecutor: ToolExecutor;
68
- private abortController: AbortController | null = null;
69
-
70
- private toolRuntimeManager: ToolRuntimeManager;
71
- private toolConfig: ToolConfigItem[] | undefined;
72
- private mcpConfigs: McpServerConfig[] | undefined;
73
- private initialized = false;
74
-
75
- constructor(config: AgentConfig, toolExecutor: ToolExecutor) {
76
- if (!config.cwd) {
77
- throw new Error('AgentConfig.cwd is required (browser-safe: no process.cwd() fallback)');
78
- }
79
- this.config = {
80
- llmConfig: config.llmConfig,
81
- cwd: config.cwd,
82
- maxIterations: config.maxIterations,
83
- maxDurationMs: config.maxDurationMs,
84
- maxToolCalls: config.maxToolCalls,
85
- maxTotalTokens: config.maxTotalTokens,
86
- dataEngine: config.dataEngine,
87
- audit: config.audit,
88
- };
89
-
90
- this.toolExecutor = toolExecutor;
91
- this.toolConfig = config.tools;
92
- this.mcpConfigs = config.mcpServers;
93
- this.toolRuntimeManager = createToolRuntimeManager();
94
-
95
- this.adapter = new ModelAdapter(config.llmConfig);
96
-
97
- const summarizeFn = this.createDefaultSummarize();
98
-
99
- this.orchestrator = new ChatOrchestrator({
100
- maxIterations: config.maxIterations,
101
- maxDurationMs: config.maxDurationMs,
102
- maxToolCalls: config.maxToolCalls,
103
- maxTotalTokens: config.maxTotalTokens,
104
- executeTool: this.executeTool.bind(this),
105
- tools: this.toolRuntimeManager.getSessionTools(),
106
- getToolDescriptor: this.toolRuntimeManager.getDescriptor,
107
- onToolApprovalRequest: config.onToolApprovalRequest,
108
- getAutoRunConfig: config.getAutoRunConfig,
109
- summarize: summarizeFn,
110
- compressionConfig: config.llmConfig.compression,
111
- llmConfig: config.llmConfig,
112
- });
113
- }
114
-
115
- /** 异步初始化工具(懒加载,允许桥接层显式触发) */
116
- private async asyncInit(): Promise<void> {
117
- if (this.initialized) return;
118
- this.initialized = true;
119
-
120
- // 第一层:注册 Core Runtime 的 in-process 内核能力
121
- if (this.toolConfig) {
122
- const resolvedTools = await resolveTools(this.toolConfig);
123
- const builtinProvider = createInProcessProvider('builtin');
124
- for (const tool of resolvedTools) {
125
- builtinProvider.register(tool, { source: tool.source, category: tool.category, tags: tool.tags });
126
- }
127
- await this.toolRuntimeManager.addProvider(builtinProvider);
128
-
129
- // 内置工具默认全部启用到会话
130
- await this.toolRuntimeManager.enable(
131
- builtinProvider.getDescriptors().map(d => d.id),
132
- );
133
- }
134
-
135
- // 第三层:注册 External Providers 的 MCP 连接
136
- if (this.mcpConfigs?.length) {
137
- const results = await Promise.allSettled(
138
- this.mcpConfigs.map(async cfg => {
139
- const provider = createMcpProvider(cfg);
140
- await this.toolRuntimeManager.addProvider(provider);
141
- // MCP 工具默认全部启用到会话
142
- const descriptors = provider.getDescriptors();
143
- await this.toolRuntimeManager.enable(descriptors.map(d => d.id));
144
- }),
145
- );
146
-
147
- for (let i = 0; i < results.length; i++) {
148
- if (results[i].status === 'rejected') {
149
- console.error(`[MCP] ${this.mcpConfigs[i].name} 连接失败:`, (results[i] as PromiseRejectedResult).reason);
150
- }
151
- }
152
- }
153
- }
154
-
155
- getModelFamilyConfig(model: string): ModelFamilyConfig | undefined {
156
- const modelConfig = this.config.llmConfig.models[model];
157
- if (!modelConfig) return undefined;
158
- return resolveModelFamilyConfig(model, modelConfig, this.config.llmConfig);
159
- }
160
-
161
- getModelRouteInfo(model: string): { available: boolean; familyConfig?: ModelFamilyConfig } {
162
- const modelConfig = this.config.llmConfig.models[model];
163
- return {
164
- available: this.adapter.supportsModel(model),
165
- familyConfig: modelConfig ? resolveModelFamilyConfig(model, modelConfig, this.config.llmConfig) : undefined,
166
- };
167
- }
168
-
169
- private buildSystemPrompt(options: ChatOptions): string {
170
- const model = options.model || DEFAULT_MODEL;
171
- const mc = this.config.llmConfig.models[model];
172
- const familyConfig = mc ? resolveModelFamilyConfig(model, mc, this.config.llmConfig) : undefined;
173
-
174
- let prompt = AGENT_MODE_PROMPT;
175
-
176
- if (options.platformPrompt) {
177
- prompt += '\n\n' + options.platformPrompt;
178
- }
179
-
180
- if (options.skillContents?.length) {
181
- prompt += '\n\n【用户指令】\n' + options.skillContents.join('\n\n');
182
- }
183
-
184
- const searchTool = this.findSearchTool();
185
- if (options.enableWebSearch && searchTool) {
186
- prompt += `\n\n【联网搜索】当用户问题需要实时信息/最新事实/可引用来源时,请先调用 ${searchTool.name} 工具获取结果,然后基于返回的 title/url/snippet 作答,并在回答中给出来源链接。`;
187
- }
188
-
189
- return prompt;
190
- }
191
-
192
- private createToolContext(signal?: AbortSignal, hooks?: Partial<ToolExecutionHooks>): ToolContext {
193
- const cwd = this.config.cwd;
194
- const executor = this.toolExecutor;
195
- return {
196
- toolCallId: hooks?.toolCallId,
197
- toolName: hooks?.toolName,
198
- allowedToolNames: hooks?.allowedToolNames,
199
- cwd,
200
- exec: async (cmd: string, args?: string[], options?: { timeout?: number }) => {
201
- const command = args?.length ? `${cmd} ${args.join(' ')}` : cmd;
202
- const r = await executor.executeCommand(command, cwd, signal, {
203
- onStdout: hooks?.onStdout,
204
- onStderr: hooks?.onStderr,
205
- }, options?.timeout);
206
- return {
207
- stdout: r.output ?? '',
208
- stderr: r.error ?? '',
209
- exitCode: r.success ? 0 : 1,
210
- };
211
- },
212
- signal,
213
- onStdout: hooks?.onStdout,
214
- onStderr: hooks?.onStderr,
215
- dataEngine: this.config.dataEngine,
216
- };
217
- }
218
-
219
- public async executeTool(
220
- name: string,
221
- args: Record<string, unknown>,
222
- signal?: AbortSignal,
223
- hooks?: ToolExecutionHooks,
224
- ): Promise<import('./types').ToolExecuteResult> {
225
- const sessionTools = this.toolRuntimeManager.getSessionTools();
226
- const tool = sessionTools.get(name);
227
- if (!tool) {
228
- return { error: `未知工具: ${name}` };
229
- }
230
- const descriptor = this.toolRuntimeManager.getDescriptor(name);
231
- const auditGovernance = hooks?.governance;
232
- const traceId = createAuditTraceId();
233
- const audit = this.config.audit;
234
- const auditToolCallId = audit?.startToolCall({
235
- id: hooks?.toolCallId,
236
- traceId,
237
- extensionId: descriptor?.assetId ?? tool.assetId ?? null,
238
- toolName: descriptor?.name ?? hooks?.toolName ?? tool.name,
239
- displayName: descriptor?.displayName ?? tool.displayName ?? null,
240
- source: descriptor?.source ?? tool.source ?? null,
241
- cwd: this.config.cwd,
242
- args,
243
- approvalPolicy: auditGovernance?.approvalPolicy ?? descriptor?.approvalPolicy ?? tool.approvalPolicy ?? null,
244
- sideEffectLevel: auditGovernance?.sideEffectLevel ?? descriptor?.sideEffectLevel ?? tool.sideEffectLevel ?? null,
245
- hostDependency: auditGovernance?.hostDependency ?? descriptor?.hostDependency ?? tool.hostDependency ?? null,
246
- metadata: {
247
- alias: descriptor?.alias ?? tool.alias ?? name,
248
- provider: descriptor?.provider,
249
- category: descriptor?.category ?? tool.category,
250
- tags: descriptor?.tags ?? tool.tags,
251
- },
252
- }) ?? hooks?.toolCallId;
253
- const context = this.createToolContext(signal, {
254
- ...hooks,
255
- toolCallId: auditToolCallId ?? hooks?.toolCallId,
256
- toolName: descriptor?.name ?? hooks?.toolName ?? tool.name,
257
- });
258
- try {
259
- const result = await (audit
260
- ? audit.runWithContext({ toolCallId: auditToolCallId ?? null, traceId }, () => tool.execute(args, context))
261
- : tool.execute(args, context));
262
- if (auditToolCallId) {
263
- audit?.finishToolCall({ toolCallId: auditToolCallId, traceId, result });
264
- }
265
- return result;
266
- } catch (error) {
267
- if (auditToolCallId) {
268
- audit?.failToolCall({ toolCallId: auditToolCallId, traceId, error });
269
- }
270
- throw error;
271
- }
272
- }
273
-
274
- private getToolDefinitions(enabledTools?: string[], forceInclude?: string[]): ProtocolToolDefinition[] {
275
- const sessionTools = this.toolRuntimeManager.getSessionTools();
276
- const allTools = Array.from(sessionTools.values());
277
- let selected = enabledTools !== undefined
278
- ? allTools.filter(t => enabledTools.includes(t.name))
279
- : allTools;
280
-
281
- if (forceInclude?.length) {
282
- for (const name of forceInclude) {
283
- if (!selected.some(t => t.name === name)) {
284
- const t = sessionTools.get(name);
285
- if (t) selected = [...selected, t];
286
- }
287
- }
288
- }
289
-
290
- return selected.map(tool => ({
291
- name: tool.name,
292
- description: tool.description,
293
- parameters: tool.parameters,
294
- }));
295
- }
296
-
297
- /** 查找第一个搜索工具(通过 ui.name 以 _search 结尾标识) */
298
- private findSearchTool(): Tool | undefined {
299
- for (const t of this.toolRuntimeManager.getSessionTools().values()) {
300
- if (t.ui?.type === 'render' && t.ui.name.endsWith('_search')) return t;
301
- }
302
- return undefined;
303
- }
304
-
305
- /** 获取所有搜索工具名(enableWebSearch 开启时 forceInclude 用) */
306
- private getSearchToolNames(): string[] {
307
- const names: string[] = [];
308
- for (const t of this.toolRuntimeManager.getSessionTools().values()) {
309
- if (t.ui?.type === 'render' && t.ui.name.endsWith('_search')) names.push(t.name);
310
- }
311
- return names;
312
- }
313
-
314
- public getAllTools(): Array<{
315
- name: string;
316
- description: string;
317
- displayName: string;
318
- assetId: string;
319
- source: import('./governance').AssetSource;
320
- category: string;
321
- parameters?: import('./types').JsonSchemaObject;
322
- outputSchema?: import('./types').JsonSchemaObject;
323
- resolvedOutputSchema?: import('./types').JsonSchemaObject;
324
- errorSchema?: import('./types').JsonSchemaObject;
325
- approvalPolicy?: import('./governance').AssetApprovalPolicy;
326
- sideEffectLevel?: import('./governance').AssetSideEffectLevel;
327
- hostDependency?: import('./governance').AssetHostDependency;
328
- }> {
329
- return this.toolRuntimeManager.getSessionToolNames()
330
- .map((name) => {
331
- const descriptor = this.toolRuntimeManager.getDescriptor(name);
332
- if (!descriptor) return null;
333
- return {
334
- name: descriptor.alias,
335
- description: descriptor.description,
336
- displayName: descriptor.displayName,
337
- assetId: descriptor.assetId,
338
- source: descriptor.source,
339
- category: descriptor.category,
340
- parameters: descriptor.parameters,
341
- outputSchema: descriptor.outputSchema,
342
- resolvedOutputSchema: descriptor.resolvedOutputSchema,
343
- errorSchema: descriptor.errorSchema,
344
- approvalPolicy: descriptor.approvalPolicy,
345
- sideEffectLevel: descriptor.sideEffectLevel,
346
- hostDependency: descriptor.hostDependency,
347
- };
348
- })
349
- .filter((item): item is NonNullable<typeof item> => !!item);
350
- }
351
-
352
- /** 显式确保工具完成初始化,供 bridge / 宿主在聊天前读取工具列表使用 */
353
- public async ensureInitialized(): Promise<void> {
354
- await this.asyncInit();
355
- }
356
-
357
- /** 获取 ToolRuntimeManager(供外部 assetManager 等集成使用) */
358
- public getToolRuntimeManager(): ToolRuntimeManager {
359
- return this.toolRuntimeManager;
360
- }
361
-
362
- /**
363
- * 聊天入口
364
- */
365
- async *chat(
366
- message: string,
367
- options: ChatOptions = {},
368
- images?: string[],
369
- ): AsyncGenerator<ChatEvent> {
370
- await this.ensureInitialized();
371
-
372
- this.abortController = new AbortController();
373
- const signal = this.abortController.signal;
374
-
375
- const model = options.model || DEFAULT_MODEL;
376
-
377
- if (!this.adapter.supportsModel(model)) {
378
- yield createApiError(`模型 ${model} 未在 LLMConfig.models 中配置`, { code: 'MODEL_NOT_SUPPORTED' });
379
- return;
380
- }
381
-
382
- const modelConfig = this.config.llmConfig.models[model];
383
- if (!modelConfig) {
384
- yield createApiError(`模型 ${model} 未在 LLMConfig.models 中配置`, { code: 'MODEL_NOT_SUPPORTED' });
385
- return;
386
- }
387
- const familyConfig = resolveModelFamilyConfig(model, modelConfig, this.config.llmConfig);
388
- if (!familyConfig) {
389
- yield createApiError(`模型 ${model} 无法解析家族配置`, { code: 'MODEL_NOT_SUPPORTED' });
390
- return;
391
- }
392
-
393
- const supportsThinking = modelConfig.supportsThinking;
394
- // 未传 thinkingMode 时:支持思考的模型默认 enabled(与前端 useChat thinking 默认 true 一致);不支持则 disabled
395
- const rawThinkingMode = options.thinkingMode ?? (supportsThinking ? 'enabled' : 'disabled');
396
- const thinkingMode: ThinkingMode = rawThinkingMode === 'enabled' ? 'enabled' : 'disabled';
397
- const systemPrompt = this.buildSystemPrompt(options);
398
-
399
- const isAskMode = options.mode === 'ask';
400
- const enableSearch = !isAskMode && !!options.enableWebSearch;
401
-
402
- const searchToolNames = enableSearch ? this.getSearchToolNames() : undefined;
403
- const resolveCloudTools = async () => {
404
- if (isAskMode) return [];
405
- const enabledTools = options.resolveEnabledTools
406
- ? await options.resolveEnabledTools()
407
- : options.enabledTools;
408
- return this.getToolDefinitions(enabledTools, searchToolNames);
409
- };
410
- const cloudTools = await resolveCloudTools();
411
-
412
- const userTools = options.userTools || [];
413
- const userToolDefinitions = userTools.map(t => ({
414
- name: t.name,
415
- description: t.description,
416
- parameters: {
417
- ...t.parameters,
418
- required: t.parameters.required || [],
419
- },
420
- }));
421
-
422
- const tools = [...cloudTools, ...userToolDefinitions];
423
-
424
- const clientToolNames = userTools.length > 0
425
- ? new Set(userTools.map(t => t.name))
426
- : undefined;
427
-
428
- const enableThinking = thinkingMode === 'enabled' && supportsThinking;
429
-
430
- const history = options.history || [];
431
-
432
- const context: OrchestratorContext = {
433
- systemPrompt,
434
- history,
435
- tools,
436
- refreshTools: userToolDefinitions.length > 0
437
- ? async () => [...await resolveCloudTools(), ...userToolDefinitions]
438
- : resolveCloudTools,
439
- signal,
440
- images,
441
- clientToolNames,
442
- };
443
-
444
- try {
445
- yield* this.orchestrator.chat(this.adapter, message, context, {
446
- model,
447
- enableThinking,
448
- autoRunConfig: options.autoRunConfig,
449
- maxIterations: options.maxIterations,
450
- maxDurationMs: options.maxDurationMs,
451
- maxToolCalls: options.maxToolCalls,
452
- maxTotalTokens: options.maxTotalTokens,
453
- });
454
- } finally {
455
- this.abortController = null;
456
- }
457
- }
458
-
459
- abort(): void {
460
- if (this.abortController) {
461
- this.abortController.abort();
462
- }
463
- }
464
-
465
- setCwd(dir: string): void {
466
- this.config.cwd = dir;
467
- }
468
-
469
- getConfig(): RuntimeConfig {
470
- return { ...this.config };
471
- }
472
-
473
- getSupportedModels(): ModelOption[] {
474
- return buildModelOptions(this.config.llmConfig);
475
- }
476
-
477
- getMcpConnections(): McpConnectionInfo[] {
478
- return this.toolRuntimeManager.getMcpConnectionInfos();
479
- }
480
-
481
- /**
482
- * 创建内置 summarize 实现
483
- */
484
- private createDefaultSummarize(): ((systemPrompt: string, userPrompt: string, model: string) => Promise<string>) | undefined {
485
- return async (systemPrompt: string, userPrompt: string, model: string): Promise<string> => {
486
- if (!this.adapter.supportsModel(model)) {
487
- throw new Error(`压缩模型 ${model} 无可用路由,请在 LLMConfig.models 中配置`);
488
- }
489
-
490
- const abortController = new AbortController();
491
- const messages = [
492
- { role: 'system' as const, content: systemPrompt },
493
- { role: 'user' as const, content: userPrompt },
494
- ];
495
-
496
- let text = '';
497
- for await (const event of this.adapter.streamOnce(messages, [], {
498
- model,
499
- signal: abortController.signal,
500
- })) {
501
- if (event.type === 'text_delta' && event.delta) {
502
- text += event.delta;
503
- }
504
- if (event.type === 'error') {
505
- throw new Error(event.error ?? '压缩请求失败');
506
- }
507
- }
508
- return text.trim();
509
- };
510
- }
511
-
512
- async destroy(): Promise<void> {
513
- await this.toolRuntimeManager.destroy();
514
- }
515
- }