@huyooo/ai-chat-core 0.2.45 → 0.3.3

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 (247) hide show
  1. package/dist/adapter/index.d.ts +11 -0
  2. package/dist/adapter/index.d.ts.map +1 -0
  3. package/dist/adapter/model-adapter.d.ts +25 -0
  4. package/dist/adapter/model-adapter.d.ts.map +1 -0
  5. package/dist/adapter/model-options.d.ts +53 -0
  6. package/dist/adapter/model-options.d.ts.map +1 -0
  7. package/dist/adapter/types.d.ts +28 -0
  8. package/dist/adapter/types.d.ts.map +1 -0
  9. package/dist/chat-runtime.d.ts +96 -0
  10. package/dist/chat-runtime.d.ts.map +1 -0
  11. package/dist/constants.d.ts +12 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/events.d.ts +605 -1
  14. package/dist/events.d.ts.map +1 -0
  15. package/dist/events.js +1 -1
  16. package/dist/extension/index.d.ts +9 -0
  17. package/dist/extension/index.d.ts.map +1 -0
  18. package/dist/extension/types.d.ts +46 -0
  19. package/dist/extension/types.d.ts.map +1 -0
  20. package/dist/families/index.d.ts +11 -0
  21. package/dist/families/index.d.ts.map +1 -0
  22. package/dist/families/presets.d.ts +31 -0
  23. package/dist/families/presets.d.ts.map +1 -0
  24. package/dist/families/resolver.d.ts +11 -0
  25. package/dist/families/resolver.d.ts.map +1 -0
  26. package/dist/families/types.d.ts +29 -0
  27. package/dist/families/types.d.ts.map +1 -0
  28. package/dist/governance/command-safety.d.ts +34 -0
  29. package/dist/governance/command-safety.d.ts.map +1 -0
  30. package/dist/governance/governance.d.ts +19 -0
  31. package/dist/governance/governance.d.ts.map +1 -0
  32. package/dist/governance/index.d.ts +12 -0
  33. package/dist/governance/index.d.ts.map +1 -0
  34. package/dist/governance/types.d.ts +29 -0
  35. package/dist/governance/types.d.ts.map +1 -0
  36. package/dist/index.d.ts +72 -804
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +51 -1
  39. package/dist/internal/management-args.d.ts +13 -0
  40. package/dist/internal/management-args.d.ts.map +1 -0
  41. package/dist/internal/management-results.d.ts +21 -0
  42. package/dist/internal/management-results.d.ts.map +1 -0
  43. package/dist/llm-config.d.ts +108 -0
  44. package/dist/llm-config.d.ts.map +1 -0
  45. package/dist/logger/core.d.ts +31 -0
  46. package/dist/logger/core.d.ts.map +1 -0
  47. package/dist/logger/index.d.ts +9 -0
  48. package/dist/logger/index.d.ts.map +1 -0
  49. package/dist/orchestrator/compression-handler.d.ts +29 -0
  50. package/dist/orchestrator/compression-handler.d.ts.map +1 -0
  51. package/dist/orchestrator/context-compressor.d.ts +51 -0
  52. package/dist/orchestrator/context-compressor.d.ts.map +1 -0
  53. package/dist/orchestrator/context-summarizer.d.ts +41 -0
  54. package/dist/orchestrator/context-summarizer.d.ts.map +1 -0
  55. package/dist/orchestrator/index.d.ts +12 -0
  56. package/dist/orchestrator/index.d.ts.map +1 -0
  57. package/dist/orchestrator/orchestrator.d.ts +46 -0
  58. package/dist/orchestrator/orchestrator.d.ts.map +1 -0
  59. package/dist/orchestrator/types.d.ts +58 -0
  60. package/dist/orchestrator/types.d.ts.map +1 -0
  61. package/dist/parts/index.d.ts +13 -0
  62. package/dist/parts/index.d.ts.map +1 -0
  63. package/dist/parts/registry.d.ts +11 -0
  64. package/dist/parts/registry.d.ts.map +1 -0
  65. package/dist/parts/summaries.d.ts +9 -0
  66. package/dist/parts/summaries.d.ts.map +1 -0
  67. package/dist/parts/types.d.ts +61 -0
  68. package/dist/parts/types.d.ts.map +1 -0
  69. package/dist/platform.d.ts +17 -0
  70. package/dist/platform.d.ts.map +1 -0
  71. package/dist/platform.js +1 -0
  72. package/dist/protocols/anthropic.d.ts +20 -0
  73. package/dist/protocols/anthropic.d.ts.map +1 -0
  74. package/dist/protocols/ark.d.ts +36 -0
  75. package/dist/protocols/ark.d.ts.map +1 -0
  76. package/dist/protocols/deepseek.d.ts +24 -0
  77. package/dist/protocols/deepseek.d.ts.map +1 -0
  78. package/dist/protocols/error-utils.d.ts +14 -0
  79. package/dist/protocols/error-utils.d.ts.map +1 -0
  80. package/dist/protocols/gemini.d.ts +24 -0
  81. package/dist/protocols/gemini.d.ts.map +1 -0
  82. package/dist/protocols/glm.d.ts +20 -0
  83. package/dist/protocols/glm.d.ts.map +1 -0
  84. package/dist/protocols/grok.d.ts +20 -0
  85. package/dist/protocols/grok.d.ts.map +1 -0
  86. package/dist/protocols/index.d.ts +31 -0
  87. package/dist/protocols/index.d.ts.map +1 -0
  88. package/dist/protocols/minimax.d.ts +38 -0
  89. package/dist/protocols/minimax.d.ts.map +1 -0
  90. package/dist/protocols/moonshot.d.ts +20 -0
  91. package/dist/protocols/moonshot.d.ts.map +1 -0
  92. package/dist/protocols/openai-sse.d.ts +33 -0
  93. package/dist/protocols/openai-sse.d.ts.map +1 -0
  94. package/dist/protocols/openai.d.ts +19 -0
  95. package/dist/protocols/openai.d.ts.map +1 -0
  96. package/dist/protocols/qwen.d.ts +26 -0
  97. package/dist/protocols/qwen.d.ts.map +1 -0
  98. package/dist/protocols/responses-sse.d.ts +30 -0
  99. package/dist/protocols/responses-sse.d.ts.map +1 -0
  100. package/dist/protocols/sse-reader.d.ts +23 -0
  101. package/dist/protocols/sse-reader.d.ts.map +1 -0
  102. package/dist/protocols/tool-arguments.d.ts +8 -0
  103. package/dist/protocols/tool-arguments.d.ts.map +1 -0
  104. package/dist/protocols/types.d.ts +148 -0
  105. package/dist/protocols/types.d.ts.map +1 -0
  106. package/dist/protocols/vercel-gateway.d.ts +15 -0
  107. package/dist/protocols/vercel-gateway.d.ts.map +1 -0
  108. package/dist/runtime.d.ts +151 -0
  109. package/dist/runtime.d.ts.map +1 -0
  110. package/dist/runtime.js +1 -0
  111. package/dist/skills/index.d.ts +14 -0
  112. package/dist/skills/index.d.ts.map +1 -0
  113. package/dist/skills/management/admin.d.ts +10 -0
  114. package/dist/skills/management/admin.d.ts.map +1 -0
  115. package/dist/skills/management/index.d.ts +11 -0
  116. package/dist/skills/management/index.d.ts.map +1 -0
  117. package/dist/skills/management/inputs.d.ts +44 -0
  118. package/dist/skills/management/inputs.d.ts.map +1 -0
  119. package/dist/skills/management/operations.d.ts +78 -0
  120. package/dist/skills/management/operations.d.ts.map +1 -0
  121. package/dist/skills/management/types.d.ts +70 -0
  122. package/dist/skills/management/types.d.ts.map +1 -0
  123. package/dist/skills/registry.d.ts +37 -0
  124. package/dist/skills/registry.d.ts.map +1 -0
  125. package/dist/skills/summaries.d.ts +9 -0
  126. package/dist/skills/summaries.d.ts.map +1 -0
  127. package/dist/skills/types.d.ts +61 -0
  128. package/dist/skills/types.d.ts.map +1 -0
  129. package/dist/test-utils/mock-sse.d.ts +13 -0
  130. package/dist/test-utils/mock-sse.d.ts.map +1 -0
  131. package/dist/tool-manager/define-tool.d.ts +35 -0
  132. package/dist/tool-manager/define-tool.d.ts.map +1 -0
  133. package/dist/tool-manager/formats.d.ts +46 -0
  134. package/dist/tool-manager/formats.d.ts.map +1 -0
  135. package/dist/tool-manager/identity.d.ts +18 -0
  136. package/dist/tool-manager/identity.d.ts.map +1 -0
  137. package/dist/tool-manager/in-process-provider.d.ts +15 -0
  138. package/dist/tool-manager/in-process-provider.d.ts.map +1 -0
  139. package/dist/tool-manager/index.d.ts +18 -0
  140. package/dist/tool-manager/index.d.ts.map +1 -0
  141. package/dist/tool-manager/manager.d.ts +18 -0
  142. package/dist/tool-manager/manager.d.ts.map +1 -0
  143. package/dist/tool-manager/mcp-provider.d.ts +21 -0
  144. package/dist/tool-manager/mcp-provider.d.ts.map +1 -0
  145. package/dist/tool-manager/summaries.d.ts +39 -0
  146. package/dist/tool-manager/summaries.d.ts.map +1 -0
  147. package/dist/tool-manager/types.d.ts +314 -0
  148. package/dist/tool-manager/types.d.ts.map +1 -0
  149. package/dist/types.d.ts +663 -0
  150. package/dist/types.d.ts.map +1 -0
  151. package/package.json +26 -15
  152. package/src/adapter/index.ts +25 -0
  153. package/src/adapter/model-adapter.ts +196 -0
  154. package/src/adapter/model-options.ts +143 -0
  155. package/src/adapter/types.ts +41 -0
  156. package/src/chat-runtime.ts +515 -0
  157. package/src/constants.ts +9 -102
  158. package/src/events.ts +364 -150
  159. package/src/extension/index.ts +24 -0
  160. package/src/extension/types.ts +49 -0
  161. package/src/families/index.ts +28 -0
  162. package/src/families/presets.ts +124 -0
  163. package/src/families/resolver.ts +22 -0
  164. package/src/families/types.ts +55 -0
  165. package/src/governance/command-safety.ts +224 -0
  166. package/src/governance/governance.ts +125 -0
  167. package/src/governance/index.ts +38 -0
  168. package/src/governance/types.ts +44 -0
  169. package/src/index.ts +250 -145
  170. package/src/internal/management-args.ts +39 -0
  171. package/src/internal/management-results.ts +60 -0
  172. package/src/llm-config.ts +137 -0
  173. package/src/logger/core.ts +96 -0
  174. package/src/logger/index.ts +8 -0
  175. package/src/orchestrator/compression-handler.ts +137 -0
  176. package/src/{providers → orchestrator}/context-compressor.ts +79 -47
  177. package/src/orchestrator/context-summarizer.ts +123 -0
  178. package/src/orchestrator/index.ts +20 -0
  179. package/src/orchestrator/orchestrator.ts +1002 -0
  180. package/src/orchestrator/types.ts +70 -0
  181. package/src/parts/index.ts +20 -0
  182. package/src/parts/registry.ts +95 -0
  183. package/src/parts/summaries.ts +40 -0
  184. package/src/parts/types.ts +63 -0
  185. package/src/platform.ts +73 -0
  186. package/src/protocols/anthropic.ts +377 -0
  187. package/src/protocols/ark.ts +300 -0
  188. package/src/protocols/deepseek.ts +192 -0
  189. package/src/{providers/protocols → protocols}/error-utils.ts +17 -20
  190. package/src/protocols/gemini.ts +352 -0
  191. package/src/protocols/glm.ts +212 -0
  192. package/src/protocols/grok.ts +98 -0
  193. package/src/protocols/index.ts +48 -0
  194. package/src/protocols/minimax.ts +308 -0
  195. package/src/protocols/moonshot.ts +186 -0
  196. package/src/protocols/openai-sse.ts +156 -0
  197. package/src/protocols/openai.ts +97 -0
  198. package/src/protocols/qwen.ts +358 -0
  199. package/src/protocols/responses-sse.ts +224 -0
  200. package/src/protocols/sse-reader.ts +54 -0
  201. package/src/protocols/tool-arguments.ts +32 -0
  202. package/src/{providers/protocols → protocols}/types.ts +46 -37
  203. package/src/protocols/vercel-gateway.ts +391 -0
  204. package/src/runtime.ts +167 -0
  205. package/src/skills/index.ts +29 -0
  206. package/src/skills/management/admin.ts +170 -0
  207. package/src/skills/management/index.ts +27 -0
  208. package/src/skills/management/inputs.ts +79 -0
  209. package/src/skills/management/operations.ts +256 -0
  210. package/src/skills/management/types.ts +57 -0
  211. package/src/skills/registry.ts +120 -0
  212. package/src/skills/summaries.ts +48 -0
  213. package/src/skills/types.ts +65 -0
  214. package/src/test-utils/mock-sse.ts +3 -3
  215. package/src/tool-manager/define-tool.ts +201 -0
  216. package/src/tool-manager/formats.ts +146 -0
  217. package/src/tool-manager/identity.ts +80 -0
  218. package/src/tool-manager/in-process-provider.ts +164 -0
  219. package/src/tool-manager/index.ts +63 -0
  220. package/src/tool-manager/manager.ts +562 -0
  221. package/src/tool-manager/mcp-provider.ts +509 -0
  222. package/src/tool-manager/summaries.ts +136 -0
  223. package/src/tool-manager/types.ts +389 -0
  224. package/src/types.ts +750 -191
  225. package/dist/events-CU5D5ray.d.ts +0 -1128
  226. package/src/agent.ts +0 -409
  227. package/src/internal/update-plan.ts +0 -2
  228. package/src/internal/web-search.ts +0 -77
  229. package/src/mcp/client-manager.ts +0 -302
  230. package/src/mcp/index.ts +0 -2
  231. package/src/mcp/types.ts +0 -43
  232. package/src/providers/context-summarizer.ts +0 -70
  233. package/src/providers/index.ts +0 -125
  234. package/src/providers/model-registry.ts +0 -466
  235. package/src/providers/orchestrator.ts +0 -839
  236. package/src/providers/protocols/anthropic.ts +0 -406
  237. package/src/providers/protocols/ark.ts +0 -362
  238. package/src/providers/protocols/deepseek.ts +0 -344
  239. package/src/providers/protocols/gemini.ts +0 -350
  240. package/src/providers/protocols/index.ts +0 -36
  241. package/src/providers/protocols/openai.ts +0 -420
  242. package/src/providers/protocols/qwen.ts +0 -315
  243. package/src/providers/types.ts +0 -264
  244. package/src/providers/unified-adapter.ts +0 -367
  245. package/src/router.ts +0 -72
  246. package/src/tools.ts +0 -162
  247. package/src/utils.ts +0 -86
package/src/types.ts CHANGED
@@ -1,90 +1,30 @@
1
1
  /**
2
- * AI Chat Core 类型定义
2
+ * AI Chat Core 公共类型定义
3
+ *
4
+ * - Agent / Chat 配置、消息与工具契约(含 JSON Schema、ToolResult 信封)
5
+ * - 与治理、MCP、Skills 等模块共享的跨层类型入口
6
+ * - 不包含协议层与编排器专用类型(见 protocols/、orchestrator/types)
3
7
  */
4
8
 
5
- import type { McpServerConfig } from './mcp/types';
6
- import {
7
- getVisibleModels,
8
- getModelFamily,
9
- getModelEntry,
10
- modelSupportsThinking,
11
- modelSupportsVision,
12
- modelSupportsNativeSearch,
13
- getModelSearchStrategy,
14
- type ModelRegistryEntry,
15
- } from './providers/model-registry';
16
- import type { ProviderType } from './router';
9
+ import type {
10
+ AssetApprovalPolicy,
11
+ AssetHostDependency,
12
+ AssetSideEffectLevel,
13
+ AssetSource,
14
+ } from './governance/types';
15
+ import type { McpServerConfig } from './tool-manager/types';
16
+ import { Kind, Type, type TSchema } from '@sinclair/typebox';
17
17
 
18
18
  // ==================== 模式与模型 ====================
19
19
 
20
20
  /** 对话模式 */
21
21
  export type ChatMode = 'agent' | 'ask';
22
22
 
23
- // 重新导出 router Model Registry 类型
24
- export type { ProviderType };
25
- export type { ModelFamilyId, ModelFamilyConfig, ModelRegistryEntry } from './providers/model-registry';
26
- export { getModelFamily, getModelEntry, modelSupportsThinking, modelSupportsNativeSearch, getModelSearchStrategy };
27
-
28
- /** 模型选项(前端显示用) */
29
- export interface ModelOption {
30
- /** 模型 ID(发送给 API) */
31
- modelId: string;
32
- /** 显示名称 */
33
- displayName: string;
34
- /** 是否支持深度思考 */
35
- supportsThinking: boolean;
36
- /** 是否支持图片理解 */
37
- supportsVision: boolean;
38
- /** 用于模型项 hover 的特性描述(由后端定义,前端只渲染) */
39
- tooltip?: {
40
- features?: string[];
41
- /** 开销信息(数组,分行显示) */
42
- cost?: string[];
43
- description?: string;
44
- };
45
- }
46
-
47
- /** 生成模型 tooltip 的 features 列表 */
48
- function buildModelFeatures(entry: ModelRegistryEntry): string[] {
49
- const family = getModelFamily(entry.id);
50
- const supportsVision = modelSupportsVision(entry.id);
51
- const supportsThinking = family?.supportsThinking ?? false;
52
- const supportsNativeSearch = family?.supportsNativeSearch ?? false;
53
-
54
- const features: string[] = [];
55
- // 顺序:多模态 > 深度思考 > 长上下文 > 联网搜索
56
- if (supportsVision) features.push('多模态');
57
- if (supportsThinking) features.push('深度思考');
58
- if (entry.contextWindow) features.push(`长上下文(${entry.contextWindow})`);
59
- if (supportsNativeSearch) features.push('联网搜索');
60
-
61
- return features;
62
- }
63
-
64
- /**
65
- * 预定义模型列表
66
- */
67
- export const MODELS: ModelOption[] = getVisibleModels().map(entry => {
68
- const family = getModelFamily(entry.id);
69
- const supportsThinking = family?.supportsThinking ?? false;
70
- const supportsVision = modelSupportsVision(entry.id);
71
-
72
- return {
73
- modelId: entry.id,
74
- displayName: entry.displayName,
75
- supportsThinking,
76
- supportsVision,
77
- tooltip: {
78
- features: buildModelFeatures(entry),
79
- cost: entry.pricing,
80
- },
81
- };
82
- });
23
+ export type { ModelFamilyId, ModelFamilyConfig } from './families';
24
+ import type { ProtocolId } from './protocols';
25
+ export type { ProtocolId } from './protocols';
83
26
 
84
- /** 根据 modelId 获取模型 */
85
- export function getModelByModelId(modelId: string): ModelOption | undefined {
86
- return MODELS.find(m => m.modelId === modelId);
87
- }
27
+ export type { ModelOption } from './adapter';
88
28
 
89
29
  // ==================== 配置 ====================
90
30
 
@@ -92,47 +32,73 @@ export function getModelByModelId(modelId: string): ModelOption | undefined {
92
32
  export type ToolApprovalCallback = (toolCall: {
93
33
  id: string;
94
34
  name: string;
35
+ toolName?: string;
36
+ extensionId?: string;
37
+ alias?: string;
38
+ displayName?: string;
95
39
  args: Record<string, unknown>;
96
40
  }) => Promise<boolean>;
97
41
 
42
+ /** 宿主应用注入的工具执行审计钩子 */
43
+ export interface ToolExecutionAuditHooks {
44
+ startToolCall(input: {
45
+ id?: string | null;
46
+ traceId: string;
47
+ extensionId?: string | null;
48
+ toolName: string;
49
+ displayName?: string | null;
50
+ source?: AssetSource | string | null;
51
+ cwd?: string | null;
52
+ args?: unknown;
53
+ approvalPolicy?: AssetApprovalPolicy | string | null;
54
+ sideEffectLevel?: AssetSideEffectLevel | string | null;
55
+ hostDependency?: AssetHostDependency | string | null;
56
+ metadata?: Record<string, unknown>;
57
+ }): string;
58
+ finishToolCall(input: {
59
+ toolCallId: string;
60
+ traceId: string;
61
+ result?: unknown;
62
+ completedAt?: string;
63
+ }): void;
64
+ failToolCall(input: {
65
+ toolCallId: string;
66
+ traceId: string;
67
+ error: unknown;
68
+ completedAt?: string;
69
+ }): void;
70
+ runWithContext<T>(
71
+ context: {
72
+ conversationId?: string | null;
73
+ turnId?: string | null;
74
+ toolCallId?: string | null;
75
+ traceId?: string | null;
76
+ },
77
+ fn: () => T,
78
+ ): T;
79
+ }
80
+
98
81
  /** Agent 配置 */
99
82
  export interface AgentConfig {
100
- /** 豆包/火山引擎 API Key (用于豆包和 DeepSeek) */
101
- arkApiKey: string;
102
- /** 豆包 API URL */
103
- arkApiUrl?: string;
104
- /** 通义千问 API Key */
105
- qwenApiKey?: string;
106
- /** 通义千问 API URL */
107
- qwenApiUrl?: string;
108
- /** OpenRouter API Key */
109
- openrouterApiKey?: string;
110
- /** OpenRouter API URL */
111
- openrouterApiUrl?: string;
112
- /** Vercel API Key(用于 Vercel AI Gateway 访问 Claude) */
113
- vercelApiKey?: string;
114
- /** Tavily API Key(用于统一 Web Search) */
115
- tavilyApiKey?: string;
116
- /** Gemini API Key (用于图片/视频,注意:中国大陆无法直接访问) */
117
- geminiApiKey: string;
118
- /** 当前工作目录(Current Working Directory) */
119
- cwd?: string;
83
+ /** 统一 LLM 配置(endpoints + models 降级链) */
84
+ llmConfig: import('./llm-config').LLMConfig;
85
+ /** 当前工作目录(必传,浏览器安全:不使用 process.cwd()) */
86
+ cwd: string;
87
+ /** 最大模型轮次(可选,默认不限制) */
88
+ maxIterations?: number;
89
+ /** 最大总执行时长,单位毫秒(可选,默认不限制) */
90
+ maxDurationMs?: number;
91
+ /** 最大工具调用次数(可选,默认不限制) */
92
+ maxToolCalls?: number;
93
+ /** 最大累计 token 数(可选,默认不限制) */
94
+ maxTotalTokens?: number;
120
95
  /**
121
96
  * 工具列表(Vite 插件风格)
122
97
  *
123
98
  * 支持多种形式:
124
- * - 单个工具:getCwdTool
99
+ * - 单个工具:getEnvironmentTool()
125
100
  * - 工具插件:searchPlugin({ dataDir, workspace })
126
101
  * - Promise:await asyncPlugin()
127
- *
128
- * @example
129
- * ```typescript
130
- * tools: [
131
- * getCwdTool,
132
- * executeCommandTool,
133
- * searchPlugin({ dataDir: '/path', workspace: '/project' }),
134
- * ]
135
- * ```
136
102
  */
137
103
  tools?: ToolConfigItem[];
138
104
  /**
@@ -149,28 +115,18 @@ export interface AgentConfig {
149
115
  * MCP Server 配置列表
150
116
  *
151
117
  * 初始化时自动连接所有 MCP Server,发现工具并注册到 Agent。
152
- *
153
- * @example
154
- * ```typescript
155
- * mcpServers: [
156
- * { name: 'filesystem', transport: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/Users/me'] },
157
- * { name: 'github', transport: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-github'], env: { GITHUB_TOKEN: '...' } },
158
- * { name: 'remote-db', transport: 'sse', url: 'http://localhost:3001/mcp' },
159
- * ]
160
- * ```
161
118
  */
162
119
  mcpServers?: McpServerConfig[];
163
120
  /**
164
- * 上下文总结回调(走 ai-server 等外部服务)
165
- *
166
- * 当对话历史超过模型 context window 时,orchestrator 调用此函数执行 AI 总结。
167
- * 宿主提供实现(如 smart-finder 的 toolAI),ai-chat-core 不关心具体调用方式。
168
- *
169
- * @param systemPrompt 总结指令
170
- * @param userPrompt 格式化后的中间对话历史
171
- * @returns 总结后的文本
121
+ * 宿主应用注入的数据引擎接口(可选)。
122
+ * 传递给 ToolContext.dataEngine,使所有工具可访问平台数据能力。
172
123
  */
173
- summarize?: (systemPrompt: string, userPrompt: string) => Promise<string>;
124
+ dataEngine?: DataEngineContext;
125
+ /**
126
+ * 宿主应用注入的工具执行审计钩子。
127
+ * 位于 ChatRuntime.executeTool 根入口,覆盖 in-process、MCP 和未来 provider。
128
+ */
129
+ audit?: ToolExecutionAuditHooks;
174
130
  }
175
131
 
176
132
  /** 深度思考模式 */
@@ -189,12 +145,6 @@ export interface AutoRunConfig {
189
145
  mode?: AutoRunMode;
190
146
  }
191
147
 
192
- /** 聊天消息格式(用于传递历史) */
193
- export interface ChatHistoryMessage {
194
- role: 'user' | 'assistant' | 'system' | 'tool';
195
- content: string;
196
- }
197
-
198
148
  /**
199
149
  * 用户工具定义(透传模式)
200
150
  *
@@ -208,6 +158,12 @@ export interface UserToolDefinition {
208
158
  description: string;
209
159
  /** 参数定义(JSON Schema,支持嵌套) */
210
160
  parameters: JsonSchemaObject;
161
+ /** 成功时 data 内的业务结构(JSON Schema,可选) */
162
+ outputSchema?: JsonSchemaObject;
163
+ /** 成功返回标准信封结构(JSON Schema,可选,由 outputSchema 自动生成) */
164
+ resolvedOutputSchema?: JsonSchemaObject;
165
+ /** 标准错误返回结构(JSON Schema,可选;不传则使用平台默认错误结构) */
166
+ errorSchema?: JsonSchemaObject;
211
167
  }
212
168
 
213
169
  /** 聊天配置(每次聊天可变的选项) */
@@ -217,7 +173,7 @@ export interface ChatOptions {
217
173
  /** 使用的模型 */
218
174
  model?: string;
219
175
  /** 模型提供商 */
220
- provider?: ProviderType;
176
+ provider?: ProtocolId;
221
177
  /** 是否启用联网搜索 */
222
178
  enableWebSearch?: boolean;
223
179
  /**
@@ -228,10 +184,23 @@ export interface ChatOptions {
228
184
  thinkingMode?: ThinkingMode;
229
185
  /** 启用的工具名称列表(agent 模式有效,ask 模式强制禁用) */
230
186
  enabledTools?: string[];
187
+ /**
188
+ * 宿主侧动态工具选择解析器。
189
+ * 每次模型迭代前调用,用于让 tool_enable 这类管理工具在同一轮 agent loop 的下一次模型请求生效。
190
+ */
191
+ resolveEnabledTools?: () => Promise<string[] | undefined>;
231
192
  /** 自动运行配置 */
232
193
  autoRunConfig?: AutoRunConfig;
233
- /** 对话历史(从数据库加载,无状态架构) */
234
- history?: ChatHistoryMessage[];
194
+ /** 单次运行最大模型轮次;不传则使用运行时默认值 */
195
+ maxIterations?: number;
196
+ /** 单次运行最大时长(毫秒);不传则使用运行时默认值 */
197
+ maxDurationMs?: number;
198
+ /** 单次运行最大工具调用次数;不传则使用运行时默认值 */
199
+ maxToolCalls?: number;
200
+ /** 单次运行最大累计 Token;不传则使用运行时默认值 */
201
+ maxTotalTokens?: number;
202
+ /** 对话历史(从数据库加载,无状态架构,需包含完整 tool_calls / tool_call_id) */
203
+ history?: ChatMessage[];
235
204
  /**
236
205
  * 用户自定义工具(透传模式)
237
206
  *
@@ -253,7 +222,7 @@ export interface ChatOptions {
253
222
  /**
254
223
  * 宿主平台提示词(可选)
255
224
  *
256
- * 由宿主应用(如 smart-finder)注入的平台特定 system prompt 扩展。
225
+ * 由宿主应用(如 SuperX)注入的平台特定 system prompt 扩展。
257
226
  * 用于描述平台特有的能力、工具编排、记忆管理等,避免在核心库中硬编码具体工具名。
258
227
  *
259
228
  * 注入位置:基础 prompt 之后、Skills 内容之前。
@@ -275,7 +244,7 @@ export interface ChatOptions {
275
244
 
276
245
  // ==================== 工具相关 ====================
277
246
 
278
- /** 前端渲染组件类型(可扩展) */
247
+ /** 前端渲染组件类型:内置若干枚举,扩展 Part 使用与 `parts/<name>` 一致的任意字符串 */
279
248
  export type RenderType = 'weather' | 'chart' | 'browser' | 'plan' | string;
280
249
 
281
250
  /** 前端动作类型(可扩展) */
@@ -287,7 +256,26 @@ export type ActionType = 'toast' | 'notification' | 'reload' | string;
287
256
  * - action: 触发前端动作(通知、刷新等)
288
257
  */
289
258
  export type ToolUI =
290
- | { type: 'render'; name: RenderType; props?: Record<string, unknown> }
259
+ | {
260
+ type: 'render';
261
+ name: RenderType;
262
+ props?: Record<string, unknown>;
263
+ /**
264
+ * 仅在 tool_call_result 成功后再创建 render Part。
265
+ *
266
+ * 适用于“结果导向”的卡片:
267
+ * - 运行中没有稳定可展示内容
268
+ * - 最终结果可能被动态抑制(例如 no-op)
269
+ */
270
+ renderOnResultOnly?: boolean;
271
+ /**
272
+ * 消息内唯一实例(如 plan 进度面板)
273
+ *
274
+ * - true: 同类型 Part 在一条消息中只存在一个,多次调用同一工具时就地更新
275
+ * - false/undefined: 每次调用创建独立 Part(如天气卡片、搜索结果)
276
+ */
277
+ singleton?: boolean;
278
+ }
291
279
  | { type: 'action'; name: ActionType };
292
280
 
293
281
  /** Shell 命令执行结果 */
@@ -297,19 +285,331 @@ export interface ExecResult {
297
285
  exitCode: number;
298
286
  }
299
287
 
288
+ export interface ExecOptions {
289
+ timeout?: number;
290
+ }
291
+
300
292
  /** 工具执行上下文 */
301
293
  export interface ToolContext {
294
+ /** 当前模型工具调用 ID(由编排器注入,供宿主审计/关联使用) */
295
+ toolCallId?: string;
296
+ /** 当前模型工具调用名称(由编排器注入,供宿主审计/关联使用) */
297
+ toolName?: string;
302
298
  /** 当前工作目录(可选,工具需要时由框架注入) */
303
299
  cwd?: string;
300
+ /**
301
+ * 当前模型回合允许调用的工具名。
302
+ * 管理类工具必须用它约束搜索、查看和启用范围,避免绕过会话能力选择。
303
+ */
304
+ allowedToolNames?: readonly string[];
304
305
  /** 执行 Shell 命令(可选,工具需要时由框架注入) */
305
- exec?: (cmd: string, args?: string[]) => Promise<ExecResult>;
306
+ exec?: (cmd: string, args?: string[], options?: ExecOptions) => Promise<ExecResult>;
306
307
  /** 中断信号(用于取消长时间操作) */
307
308
  signal?: AbortSignal;
309
+ /** 向对话流推送 stdout 增量(可选) */
310
+ onStdout?: (chunk: string) => void;
311
+ /** 向对话流推送 stderr 增量(可选) */
312
+ onStderr?: (chunk: string) => void;
313
+ /**
314
+ * 宿主应用注入的数据引擎接口(可选)。
315
+ * 市场扩展工具可通过此接口访问数据库、搜索引擎等平台能力。
316
+ */
317
+ dataEngine?: DataEngineContext;
318
+ }
319
+
320
+ /** 数据引擎上下文 — 宿主应用按需注入 */
321
+ export interface DataEngineContext {
322
+ /** 按名称获取 SQLite 只读连接,用于查询已注册数据库 */
323
+ queryDb: (dbName: string, sql: string, params?: unknown[]) => { columns: string[]; rows: Record<string, unknown>[] };
324
+ /** 列出所有可用数据集(SQLite + Vector + FullText) */
325
+ listDatasets: () => Array<{
326
+ id?: string
327
+ name: string
328
+ storageKind: string
329
+ owner: { ownerType: string; ownerKey: string }
330
+ workspaceKey?: string | null
331
+ customScope?: Record<string, unknown> | null
332
+ description: string
333
+ queryHint?: string
334
+ path?: string
335
+ capabilities?: {
336
+ readable: boolean
337
+ writable: boolean
338
+ queryable: boolean
339
+ searchable?: boolean
340
+ recoverable: boolean
341
+ }
342
+ }>;
343
+ /** 跨数据库关键词搜索 */
344
+ searchAll: (
345
+ keyword: string,
346
+ opts?: {
347
+ ownerType?: string
348
+ ownerKey?: string
349
+ workspaceKey?: string
350
+ storageKind?: string
351
+ mode?: 'exact' | 'semantic' | 'fulltext' | 'hybrid'
352
+ limit?: number
353
+ },
354
+ ) => Array<{
355
+ database: string
356
+ table: string
357
+ row: Record<string, unknown>
358
+ resourceName?: string
359
+ storageKind?: string
360
+ matchType?: string
361
+ score?: number
362
+ path?: string
363
+ snippet?: string
364
+ }> | Promise<Array<{
365
+ database: string
366
+ table: string
367
+ row: Record<string, unknown>
368
+ resourceName?: string
369
+ storageKind?: string
370
+ matchType?: string
371
+ score?: number
372
+ path?: string
373
+ snippet?: string
374
+ }>>;
375
+ }
376
+
377
+ // ==================== 工具结果 ====================
378
+
379
+ /** 统一工具结果信封 */
380
+ export interface ToolResult {
381
+ /** 结构化业务数据。序列化后固定放在 data 字段内。 */
382
+ data?: Record<string, unknown>;
383
+ /** 给用户和模型看的简短说明。序列化后固定放在 message 字段内。 */
384
+ message?: string;
385
+ /** @deprecated 使用 message。保留给旧内部调用,序列化时会映射到 message。 */
386
+ text?: string;
387
+ /** 精简摘要,帮助模型快速理解工具结果 */
388
+ _summary?: string;
389
+ /** 附加元数据(调试/埋点/来源信息) */
390
+ metadata?: Record<string, unknown>;
391
+ }
392
+
393
+ export type ToolSuccess<TData extends Record<string, unknown> = Record<string, unknown>> = {
394
+ status: 'ok';
395
+ data: TData;
396
+ message?: string;
397
+ };
398
+
399
+ export function toolOk<TData extends Record<string, unknown>>(
400
+ data: TData,
401
+ message?: string,
402
+ ): ToolResult {
403
+ return {
404
+ data,
405
+ message,
406
+ };
407
+ }
408
+
409
+ export function textToolResult(
410
+ text: string,
411
+ options: { summary?: string; metadata?: Record<string, unknown> } = {},
412
+ ): ToolResult {
413
+ return {
414
+ message: text,
415
+ _summary: options.summary,
416
+ metadata: options.metadata,
417
+ };
418
+ }
419
+
420
+ export function dataToolResult(
421
+ data: Record<string, unknown>,
422
+ options: { text?: string; summary?: string; metadata?: Record<string, unknown> } = {},
423
+ ): ToolResult {
424
+ return {
425
+ data,
426
+ message: options.text,
427
+ _summary: options.summary,
428
+ metadata: options.metadata,
429
+ };
430
+ }
431
+
432
+ export function emptyToolResult(
433
+ options: { summary?: string; metadata?: Record<string, unknown> } = {},
434
+ ): ToolResult {
435
+ return {
436
+ text: undefined,
437
+ _summary: options.summary,
438
+ metadata: options.metadata,
439
+ };
440
+ }
441
+
442
+ export interface ToolGovernanceSnapshot {
443
+ approvalPolicy?: AssetApprovalPolicy;
444
+ sideEffectLevel?: AssetSideEffectLevel;
445
+ hostDependency?: AssetHostDependency;
446
+ riskSummary?: string;
447
+ riskTags?: string[];
448
+ riskSignals?: string[];
449
+ }
450
+
451
+ /** 工具执行允许返回的值 */
452
+ export type ToolExecuteResult = ToolResult | Record<string, unknown>;
453
+
454
+ function isRecord(value: unknown): value is Record<string, unknown> {
455
+ return typeof value === 'object' && value !== null;
456
+ }
457
+
458
+ /** 判断对象是否已经是 ToolResult 信封 */
459
+ export function isToolResult(value: unknown): value is ToolResult {
460
+ if (!isRecord(value)) return false;
461
+ return (
462
+ 'data' in value ||
463
+ 'message' in value ||
464
+ 'text' in value ||
465
+ '_summary' in value ||
466
+ 'metadata' in value
467
+ );
468
+ }
469
+
470
+ /** 规范化工具结果为统一信封 */
471
+ export function normalizeToolResult(value: ToolExecuteResult | undefined): ToolResult {
472
+ if (!value) return { data: {} };
473
+ if (isToolResult(value)) return value;
474
+ return { data: value };
475
+ }
476
+
477
+ /**
478
+ * 将 ToolResult 序列化为给 LLM / 事件系统使用的最终对象。
479
+ *
480
+ * 设计原则:
481
+ * - 成功结果统一返回 status/data/message envelope。
482
+ * - 业务字段一律位于 data 内,避免与平台协议字段冲突。
483
+ */
484
+ export function serializeToolResult(result: ToolResult): Record<string, unknown> {
485
+ const output: Record<string, unknown> = {
486
+ status: 'ok',
487
+ data: result.data ?? {},
488
+ };
489
+ const message = result.message ?? result.text;
490
+ if (message !== undefined) output.message = message;
491
+ if (result._summary !== undefined) output._summary = result._summary;
492
+ if (result.metadata !== undefined) output._meta = result.metadata;
493
+ return output;
494
+ }
495
+
496
+ function isToolUi(value: unknown): value is ToolUI {
497
+ if (!isRecord(value)) return false;
498
+ if (value.type === 'action') {
499
+ return typeof value.name === 'string';
500
+ }
501
+ if (value.type === 'render') {
502
+ return typeof value.name === 'string';
503
+ }
504
+ return false;
505
+ }
506
+
507
+ /**
508
+ * 解析单次工具执行最终应使用的 UI。
509
+ *
510
+ * 规则:
511
+ * - 默认沿用工具静态声明的 ui
512
+ * - result.metadata.ui 可覆盖静态 ui
513
+ * - result.metadata.ui === null 表示这次显式不渲染任何 render/action ui
514
+ */
515
+ export function resolveToolResultUi(
516
+ result: ToolResult,
517
+ fallback?: ToolUI,
518
+ ): ToolUI | undefined {
519
+ const metadata = result.metadata;
520
+ if (!metadata || !Object.prototype.hasOwnProperty.call(metadata, 'ui')) {
521
+ return fallback;
522
+ }
523
+
524
+ const override = metadata.ui;
525
+ if (override == null) {
526
+ return undefined;
527
+ }
528
+
529
+ return isToolUi(override) ? override : fallback;
530
+ }
531
+
532
+ function mergeApprovalPolicy(
533
+ left?: AssetApprovalPolicy,
534
+ right?: AssetApprovalPolicy,
535
+ ) {
536
+ const order: Record<NonNullable<typeof left>, number> = {
537
+ auto: 0,
538
+ 'destructive-only': 1,
539
+ manual: 2,
540
+ };
541
+ if (!left) return right;
542
+ if (!right) return left;
543
+ return order[left] >= order[right] ? left : right;
544
+ }
545
+
546
+ function mergeSideEffectLevel(
547
+ left?: AssetSideEffectLevel,
548
+ right?: AssetSideEffectLevel,
549
+ ) {
550
+ const order: Record<NonNullable<typeof left>, number> = {
551
+ read: 0,
552
+ write: 1,
553
+ destructive: 2,
554
+ };
555
+ if (!left) return right;
556
+ if (!right) return left;
557
+ return order[left] >= order[right] ? left : right;
558
+ }
559
+
560
+ function mergeHostDependency(
561
+ left?: AssetHostDependency,
562
+ right?: AssetHostDependency,
563
+ ) {
564
+ const order: Record<NonNullable<typeof left>, number> = {
565
+ none: 0,
566
+ 'local-app': 1,
567
+ 'os-service': 2,
568
+ 'remote-service': 3,
569
+ };
570
+ if (!left) return right;
571
+ if (!right) return left;
572
+ return order[left] >= order[right] ? left : right;
573
+ }
574
+
575
+ /** 合并静态治理与基于输入参数的动态治理,始终选择更严格的一侧。 */
576
+ export function mergeToolGovernance(
577
+ base?: ToolGovernanceSnapshot,
578
+ override?: ToolGovernanceSnapshot,
579
+ ): ToolGovernanceSnapshot {
580
+ return {
581
+ approvalPolicy: mergeApprovalPolicy(base?.approvalPolicy, override?.approvalPolicy),
582
+ sideEffectLevel: mergeSideEffectLevel(base?.sideEffectLevel, override?.sideEffectLevel),
583
+ hostDependency: mergeHostDependency(base?.hostDependency, override?.hostDependency),
584
+ riskSummary: override?.riskSummary ?? base?.riskSummary,
585
+ riskTags: override?.riskTags ?? base?.riskTags,
586
+ riskSignals: override?.riskSignals ?? base?.riskSignals,
587
+ };
588
+ }
589
+
590
+ /**
591
+ * 基于工具静态声明和本次输入参数,解析执行前应展示/判断的治理信息。
592
+ */
593
+ export async function resolveToolGovernanceSnapshot(
594
+ tool: Pick<Tool, 'approvalPolicy' | 'sideEffectLevel' | 'hostDependency' | 'assessInputGovernance'> | undefined,
595
+ args: Record<string, unknown>,
596
+ ): Promise<ToolGovernanceSnapshot> {
597
+ const staticGovernance: ToolGovernanceSnapshot = tool
598
+ ? {
599
+ approvalPolicy: tool.approvalPolicy,
600
+ sideEffectLevel: tool.sideEffectLevel,
601
+ hostDependency: tool.hostDependency,
602
+ }
603
+ : {};
604
+ const dynamicGovernance = tool?.assessInputGovernance
605
+ ? await tool.assessInputGovernance(args)
606
+ : undefined;
607
+ return mergeToolGovernance(staticGovernance, dynamicGovernance);
308
608
  }
309
609
 
310
610
  // ==================== 工具错误 ====================
311
611
 
312
- /** 工具错误码 */
612
+ /** 工具错误码(预定义 + 可扩展) */
313
613
  export type ToolErrorCode =
314
614
  | 'INVALID_PARAMS'
315
615
  | 'NOT_FOUND'
@@ -317,63 +617,72 @@ export type ToolErrorCode =
317
617
  | 'OPERATION_FAILED'
318
618
  | 'TIMEOUT'
319
619
  | 'NETWORK_ERROR'
320
- | string;
620
+ | (string & {});
621
+
622
+ /** 标准工具错误分类 */
623
+ export type ToolErrorCategory =
624
+ | 'validation'
625
+ | 'permission'
626
+ | 'network'
627
+ | 'not_found'
628
+ | 'conflict'
629
+ | 'runtime'
630
+ | 'external'
631
+ | (string & {});
321
632
 
322
633
  /** 工具错误结构 */
323
634
  export interface ToolError {
324
635
  message: string;
325
636
  code?: ToolErrorCode;
637
+ category?: ToolErrorCategory;
326
638
  suggestion?: string;
327
639
  retryable?: boolean;
640
+ details?: Record<string, unknown>;
328
641
  }
329
642
 
330
- /** 判断是否为结构化工具错误 */
331
- export function isToolError(e: unknown): e is Error & { toolError: ToolError } {
332
- return (
333
- e instanceof Error &&
334
- typeof (e as Error & { toolError?: unknown }).toolError === 'object' &&
335
- (e as Error & { toolError: unknown }).toolError !== null &&
336
- typeof ((e as Error & { toolError: Record<string, unknown> }).toolError as Record<string, unknown>).message === 'string'
337
- );
338
- }
643
+ /** 结构化工具异常 */
644
+ export class ToolException extends Error {
645
+ readonly toolError: ToolError;
339
646
 
340
- /** 抛出结构化工具错误 */
341
- export function throwToolError(
342
- message: string,
343
- code?: ToolErrorCode,
344
- opts?: { suggestion?: string; retryable?: boolean }
345
- ): never {
346
- const toolError: ToolError = { message, code, ...opts };
347
- const err = new Error(message) as Error & { toolError: ToolError };
348
- Object.defineProperty(err, 'toolError', { value: toolError, enumerable: true });
349
- throw err;
647
+ constructor(toolError: ToolError) {
648
+ super(toolError.message);
649
+ this.name = 'ToolException';
650
+ this.toolError = toolError;
651
+ }
350
652
  }
351
653
 
352
- /** 重新抛出工具错误(非工具错误则包装后抛出) */
353
- export function rethrowToolError(
354
- error: unknown,
355
- code?: ToolErrorCode,
356
- opts?: { suggestion?: string; retryable?: boolean }
357
- ): never {
358
- if (isToolError(error)) throw error;
359
- const message = error instanceof Error ? error.message : String(error);
360
- throwToolError(message, code, opts);
654
+ /** 判断是否为结构化工具错误 */
655
+ export function isToolError(e: unknown): e is ToolException {
656
+ return e instanceof ToolException;
361
657
  }
362
658
 
363
- /** 从 args 中安全提取类型化参数 */
364
- export function getArg<T>(args: Record<string, unknown>, key: string): T | undefined {
365
- return args[key] as T | undefined;
659
+ /**
660
+ * 抛出结构化工具错误
661
+ *
662
+ * @example
663
+ * throwToolError('文件不存在')
664
+ * throwToolError({ message: '网络超时', code: 'NETWORK_ERROR', retryable: true })
665
+ */
666
+ export function throwToolError(message: string): never;
667
+ export function throwToolError(error: ToolError): never;
668
+ export function throwToolError(input: string | ToolError): never {
669
+ throw new ToolException(typeof input === 'string' ? { message: input, code: 'OPERATION_FAILED' } : input);
366
670
  }
367
671
 
368
672
  /** JSON Schema 属性定义(支持嵌套,符合 JSON Schema 规范) */
369
673
  export interface JsonSchemaProperty {
370
674
  type?: string;
675
+ const?: unknown;
371
676
  description?: string;
677
+ format?: string;
372
678
  enum?: unknown[];
373
679
  items?: JsonSchemaProperty;
374
680
  properties?: Record<string, JsonSchemaProperty>;
375
681
  required?: string[];
376
682
  default?: unknown;
683
+ additionalProperties?: boolean | JsonSchemaProperty;
684
+ anyOf?: JsonSchemaProperty[];
685
+ oneOf?: JsonSchemaProperty[];
377
686
  }
378
687
 
379
688
  /** JSON Schema 对象类型(工具参数的根类型) */
@@ -382,6 +691,216 @@ export interface JsonSchemaObject {
382
691
  properties: Record<string, JsonSchemaProperty>;
383
692
  required?: string[];
384
693
  description?: string;
694
+ additionalProperties?: boolean | JsonSchemaProperty;
695
+ }
696
+
697
+ /** 平台标准工具错误返回结构 */
698
+ export const STANDARD_TOOL_ERROR_SCHEMA: JsonSchemaObject = {
699
+ type: 'object',
700
+ description: '工具失败时的平台标准错误结构。成功结果使用工具自己的 resolvedOutputSchema。',
701
+ properties: {
702
+ status: {
703
+ type: 'string',
704
+ enum: ['error'],
705
+ description: '固定为 error,表示工具执行失败。',
706
+ },
707
+ failureReason: {
708
+ type: 'string',
709
+ description: '执行层失败原因,例如 parse_error、denied、timeout、execution_error。',
710
+ },
711
+ error: {
712
+ type: 'object',
713
+ description: '结构化错误信息。',
714
+ properties: {
715
+ code: {
716
+ type: 'string',
717
+ description: '稳定错误码,例如 INVALID_PARAMS、NETWORK_ERROR、NOT_FOUND。',
718
+ },
719
+ message: {
720
+ type: 'string',
721
+ description: '给用户和模型看的错误说明。',
722
+ },
723
+ category: {
724
+ type: 'string',
725
+ enum: ['validation', 'permission', 'network', 'not_found', 'conflict', 'runtime', 'external'],
726
+ description: '错误分类,用于判断是否换参数、重试、申请权限或停止。',
727
+ },
728
+ retryable: {
729
+ type: 'boolean',
730
+ description: '是否建议用相同目标稍后重试。',
731
+ },
732
+ suggestion: {
733
+ type: 'string',
734
+ description: '可选修复建议。',
735
+ },
736
+ details: {
737
+ type: 'object',
738
+ description: '可选调试详情,字段随错误码变化。',
739
+ additionalProperties: true,
740
+ },
741
+ },
742
+ required: ['message'],
743
+ additionalProperties: false,
744
+ },
745
+ },
746
+ required: ['status', 'failureReason', 'error'],
747
+ additionalProperties: false,
748
+ };
749
+
750
+ function isTypeBoxSchema(schema: Record<string, unknown>): schema is TSchema {
751
+ return Object.prototype.hasOwnProperty.call(schema, Kind);
752
+ }
753
+
754
+ function toSchemaOptions(schema: Record<string, unknown>): Record<string, unknown> {
755
+ const options: Record<string, unknown> = {};
756
+ const optionKeys = [
757
+ 'description',
758
+ 'default',
759
+ 'title',
760
+ 'format',
761
+ 'pattern',
762
+ 'minLength',
763
+ 'maxLength',
764
+ 'minimum',
765
+ 'maximum',
766
+ 'exclusiveMinimum',
767
+ 'exclusiveMaximum',
768
+ 'multipleOf',
769
+ 'minItems',
770
+ 'maxItems',
771
+ 'uniqueItems',
772
+ ];
773
+
774
+ for (const key of optionKeys) {
775
+ const value = schema[key];
776
+ if (value !== undefined) {
777
+ options[key] = value;
778
+ }
779
+ }
780
+
781
+ const additionalProperties = schema.additionalProperties;
782
+ if (typeof additionalProperties === 'boolean') {
783
+ options.additionalProperties = additionalProperties;
784
+ } else if (additionalProperties && typeof additionalProperties === 'object') {
785
+ options.additionalProperties = jsonSchemaToTypeBoxSchema(additionalProperties as Record<string, unknown>);
786
+ }
787
+
788
+ return options;
789
+ }
790
+
791
+ function toTypeBoxLiteral(value: unknown, options: Record<string, unknown>): TSchema {
792
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
793
+ return Type.Literal(value, options);
794
+ }
795
+ if (value === null) {
796
+ return Type.Null(options);
797
+ }
798
+ return Type.Any(options);
799
+ }
800
+
801
+ function toTypeBoxEnumSchema(
802
+ enumValues: readonly unknown[],
803
+ schema: Record<string, unknown>,
804
+ ): TSchema {
805
+ const options = toSchemaOptions(schema);
806
+ const literals = enumValues.map(value => toTypeBoxLiteral(value, {}));
807
+ if (literals.length === 1) {
808
+ return toTypeBoxLiteral(enumValues[0], options);
809
+ }
810
+ return Type.Union(literals, options);
811
+ }
812
+
813
+ export function jsonSchemaToTypeBoxSchema(schema: Record<string, unknown>): TSchema {
814
+ if (isTypeBoxSchema(schema)) return schema;
815
+
816
+ if (Object.prototype.hasOwnProperty.call(schema, 'const')) {
817
+ return toTypeBoxLiteral(schema.const, toSchemaOptions(schema));
818
+ }
819
+
820
+ const enumValues = Array.isArray(schema.enum) ? schema.enum : undefined;
821
+ if (enumValues && enumValues.length > 0) {
822
+ return toTypeBoxEnumSchema(enumValues, schema);
823
+ }
824
+
825
+ const unionSchemas = Array.isArray(schema.oneOf)
826
+ ? schema.oneOf
827
+ : Array.isArray(schema.anyOf)
828
+ ? schema.anyOf
829
+ : undefined;
830
+ if (unionSchemas && unionSchemas.length > 0) {
831
+ return Type.Union(
832
+ unionSchemas.map(value => value && typeof value === 'object'
833
+ ? jsonSchemaToTypeBoxSchema(value as Record<string, unknown>)
834
+ : Type.Any()),
835
+ toSchemaOptions(schema),
836
+ );
837
+ }
838
+
839
+ const type = schema.type;
840
+ if (Array.isArray(type)) {
841
+ return Type.Union(
842
+ type.map(value => jsonSchemaToTypeBoxSchema({ ...schema, type: value, oneOf: undefined, anyOf: undefined })),
843
+ toSchemaOptions(schema),
844
+ );
845
+ }
846
+
847
+ const options = toSchemaOptions(schema);
848
+
849
+ if (type === 'string') {
850
+ return Type.String(options);
851
+ }
852
+ if (type === 'number') {
853
+ return Type.Number(options);
854
+ }
855
+ if (type === 'integer') {
856
+ return Type.Integer(options);
857
+ }
858
+ if (type === 'boolean') {
859
+ return Type.Boolean(options);
860
+ }
861
+ if (type === 'null') {
862
+ return Type.Null(options);
863
+ }
864
+ if (type === 'array') {
865
+ const items = schema.items;
866
+ const itemSchema = items && typeof items === 'object'
867
+ ? jsonSchemaToTypeBoxSchema(items as Record<string, unknown>)
868
+ : Type.Any();
869
+ return Type.Array(itemSchema, options);
870
+ }
871
+ if (type === 'object' || typeof schema.properties === 'object') {
872
+ const properties = schema.properties;
873
+ const required = Array.isArray(schema.required) ? new Set(schema.required.filter(value => typeof value === 'string')) : new Set<string>();
874
+ const entries = properties && typeof properties === 'object'
875
+ ? Object.entries(properties)
876
+ : [];
877
+ const mappedProperties: Record<string, TSchema> = {};
878
+
879
+ for (const [key, value] of entries) {
880
+ const propertySchema = value && typeof value === 'object'
881
+ ? jsonSchemaToTypeBoxSchema(value as Record<string, unknown>)
882
+ : Type.Any();
883
+ mappedProperties[key] = required.has(key) ? propertySchema : Type.Optional(propertySchema);
884
+ }
885
+
886
+ return Type.Object(mappedProperties, options);
887
+ }
888
+
889
+ return Type.Any(options);
890
+ }
891
+
892
+ export function createResolvedOutputSchema(dataSchema: JsonSchemaObject): JsonSchemaObject {
893
+ const dataWithDescription = dataSchema.description
894
+ ? dataSchema
895
+ : { ...dataSchema, description: '工具成功时的业务数据。' };
896
+
897
+ return Type.Object({
898
+ status: Type.Literal('ok', { description: '固定为 ok,表示工具执行成功。' }),
899
+ data: jsonSchemaToTypeBoxSchema(dataWithDescription as unknown as Record<string, unknown>),
900
+ message: Type.Optional(Type.String({ description: '可选。给用户和模型看的简短说明,不承载业务数据。' })),
901
+ }, {
902
+ description: '工具成功时的平台标准返回结构。业务字段固定放在 data 内。',
903
+ }) as unknown as JsonSchemaObject;
385
904
  }
386
905
 
387
906
  /**
@@ -393,17 +912,41 @@ export interface JsonSchemaObject {
393
912
  * name: 'my_tool',
394
913
  * description: '我的自定义工具',
395
914
  * parameters: { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] },
396
- * execute: async (args) => ({ result: getArg<string>(args, 'query') })
915
+ * execute: async (args) => ({ result: args.query })
397
916
  * };
398
917
  * ```
399
918
  */
400
919
  export interface Tool {
401
- /** 工具名称 */
920
+ /** 工具全局唯一 ID(可选,不传则由 provider 生成) */
921
+ id?: string;
922
+ /**
923
+ * 工具集 ID(scope 命名空间)
924
+ *
925
+ * 设置后表示此工具属于某个 scoped 工具集:
926
+ * - identity: `source:assetId:name`
927
+ * - alias: `assetId__name`
928
+ *
929
+ * 不设置则 name 同时作为 assetId(独立工具):
930
+ * - identity: `source:name`
931
+ * - alias: `name`
932
+ */
933
+ assetId?: string;
934
+ /** scope 内的工具名(即 assetId/name 两段式中的 name) */
402
935
  name: string;
936
+ /** 对模型暴露的别名(可选,不传则由 provider 生成) */
937
+ alias?: string;
938
+ /** UI 展示名称(可选) */
939
+ displayName?: string;
403
940
  /** 工具描述(供 AI 理解) */
404
941
  description: string;
405
942
  /** 参数定义(JSON Schema) */
406
943
  parameters: JsonSchemaObject;
944
+ /** 成功时 data 内的业务结构(JSON Schema,可选) */
945
+ outputSchema?: JsonSchemaObject;
946
+ /** 成功返回标准信封结构(JSON Schema,可选,由 outputSchema 自动生成) */
947
+ resolvedOutputSchema?: JsonSchemaObject;
948
+ /** 失败返回结构(JSON Schema;不传时描述符层使用平台标准错误结构) */
949
+ errorSchema?: JsonSchemaObject;
407
950
  /**
408
951
  * UI 声明(可选)
409
952
  * - render: 在对话流中渲染自定义组件
@@ -416,17 +959,37 @@ export interface Tool {
416
959
  * 设为 true 时无论全局配置如何,该工具必须用户确认才执行
417
960
  */
418
961
  requiresApproval?: boolean;
962
+ /** 审批策略。`destructive-only` 表示仅 destructive 工具需要批准。 */
963
+ approvalPolicy?: AssetApprovalPolicy;
964
+ /** 副作用等级。用于审批和风险展示。 */
965
+ sideEffectLevel?: AssetSideEffectLevel;
966
+ /** 宿主依赖类型。用于治理和展示。 */
967
+ hostDependency?: AssetHostDependency;
968
+ /**
969
+ * 基于本次输入参数预判治理信息(可选)。
970
+ *
971
+ * 设计约束:
972
+ * - 用于执行前的动态风险评估
973
+ * - Orchestrator 只会将其与静态治理做“更严格”的合并,不会放宽静态治理
974
+ */
975
+ assessInputGovernance?: (
976
+ args: Record<string, unknown>,
977
+ ) => ToolGovernanceSnapshot | Promise<ToolGovernanceSnapshot | undefined> | undefined;
978
+ /** 分发来源(注册时如设置则覆盖 provider 默认值) */
979
+ source?: import('./governance/types').AssetSource;
980
+ /** 工具分类(供 ToolRegistry 发现使用) */
981
+ category?: string;
982
+ /** 工具标签(供 ToolRegistry 搜索使用) */
983
+ tags?: string[];
419
984
  /** 超时时间(毫秒),由框架通过 AbortSignal 强制执行 */
420
985
  timeout?: number;
421
- /** 扩展字段,供宿主应用存放元数据 */
422
- meta?: Record<string, unknown>;
423
- /**
986
+ /**
424
987
  * 执行函数
425
988
  *
426
- * 成功返回 object,框架自动 JSON.stringify 后传给 LLM。
989
+ * 成功返回 ToolResult 或普通对象,框架会统一规范化后再传给 LLM。
427
990
  * 失败统一 throw(推荐使用 throwToolError())。
428
991
  */
429
- execute: (args: Record<string, unknown>, context: ToolContext) => Promise<object>;
992
+ execute: (args: Record<string, unknown>, context: ToolContext) => Promise<ToolExecuteResult>;
430
993
  }
431
994
 
432
995
  /** 工具执行器接口(供 Agent 内部使用,自定义命令执行环境) */
@@ -439,7 +1002,8 @@ export interface ToolExecutor {
439
1002
  hooks?: {
440
1003
  onStdout?: (chunk: string) => void;
441
1004
  onStderr?: (chunk: string) => void;
442
- }
1005
+ },
1006
+ timeout?: number,
443
1007
  ): Promise<{ success: boolean; output?: string; error?: string }>;
444
1008
  }
445
1009
 
@@ -462,9 +1026,9 @@ export interface ToolPlugin {
462
1026
  *
463
1027
  * @example
464
1028
  * ```typescript
465
- * export function getCwdTool(): ToolPlugin {
1029
+ * export function getEnvironmentTool(): ToolPlugin {
466
1030
  * return tool({
467
- * name: 'get_cwd',
1031
+ * name: 'get_environment',
468
1032
  * description: '...',
469
1033
  * parameters: { ... },
470
1034
  * execute: async (args, context) => { ... }
@@ -499,7 +1063,7 @@ export function tools(ts: Tool[]): ToolPlugin {
499
1063
  * @example
500
1064
  * ```typescript
501
1065
  * tools: [
502
- * getCwdTool(), // 工具插件(函数调用)
1066
+ * getEnvironmentTool(), // 工具插件(函数调用)
503
1067
  * searchPlugin({ dataDir, workspace }), // 异步插件(返回 Promise<ToolPlugin>)
504
1068
  * ]
505
1069
  * ```
@@ -516,10 +1080,10 @@ export type ToolConfigItem = Tool | ToolPlugin | Promise<Tool | ToolPlugin>;
516
1080
  */
517
1081
  export async function resolveTools(items: ToolConfigItem[]): Promise<Tool[]> {
518
1082
  const tools: Tool[] = [];
519
-
1083
+
520
1084
  for (const item of items) {
521
1085
  const resolved = await item;
522
-
1086
+
523
1087
  if ('tools' in resolved && Array.isArray(resolved.tools)) {
524
1088
  // ToolPlugin
525
1089
  tools.push(...resolved.tools);
@@ -530,7 +1094,7 @@ export async function resolveTools(items: ToolConfigItem[]): Promise<Tool[]> {
530
1094
  console.warn('无法识别的工具配置项:', resolved);
531
1095
  }
532
1096
  }
533
-
1097
+
534
1098
  return tools;
535
1099
  }
536
1100
 
@@ -571,13 +1135,8 @@ export interface ChatMessage {
571
1135
 
572
1136
  /** 火山引擎 Responses API 工具定义 */
573
1137
  export interface ResponsesApiTool {
574
- type: 'function' | 'web_search';
575
- // Function 类型
1138
+ type: 'function';
576
1139
  name?: string;
577
1140
  description?: string;
578
1141
  parameters?: Record<string, unknown>;
579
- // Web Search 类型
580
- max_keyword?: number;
581
- limit?: number;
582
- sources?: string[];
583
1142
  }