@zhin.js/agent 0.1.15 → 0.1.16

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 (198) hide show
  1. package/README.md +80 -43
  2. package/lib/builtin/activate-skill-tool.d.ts +21 -0
  3. package/lib/builtin/activate-skill-tool.d.ts.map +1 -0
  4. package/lib/builtin/activate-skill-tool.js +57 -0
  5. package/lib/builtin/activate-skill-tool.js.map +1 -0
  6. package/lib/builtin/ask-user-tool.d.ts +28 -0
  7. package/lib/builtin/ask-user-tool.d.ts.map +1 -0
  8. package/lib/builtin/ask-user-tool.js +182 -0
  9. package/lib/builtin/ask-user-tool.js.map +1 -0
  10. package/lib/builtin/bash-tool.d.ts +23 -0
  11. package/lib/builtin/bash-tool.d.ts.map +1 -0
  12. package/lib/builtin/bash-tool.js +64 -0
  13. package/lib/builtin/bash-tool.js.map +1 -0
  14. package/lib/builtin/bing-search-html.d.ts +37 -0
  15. package/lib/builtin/bing-search-html.d.ts.map +1 -0
  16. package/lib/builtin/bing-search-html.js +116 -0
  17. package/lib/builtin/bing-search-html.js.map +1 -0
  18. package/lib/builtin/builtin-base-tool.d.ts +25 -0
  19. package/lib/builtin/builtin-base-tool.d.ts.map +1 -0
  20. package/lib/builtin/builtin-base-tool.js +30 -0
  21. package/lib/builtin/builtin-base-tool.js.map +1 -0
  22. package/lib/builtin/edit-file-tool.d.ts +13 -0
  23. package/lib/builtin/edit-file-tool.d.ts.map +1 -0
  24. package/lib/builtin/edit-file-tool.js +81 -0
  25. package/lib/builtin/edit-file-tool.js.map +1 -0
  26. package/lib/builtin/file-edit-quote-utils.d.ts +24 -0
  27. package/lib/builtin/file-edit-quote-utils.d.ts.map +1 -0
  28. package/lib/builtin/file-edit-quote-utils.js +81 -0
  29. package/lib/builtin/file-edit-quote-utils.js.map +1 -0
  30. package/lib/builtin/glob-tool.d.ts +23 -0
  31. package/lib/builtin/glob-tool.d.ts.map +1 -0
  32. package/lib/builtin/glob-tool.js +54 -0
  33. package/lib/builtin/glob-tool.js.map +1 -0
  34. package/lib/builtin/grep-tool.d.ts +23 -0
  35. package/lib/builtin/grep-tool.d.ts.map +1 -0
  36. package/lib/builtin/grep-tool.js +118 -0
  37. package/lib/builtin/grep-tool.js.map +1 -0
  38. package/lib/builtin/install-skill-tool.d.ts +24 -0
  39. package/lib/builtin/install-skill-tool.d.ts.map +1 -0
  40. package/lib/builtin/install-skill-tool.js +76 -0
  41. package/lib/builtin/install-skill-tool.js.map +1 -0
  42. package/lib/builtin/list-dir-tool.d.ts +13 -0
  43. package/lib/builtin/list-dir-tool.d.ts.map +1 -0
  44. package/lib/builtin/list-dir-tool.js +59 -0
  45. package/lib/builtin/list-dir-tool.js.map +1 -0
  46. package/lib/builtin/read-file-tool.d.ts +14 -0
  47. package/lib/builtin/read-file-tool.d.ts.map +1 -0
  48. package/lib/builtin/read-file-tool.js +77 -0
  49. package/lib/builtin/read-file-tool.js.map +1 -0
  50. package/lib/builtin/read-memory-tool.d.ts +14 -0
  51. package/lib/builtin/read-memory-tool.d.ts.map +1 -0
  52. package/lib/builtin/read-memory-tool.js +49 -0
  53. package/lib/builtin/read-memory-tool.js.map +1 -0
  54. package/lib/builtin/spawn-task-tool.d.ts +20 -0
  55. package/lib/builtin/spawn-task-tool.d.ts.map +1 -0
  56. package/lib/builtin/spawn-task-tool.js +57 -0
  57. package/lib/builtin/spawn-task-tool.js.map +1 -0
  58. package/lib/builtin/todo-read-tool.d.ts +14 -0
  59. package/lib/builtin/todo-read-tool.d.ts.map +1 -0
  60. package/lib/builtin/todo-read-tool.js +56 -0
  61. package/lib/builtin/todo-read-tool.js.map +1 -0
  62. package/lib/builtin/todo-write-tool.d.ts +14 -0
  63. package/lib/builtin/todo-write-tool.d.ts.map +1 -0
  64. package/lib/builtin/todo-write-tool.js +54 -0
  65. package/lib/builtin/todo-write-tool.js.map +1 -0
  66. package/lib/builtin/web-fetch-tool.d.ts +19 -0
  67. package/lib/builtin/web-fetch-tool.d.ts.map +1 -0
  68. package/lib/builtin/web-fetch-tool.js +89 -0
  69. package/lib/builtin/web-fetch-tool.js.map +1 -0
  70. package/lib/builtin/web-search-locale.d.ts +16 -0
  71. package/lib/builtin/web-search-locale.d.ts.map +1 -0
  72. package/lib/builtin/web-search-locale.js +73 -0
  73. package/lib/builtin/web-search-locale.js.map +1 -0
  74. package/lib/builtin/web-search-tool.d.ts +20 -0
  75. package/lib/builtin/web-search-tool.d.ts.map +1 -0
  76. package/lib/builtin/web-search-tool.js +105 -0
  77. package/lib/builtin/web-search-tool.js.map +1 -0
  78. package/lib/builtin/web-tool-utils.d.ts +4 -0
  79. package/lib/builtin/web-tool-utils.d.ts.map +1 -0
  80. package/lib/builtin/web-tool-utils.js +4 -0
  81. package/lib/builtin/web-tool-utils.js.map +1 -0
  82. package/lib/builtin/write-file-tool.d.ts +13 -0
  83. package/lib/builtin/write-file-tool.d.ts.map +1 -0
  84. package/lib/builtin/write-file-tool.js +51 -0
  85. package/lib/builtin/write-file-tool.js.map +1 -0
  86. package/lib/builtin/write-memory-tool.d.ts +14 -0
  87. package/lib/builtin/write-memory-tool.d.ts.map +1 -0
  88. package/lib/builtin/write-memory-tool.js +50 -0
  89. package/lib/builtin/write-memory-tool.js.map +1 -0
  90. package/lib/builtin-tools.d.ts +10 -11
  91. package/lib/builtin-tools.d.ts.map +1 -1
  92. package/lib/builtin-tools.js +44 -862
  93. package/lib/builtin-tools.js.map +1 -1
  94. package/lib/defaults/tools.d.ts +3 -6
  95. package/lib/defaults/tools.d.ts.map +1 -1
  96. package/lib/defaults/tools.js +3 -11
  97. package/lib/defaults/tools.js.map +1 -1
  98. package/lib/index.d.ts +25 -3
  99. package/lib/index.d.ts.map +1 -1
  100. package/lib/index.js +24 -3
  101. package/lib/index.js.map +1 -1
  102. package/lib/init/create-zhin-agent.d.ts.map +1 -1
  103. package/lib/init/create-zhin-agent.js +4 -3
  104. package/lib/init/create-zhin-agent.js.map +1 -1
  105. package/lib/init/message-media.d.ts +8 -0
  106. package/lib/init/message-media.d.ts.map +1 -0
  107. package/lib/init/message-media.js +75 -0
  108. package/lib/init/message-media.js.map +1 -0
  109. package/lib/init/output-renderer.d.ts +3 -0
  110. package/lib/init/output-renderer.d.ts.map +1 -0
  111. package/lib/init/output-renderer.js +38 -0
  112. package/lib/init/output-renderer.js.map +1 -0
  113. package/lib/init/register-ai-trigger.d.ts +1 -1
  114. package/lib/init/register-ai-trigger.d.ts.map +1 -1
  115. package/lib/init/register-ai-trigger.js +35 -159
  116. package/lib/init/register-ai-trigger.js.map +1 -1
  117. package/lib/init/register-builtin-tools.d.ts.map +1 -1
  118. package/lib/init/register-builtin-tools.js +9 -5
  119. package/lib/init/register-builtin-tools.js.map +1 -1
  120. package/lib/orchestrator/index.d.ts +2 -0
  121. package/lib/orchestrator/index.d.ts.map +1 -1
  122. package/lib/orchestrator/index.js +1 -0
  123. package/lib/orchestrator/index.js.map +1 -1
  124. package/lib/orchestrator/resource-registry.d.ts +1 -0
  125. package/lib/orchestrator/resource-registry.d.ts.map +1 -1
  126. package/lib/orchestrator/resource-registry.js +6 -0
  127. package/lib/orchestrator/resource-registry.js.map +1 -1
  128. package/lib/orchestrator/tool-registry.d.ts +5 -11
  129. package/lib/orchestrator/tool-registry.d.ts.map +1 -1
  130. package/lib/orchestrator/tool-registry.js +30 -75
  131. package/lib/orchestrator/tool-registry.js.map +1 -1
  132. package/lib/orchestrator/tool-selection.d.ts +39 -0
  133. package/lib/orchestrator/tool-selection.d.ts.map +1 -0
  134. package/lib/orchestrator/tool-selection.js +319 -0
  135. package/lib/orchestrator/tool-selection.js.map +1 -0
  136. package/lib/orchestrator/types.d.ts +2 -0
  137. package/lib/orchestrator/types.d.ts.map +1 -1
  138. package/lib/reserved-tools.d.ts +3 -0
  139. package/lib/reserved-tools.d.ts.map +1 -0
  140. package/lib/reserved-tools.js +30 -0
  141. package/lib/reserved-tools.js.map +1 -0
  142. package/lib/service.d.ts +9 -5
  143. package/lib/service.d.ts.map +1 -1
  144. package/lib/service.js +42 -36
  145. package/lib/service.js.map +1 -1
  146. package/lib/subagent.d.ts +6 -0
  147. package/lib/subagent.d.ts.map +1 -1
  148. package/lib/subagent.js +33 -15
  149. package/lib/subagent.js.map +1 -1
  150. package/lib/task-executor.d.ts +1 -0
  151. package/lib/task-executor.d.ts.map +1 -1
  152. package/lib/task-executor.js +15 -8
  153. package/lib/task-executor.js.map +1 -1
  154. package/lib/zhin-agent/builtin-tools.d.ts +1 -3
  155. package/lib/zhin-agent/builtin-tools.d.ts.map +1 -1
  156. package/lib/zhin-agent/builtin-tools.js +4 -41
  157. package/lib/zhin-agent/builtin-tools.js.map +1 -1
  158. package/lib/zhin-agent/config.d.ts +7 -0
  159. package/lib/zhin-agent/config.d.ts.map +1 -1
  160. package/lib/zhin-agent/config.js +12 -7
  161. package/lib/zhin-agent/config.js.map +1 -1
  162. package/lib/zhin-agent/context-budget.d.ts +27 -0
  163. package/lib/zhin-agent/context-budget.d.ts.map +1 -0
  164. package/lib/zhin-agent/context-budget.js +50 -0
  165. package/lib/zhin-agent/context-budget.js.map +1 -0
  166. package/lib/zhin-agent/index.d.ts +10 -0
  167. package/lib/zhin-agent/index.d.ts.map +1 -1
  168. package/lib/zhin-agent/index.js +120 -88
  169. package/lib/zhin-agent/index.js.map +1 -1
  170. package/lib/zhin-agent/model-harness.d.ts +29 -0
  171. package/lib/zhin-agent/model-harness.d.ts.map +1 -0
  172. package/lib/zhin-agent/model-harness.js +67 -0
  173. package/lib/zhin-agent/model-harness.js.map +1 -0
  174. package/lib/zhin-agent/pre-exec.d.ts +7 -0
  175. package/lib/zhin-agent/pre-exec.d.ts.map +1 -0
  176. package/lib/zhin-agent/pre-exec.js +25 -0
  177. package/lib/zhin-agent/pre-exec.js.map +1 -0
  178. package/lib/zhin-agent/prompt.d.ts +10 -8
  179. package/lib/zhin-agent/prompt.d.ts.map +1 -1
  180. package/lib/zhin-agent/prompt.js +37 -30
  181. package/lib/zhin-agent/prompt.js.map +1 -1
  182. package/lib/zhin-agent/text-sanitize.d.ts +8 -0
  183. package/lib/zhin-agent/text-sanitize.d.ts.map +1 -0
  184. package/lib/zhin-agent/text-sanitize.js +19 -0
  185. package/lib/zhin-agent/text-sanitize.js.map +1 -0
  186. package/lib/zhin-agent/tool-runtime.d.ts +31 -0
  187. package/lib/zhin-agent/tool-runtime.d.ts.map +1 -0
  188. package/lib/zhin-agent/tool-runtime.js +49 -0
  189. package/lib/zhin-agent/tool-runtime.js.map +1 -0
  190. package/package.json +8 -6
  191. package/lib/tools.d.ts +0 -45
  192. package/lib/tools.d.ts.map +0 -1
  193. package/lib/tools.js +0 -205
  194. package/lib/tools.js.map +0 -1
  195. package/lib/zhin-agent/tool-collector.d.ts +0 -22
  196. package/lib/zhin-agent/tool-collector.d.ts.map +0 -1
  197. package/lib/zhin-agent/tool-collector.js +0 -225
  198. package/lib/zhin-agent/tool-collector.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/zhin-agent/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAKzD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAI/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,CAGpG;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ5G;AAED,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,sBAAsB,wDAAwD,CAAC;AAC5F,eAAO,MAAM,sBAAsB,wCAAwC,CAAC;AAE5E,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM3C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,wBAAwB;AACxB,eAAO,MAAM,gBAAgB;;;;CAInB,CAAC;AAEX,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC7C,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;IAC/D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,qCAAqC;IACrC,aAAa,CAAC,EAAE,EAAE,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAClD,sCAAsC;IACtC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,eAAe,CA2BpD,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/zhin-agent/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAKzD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAI/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,CAGpG;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ5G;AAED,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,sBAAsB,wDAAwD,CAAC;AAC5F,eAAO,MAAM,sBAAsB,wCAAwC,CAAC;AAE5E,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAA6B,CAAC;AAE1E,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAGpE,wBAAwB;AACxB,eAAO,MAAM,gBAAgB;;;;CAInB,CAAC;AAEX,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC7C,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;IAC/D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,qCAAqC;IACrC,aAAa,CAAC,EAAE,EAAE,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAClD,sCAAsC;IACtC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,iDAAiD;IACjD,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,eAAe,CA6BpD,CAAC;AAEF,8CAA8C;AAC9C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAIpH"}
@@ -2,6 +2,7 @@
2
2
  * ZhinAgent 配置、常量、类型定义
3
3
  */
4
4
  import { DEFAULT_CONTEXT_TOKENS } from '@zhin.js/ai';
5
+ import { PERMISSION_LEVEL_PRIORITY } from '../orchestrator/tool-selection.js';
5
6
  const SMALL_MODEL_RE = /[:\-_](0\.5|1\.?[58]?|[3-8])b\b/i;
6
7
  const MEDIUM_MODEL_RE = /[:\-_](14|[12][0-9]|32)b\b/i;
7
8
  /**
@@ -40,13 +41,8 @@ export function resolveSkillInstructionMaxChars(config, modelName) {
40
41
  export const SECTION_SEP = '\n\n---\n\n';
41
42
  export const HISTORY_CONTEXT_MARKER = '[Chat messages since your last reply - for context]';
42
43
  export const CURRENT_MESSAGE_MARKER = '[Current message - respond to this]';
43
- export const PERM_MAP = {
44
- user: 0,
45
- group_admin: 1,
46
- group_owner: 2,
47
- bot_admin: 3,
48
- owner: 4,
49
- };
44
+ export const PERM_MAP = PERMISSION_LEVEL_PRIORITY;
45
+ const TRUE_VALUES = new Set(['1', 'true', 'yes', 'on']);
50
46
  /** 上下文感知内置工具的关键词触发正则 */
51
47
  export const KEYWORD_TRIGGERS = {
52
48
  chatHistory: /之前|上次|历史|回忆|聊过|记录|还记得|曾经/i,
@@ -80,5 +76,14 @@ export const DEFAULT_CONFIG = {
80
76
  subagentTools: [],
81
77
  modelSizeHint: '',
82
78
  skillInstructionMaxChars: 0,
79
+ modelHarness: {},
80
+ phaseTrace: false,
83
81
  };
82
+ /** `env` 参数主要用于测试注入,运行时默认读取 `process.env`。 */
83
+ export function isPhaseTraceEnabled(config, env = process.env) {
84
+ if (config.phaseTrace)
85
+ return true;
86
+ const raw = env.ZHIN_AGENT_PHASE_TRACE?.trim().toLowerCase();
87
+ return !!raw && TRUE_VALUES.has(raw);
88
+ }
84
89
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/zhin-agent/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAIrD,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAC1D,MAAM,eAAe,GAAG,6BAA6B,CAAC;AAEtD;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,OAAO,CAAC;IACnD,IAAI,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,QAAQ,CAAC;IACrD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAiC,EAAE,SAAiB;IACnF,IAAI,MAAM,CAAC,aAAa,IAAK,MAAM,CAAC,aAAwB,KAAK,EAAE;QAAE,OAAO,MAAM,CAAC,aAA8B,CAAC;IAClH,OAAO,cAAc,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,+BAA+B,CAAC,MAAiC,EAAE,SAAiB;IAClG,IAAI,MAAM,CAAC,wBAAwB,IAAI,MAAM,CAAC,wBAAwB,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,wBAAwB,CAAC;IACnH,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC;QAC1B,KAAK,QAAQ,CAAC,CAAC,OAAO,IAAI,CAAC;QAC3B,KAAK,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AACzC,MAAM,CAAC,MAAM,sBAAsB,GAAG,qDAAqD,CAAC;AAC5F,MAAM,CAAC,MAAM,sBAAsB,GAAG,qCAAqC,CAAC;AAE5E,MAAM,CAAC,MAAM,QAAQ,GAA2B;IAC9C,IAAI,EAAE,CAAC;IACP,WAAW,EAAE,CAAC;IACd,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,CAAC;CACT,CAAC;AAIF,wBAAwB;AACxB,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,2BAA2B;IACxC,WAAW,EAAE,kDAAkD;IAC/D,SAAS,EAAE,qCAAqC;CACxC,CAAC;AAmCX,MAAM,CAAC,MAAM,cAAc,GAA8B;IACvD,OAAO,EAAE,0RAA0R;IACnS,aAAa,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM;IACf,cAAc,EAAE,MAAM;IACtB,SAAS,EAAE,CAAC;IACZ,QAAQ,EAAE,CAAC;IACX,cAAc,EAAE,CAAC;IACjB,iBAAiB,EAAE,CAAC;IACpB,oBAAoB,EAAE,IAAI;IAC1B,SAAS,EAAE,EAAE;IACb,aAAa,EAAE,IAAI;IACnB,SAAS,EAAE,EAAE;IACb,aAAa,EAAE,EAAE;IACjB,WAAW,EAAE,EAAE;IACf,aAAa,EAAE,sBAAsB;IACrC,eAAe,EAAE,GAAG;IACpB,aAAa,EAAE,EAAE;IACjB,YAAY,EAAE,EAAE;IAChB,YAAY,EAAE,MAAM;IACpB,UAAU,EAAE,QAAQ;IACpB,aAAa,EAAE,EAAE;IACjB,OAAO,EAAE,KAAK;IACd,qBAAqB,EAAE,EAAE;IACzB,aAAa,EAAE,EAAE;IACjB,aAAa,EAAE,EAAE;IACjB,wBAAwB,EAAE,CAAC;CAC5B,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/zhin-agent/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { AIProvider, ChatMessage, PruneResult } from '@zhin.js/ai';
2
+ import type { ModelRegistry } from '@zhin.js/ai';
3
+ import type { ZhinAgentConfig } from './config.js';
4
+ export interface ResolvedContextBudget {
5
+ contextWindow: number;
6
+ maxHistoryShare: number;
7
+ source: 'config' | 'model-registry' | 'provider' | 'default';
8
+ }
9
+ export interface PrunedHistory {
10
+ messages: ChatMessage[];
11
+ result: PruneResult;
12
+ budget: ResolvedContextBudget;
13
+ }
14
+ export declare function resolveContextBudget(params: {
15
+ config: Required<ZhinAgentConfig>;
16
+ provider: AIProvider;
17
+ modelRegistry?: ModelRegistry | null;
18
+ model?: string;
19
+ }): ResolvedContextBudget;
20
+ export declare function pruneHistoryWithBudget(params: {
21
+ messages: ChatMessage[];
22
+ config: Required<ZhinAgentConfig>;
23
+ provider: AIProvider;
24
+ modelRegistry?: ModelRegistry | null;
25
+ model?: string;
26
+ }): PrunedHistory;
27
+ //# sourceMappingURL=context-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-budget.d.ts","sourceRoot":"","sources":["../../src/zhin-agent/context-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAKxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,QAAQ,GAAG,gBAAgB,GAAG,UAAU,GAAG,SAAS,CAAC;CAC9D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAWD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IAClC,QAAQ,EAAE,UAAU,CAAC;IACrB,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,qBAAqB,CAgCxB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IAClC,QAAQ,EAAE,UAAU,CAAC;IACrB,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,aAAa,CAYhB"}
@@ -0,0 +1,50 @@
1
+ import { DEFAULT_CONTEXT_TOKENS, pruneHistoryForContext, } from '@zhin.js/ai';
2
+ function resolveRegistryWindow(registry, provider, model) {
3
+ if (!registry || !model)
4
+ return undefined;
5
+ return registry.getModel(provider.name, model)?.contextWindow;
6
+ }
7
+ export function resolveContextBudget(params) {
8
+ const configured = params.config.contextTokens;
9
+ if (configured && configured > 0 && configured !== DEFAULT_CONTEXT_TOKENS) {
10
+ return {
11
+ contextWindow: configured,
12
+ maxHistoryShare: params.config.maxHistoryShare ?? 0.5,
13
+ source: 'config',
14
+ };
15
+ }
16
+ const registryWindow = resolveRegistryWindow(params.modelRegistry, params.provider, params.model);
17
+ if (registryWindow && registryWindow > 0) {
18
+ return {
19
+ contextWindow: registryWindow,
20
+ maxHistoryShare: params.config.maxHistoryShare ?? 0.5,
21
+ source: 'model-registry',
22
+ };
23
+ }
24
+ if (params.provider.contextWindow && params.provider.contextWindow > 0) {
25
+ return {
26
+ contextWindow: params.provider.contextWindow,
27
+ maxHistoryShare: params.config.maxHistoryShare ?? 0.5,
28
+ source: 'provider',
29
+ };
30
+ }
31
+ return {
32
+ contextWindow: configured || DEFAULT_CONTEXT_TOKENS,
33
+ maxHistoryShare: params.config.maxHistoryShare ?? 0.5,
34
+ source: 'default',
35
+ };
36
+ }
37
+ export function pruneHistoryWithBudget(params) {
38
+ const budget = resolveContextBudget(params);
39
+ const result = pruneHistoryForContext({
40
+ messages: params.messages,
41
+ maxContextTokens: budget.contextWindow,
42
+ maxHistoryShare: budget.maxHistoryShare,
43
+ });
44
+ return {
45
+ messages: result.messages,
46
+ result,
47
+ budget,
48
+ };
49
+ }
50
+ //# sourceMappingURL=context-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-budget.js","sourceRoot":"","sources":["../../src/zhin-agent/context-budget.ts"],"names":[],"mappings":"AACA,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAgBrB,SAAS,qBAAqB,CAC5B,QAA0C,EAC1C,QAAoB,EACpB,KAAc;IAEd,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,aAAa,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAKpC;IACC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;IAC/C,IAAI,UAAU,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,KAAK,sBAAsB,EAAE,CAAC;QAC1E,OAAO;YACL,aAAa,EAAE,UAAU;YACzB,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,GAAG;YACrD,MAAM,EAAE,QAAQ;SACjB,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,qBAAqB,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAClG,IAAI,cAAc,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,aAAa,EAAE,cAAc;YAC7B,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,GAAG;YACrD,MAAM,EAAE,gBAAgB;SACzB,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;QACvE,OAAO;YACL,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,aAAa;YAC5C,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,GAAG;YACrD,MAAM,EAAE,UAAU;SACnB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,aAAa,EAAE,UAAU,IAAI,sBAAsB;QACnD,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,GAAG;QACrD,MAAM,EAAE,SAAS;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAMtC;IACC,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,sBAAsB,CAAC;QACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,gBAAgB,EAAE,MAAM,CAAC,aAAa;QACtC,eAAe,EAAE,MAAM,CAAC,eAAe;KACxC,CAAC,CAAC;IACH,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -41,6 +41,7 @@ export declare class ZhinAgent {
41
41
  private activeSkillsContext;
42
42
  private skillsSummaryXML;
43
43
  private modelRegistry;
44
+ private phaseTraceEnabled;
44
45
  constructor(provider: AIProvider, config?: ZhinAgentConfig);
45
46
  setSkillRegistry(registry: SkillRegistry): void;
46
47
  setSessionManager(manager: SessionManager): void;
@@ -64,7 +65,16 @@ export declare class ZhinAgent {
64
65
  setActiveSkillsContext(content: string): void;
65
66
  setSkillsSummaryXML(xml: string): void;
66
67
  process(content: string, context: ToolContext, externalTools?: Tool[], onChunk?: OnChunkCallback): Promise<OutputElement[]>;
68
+ private buildDisciplinedPrompt;
69
+ private logPhase;
67
70
  processMultimodal(parts: ContentPart[], context: ToolContext, onChunk?: OnChunkCallback): Promise<OutputElement[]>;
71
+ /**
72
+ * 为内置工具注入 `extra.web_search_locale`:
73
+ * - 若调用方已在 `context.extra.web_search_locale` 中设置,则规范化后沿用;
74
+ * - 否则读取用户档案 `preferred_language` / `language`;
75
+ * - 均未设置时不在 extra 中写入,web_search 默认使用中文市场。
76
+ */
77
+ private attachWebSearchLocale;
68
78
  private buildHistoryMessages;
69
79
  private streamChatWithHistory;
70
80
  private saveToSession;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/zhin-agent/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/zhin-agent/index.ts"],"names":[],"mappings":"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"}
@@ -21,44 +21,22 @@ import { SessionManager, createMemorySessionManager } from '@zhin.js/ai';
21
21
  import { ConversationMemory } from '@zhin.js/ai';
22
22
  import { parseOutput } from '@zhin.js/ai';
23
23
  import { UserProfileStore } from '../user-profile.js';
24
+ import { WEB_SEARCH_LOCALE_EXTRA_KEY, normalizeWebSearchLocaleHint, } from '../builtin/web-search-locale.js';
24
25
  import { RateLimiter } from '@zhin.js/ai';
25
26
  import { detectTone } from '@zhin.js/ai';
26
27
  import { SubagentManager } from '../subagent.js';
27
- import { pruneHistoryForContext, DEFAULT_CONTEXT_TOKENS, } from '@zhin.js/ai';
28
28
  import { triggerAIHook, createAIHookEvent } from '../hooks.js';
29
29
  // ── Sub-modules ─────────────────────────────────────────────────────
30
- import { DEFAULT_CONFIG, KEYWORD_TRIGGERS, } from './config.js';
30
+ import { DEFAULT_CONFIG, isPhaseTraceEnabled, } from './config.js';
31
31
  import { applyExecPolicyToTools } from '../security/exec-policy.js';
32
- import { collectRelevantTools } from './tool-collector.js';
33
- import { buildEnhancedPersona, buildContextHint, buildRichSystemPrompt, buildUserMessageWithHistory, } from './prompt.js';
34
- import { createChatHistoryTool, createUserProfileTool, createSpawnTaskTool, } from './builtin-tools.js';
32
+ import { buildEnhancedPersona, buildContextHint, buildRichSystemPrompt, buildUserMessageWithHistory, FIXED_DISCIPLINE_RULES, } from './prompt.js';
33
+ import { buildPreExecFastPathPrompt, collectRuntimeTools, planToolRun, } from './tool-runtime.js';
34
+ import { stripHallucinatedToolCalls, stripThinkBlocks } from './text-sanitize.js';
35
+ import { pruneHistoryWithBudget } from './context-budget.js';
36
+ import { resolveModelHarness } from './model-harness.js';
37
+ import { RESERVED_TOOL_NAMES, RESERVED_TOOL_NAME_PREFIXES } from '../reserved-tools.js';
35
38
  const logger = new Logger(null, 'ZhinAgent');
36
39
  const now = () => performance.now();
37
- /** Strip `<think>…</think>` blocks that some reasoning models embed in content. */
38
- function stripThinkBlocks(text) {
39
- return text.replace(/<think>[\s\S]*?<\/think>\s*/g, '').trim();
40
- }
41
- /**
42
- * Strip hallucinated tool-call markup that some models emit as plain text
43
- * (e.g. `<tool_call …/>`, `<function=xxx>…</function>`, `<|plugin|>…`).
44
- * Only removes the markup; any surrounding real text is preserved.
45
- */
46
- function stripHallucinatedToolCalls(text) {
47
- let cleaned = text;
48
- // <tool_call …/> or <tool_call …>…</tool_call>
49
- cleaned = cleaned.replace(/<tool_call\b[\s\S]*?(?:\/>|<\/tool_call>)/gi, '');
50
- // <tool_result …/> or <tool_result …>…</tool_result>
51
- cleaned = cleaned.replace(/<tool_result\b[\s\S]*?(?:\/>|<\/tool_result>)/gi, '');
52
- // <function=name>…</function>
53
- cleaned = cleaned.replace(/<function=[^>]*>[\s\S]*?<\/function>/gi, '');
54
- // {tool_result} / {tool_call} bare placeholders
55
- cleaned = cleaned.replace(/\{tool_(?:result|call)\}/gi, '');
56
- // <|plugin|>…<|/plugin|> (some Chinese models)
57
- cleaned = cleaned.replace(/<\|plugin\|>[\s\S]*?<\|\/plugin\|>/gi, '');
58
- // <<<tool_call>>> … <<<end>>> style
59
- cleaned = cleaned.replace(/<<<tool_call>>>[\s\S]*?<<<end>>>/gi, '');
60
- return cleaned.trim();
61
- }
62
40
  // ============================================================================
63
41
  // ZhinAgent
64
42
  // ============================================================================
@@ -77,9 +55,11 @@ export class ZhinAgent {
77
55
  activeSkillsContext = '';
78
56
  skillsSummaryXML = '';
79
57
  modelRegistry = null;
58
+ phaseTraceEnabled;
80
59
  constructor(provider, config) {
81
60
  this.provider = provider;
82
61
  this.config = { ...DEFAULT_CONFIG, ...config };
62
+ this.phaseTraceEnabled = isPhaseTraceEnabled(this.config);
83
63
  this.sessions = createMemorySessionManager();
84
64
  this.memory = new ConversationMemory({
85
65
  minTopicRounds: this.config.minTopicRounds,
@@ -105,6 +85,7 @@ export class ZhinAgent {
105
85
  }
106
86
  setModelRegistry(registry) {
107
87
  this.modelRegistry = registry;
88
+ this.subagentManager?.setModelRegistry(registry);
108
89
  }
109
90
  upgradeMemoryToDatabase(msgModel, sumModel) {
110
91
  this.memory.upgradeToDatabase(msgModel, sumModel);
@@ -117,8 +98,10 @@ export class ZhinAgent {
117
98
  provider: this.provider,
118
99
  workspace: process.cwd(),
119
100
  createTools,
101
+ subagentTools: this.config.subagentTools,
120
102
  maxIterations: this.config.maxSubagentIterations,
121
103
  execPolicyConfig: this.config,
104
+ modelRegistry: this.modelRegistry,
122
105
  });
123
106
  logger.debug('SubagentManager initialized');
124
107
  }
@@ -185,12 +168,19 @@ export class ZhinAgent {
185
168
  const { senderId, sceneId, platform } = context;
186
169
  const sessionId = SessionManager.generateId(platform || '', senderId || '', sceneId);
187
170
  const userId = senderId || 'unknown';
171
+ this.logPhase('turn.start', sessionId, {
172
+ mode: 'text',
173
+ provider: this.provider.name,
174
+ });
188
175
  // 0. Rate limit
189
176
  const rateCheck = this.rateLimiter.check(userId);
190
177
  if (!rateCheck.allowed) {
178
+ this.logPhase('turn.rate_limited', sessionId, { userId });
191
179
  logger.debug(`[速率限制] 用户 ${userId} 被限制: ${rateCheck.message}`);
192
180
  return parseOutput(rateCheck.message || '请稍后再试');
193
181
  }
182
+ // 0.5 工具上下文:web_search 语言(档案 preferred_language / language,否则默认中文)
183
+ const contextForTools = await this.attachWebSearchLocale(context, userId);
194
184
  triggerAIHook(createAIHookEvent('message', 'received', sessionId, {
195
185
  userId,
196
186
  content,
@@ -198,22 +188,21 @@ export class ZhinAgent {
198
188
  })).catch(() => { });
199
189
  // 1. Collect tools
200
190
  const tFilter = now();
201
- const allTools = collectRelevantTools(content, context, externalTools, {
191
+ const allTools = collectRuntimeTools({
192
+ content,
193
+ context: contextForTools,
194
+ externalTools,
202
195
  config: this.config,
203
196
  skillRegistry: this.skillRegistry,
204
197
  externalRegistered: this.externalTools,
198
+ sessionId,
199
+ userId,
200
+ memory: this.memory,
201
+ userProfiles: this.userProfiles,
202
+ subagentManager: this.subagentManager,
205
203
  });
206
- // Inject context-aware built-in tools on keyword match
207
- if (KEYWORD_TRIGGERS.chatHistory.test(content)) {
208
- allTools.push(createChatHistoryTool(sessionId, this.memory));
209
- }
210
- if (KEYWORD_TRIGGERS.userProfile.test(content)) {
211
- allTools.push(createUserProfileTool(userId, this.userProfiles));
212
- }
213
- if (this.subagentManager && KEYWORD_TRIGGERS.spawnTask.test(content)) {
214
- allTools.push(createSpawnTaskTool(context, this.subagentManager));
215
- }
216
204
  const filterMs = (now() - tFilter).toFixed(0);
205
+ this.logPhase('tools.collected', sessionId, { count: allTools.length });
217
206
  logger.info(`[工具过滤] ${allTools.length} 个工具: ${allTools.map(t => t.name).join(', ') || '(无)'}`);
218
207
  // 2. History + profile (parallel)
219
208
  const tMem = now();
@@ -221,82 +210,71 @@ export class ZhinAgent {
221
210
  this.buildHistoryMessages(sessionId),
222
211
  this.userProfiles.buildProfileSummary(userId),
223
212
  ]);
224
- const contextTokens = this.config.contextTokens ?? DEFAULT_CONTEXT_TOKENS;
225
- const maxHistoryShare = this.config.maxHistoryShare ?? 0.5;
226
- const pruneResult = pruneHistoryForContext({
213
+ const chatCandidates = this.resolveModelCandidates('chat');
214
+ const { messages: historyMessages, result: pruneResult, budget: contextBudget, } = pruneHistoryWithBudget({
227
215
  messages: rawHistoryMessages,
228
- maxContextTokens: contextTokens,
229
- maxHistoryShare,
216
+ config: this.config,
217
+ provider: this.provider,
218
+ modelRegistry: this.modelRegistry,
219
+ model: chatCandidates[0],
230
220
  });
231
- let historyMessages = pruneResult.messages;
232
221
  if (pruneResult.droppedCount > 0) {
233
222
  logger.debug(`[上下文窗口] 丢弃 ${pruneResult.droppedCount} 条历史消息 (${pruneResult.droppedTokens} tokens)`);
234
223
  }
235
224
  const memMs = (now() - tMem).toFixed(0);
225
+ this.logPhase('context.ready', sessionId, { historyCount: historyMessages.length });
236
226
  // 2.5 Tone + persona
237
227
  const toneHint = this.config.toneAwareness ? detectTone(content).hint : '';
238
228
  const personaEnhanced = buildEnhancedPersona(this.config, profileSummary, toneHint);
239
229
  // 3. No tools → chat path (prefer per-session model, then lightweight model)
240
230
  if (allTools.length === 0) {
231
+ this.logPhase('path.chat', sessionId, { toolCount: 0 });
241
232
  const liteModel = this.config.chatLiteModel || undefined;
242
- logger.info(`[System Prompt] chat-path: ${personaEnhanced.length} chars${liteModel ? `, model=${liteModel}` : ''}`);
233
+ const chatSystemPrompt = this.buildDisciplinedPrompt(personaEnhanced);
234
+ logger.info(`[System Prompt] chat-path: ${chatSystemPrompt.length} chars${liteModel ? `, model=${liteModel}` : ''}`);
243
235
  logger.debug(`[闲聊路径] 过滤=${filterMs}ms, 记忆=${memMs}ms (${historyMessages.length}条), 0 工具`);
244
236
  const tLLM = now();
245
- let reply = await this.streamChatWithHistory(content, personaEnhanced, historyMessages, onChunk, liteModel);
237
+ this.logPhase('chat.llm.start', sessionId, { model: liteModel || chatCandidates[0] || '' });
238
+ let reply = await this.streamChatWithHistory(content, chatSystemPrompt, historyMessages, onChunk, liteModel);
246
239
  reply = stripHallucinatedToolCalls(reply);
247
240
  const llmMs = (now() - tLLM).toFixed(0);
241
+ this.logPhase('chat.llm.end', sessionId, { durationMs: Number(llmMs) });
248
242
  logger.info(`[闲聊路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, LLM=${llmMs}ms, 总=${(now() - t0).toFixed(0)}ms`);
249
243
  await this.saveToSession(sessionId, content, reply, sceneId);
244
+ this.logPhase('turn.end', sessionId, { path: 'chat' });
250
245
  return parseOutput(reply);
251
246
  }
252
247
  logger.debug(`[工具路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, ${allTools.length} 工具 (${allTools.map(t => t.name).join(', ')})`);
253
248
  // 4. Pre-executable tools
254
- const preExecTools = [];
255
- for (const tool of allTools) {
256
- if (tool.preExecutable)
257
- preExecTools.push(tool);
249
+ const preExecCandidates = allTools.filter(tool => tool.preExecutable);
250
+ const tPre = preExecCandidates.length > 0 ? now() : 0;
251
+ if (preExecCandidates.length > 0) {
252
+ logger.debug(`预执行: ${preExecCandidates.map(t => t.name).join(', ')}`);
258
253
  }
259
- // 5. Pre-execution
260
- let preData = '';
261
- if (preExecTools.length > 0) {
262
- const tPre = now();
263
- logger.debug(`预执行: ${preExecTools.map(t => t.name).join(', ')}`);
264
- const results = await Promise.allSettled(preExecTools.map(async (tool) => {
265
- const result = await Promise.race([
266
- tool.execute({}),
267
- new Promise((_, rej) => setTimeout(() => rej(new Error('超时')), this.config.preExecTimeout)),
268
- ]);
269
- return { name: tool.name, result };
270
- }));
271
- for (const r of results) {
272
- if (r.status === 'fulfilled') {
273
- let s = typeof r.value.result === 'string' ? r.value.result : JSON.stringify(r.value.result);
274
- if (s.length > 500) {
275
- s = s.slice(0, 500) + `\n... (truncated, ${s.length} chars total)`;
276
- }
277
- preData += `\n【${r.value.name}】${s}`;
278
- }
279
- }
254
+ const toolRun = await planToolRun(allTools, this.config.preExecTimeout);
255
+ this.logPhase('preexec.done', sessionId, {
256
+ mode: toolRun.mode,
257
+ preExecutedTools: toolRun.preExecution.tools.length,
258
+ });
259
+ const preData = toolRun.preExecution.data;
260
+ if (tPre > 0) {
280
261
  logger.debug(`预执行耗时: ${(now() - tPre).toFixed(0)}ms`);
281
262
  }
282
263
  // 6. Path selection
283
264
  let reply;
284
- const hasNonPreExecTools = allTools.some(t => !t.preExecutable);
285
- if (!hasNonPreExecTools && preData) {
265
+ if (toolRun.mode === 'pre-exec-fast-path') {
266
+ this.logPhase('path.pre_exec_fast', sessionId, { toolCount: allTools.length });
286
267
  // Fast path
287
268
  const tLLM = now();
288
- const prompt = `${personaEnhanced}
289
-
290
- Pre-fetched data (from user's question):
291
- ${preData}
292
-
293
- Answer the user's question based on the data above. Be clear and concise; use emoji when appropriate.`;
269
+ const prompt = this.buildDisciplinedPrompt(buildPreExecFastPathPrompt(personaEnhanced, preData));
294
270
  logger.info(`[System Prompt] fast-path: ${prompt.length} chars`);
271
+ this.logPhase('fast.llm.start', sessionId, { model: chatCandidates[0] || '' });
295
272
  reply = await this.streamChatWithHistory(content, prompt, historyMessages, onChunk);
273
+ this.logPhase('fast.llm.end', sessionId, { durationMs: Math.round(now() - tLLM) });
296
274
  logger.info(`[快速路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, LLM=${(now() - tLLM).toFixed(0)}ms, 总=${(now() - t0).toFixed(0)}ms`);
297
275
  }
298
276
  else {
299
- // Agent path
277
+ this.logPhase('path.agent', sessionId, { toolCount: allTools.length });
300
278
  const tAgent = now();
301
279
  logger.debug(`Agent 路径: ${allTools.length} 个工具`);
302
280
  const contextHint = buildContextHint(context, content);
@@ -316,10 +294,16 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
316
294
  // Adaptive maxIterations: boost when skills are active (multi-step skill flows)
317
295
  const SKILL_ITERATION_BOOST = 3;
318
296
  const hasSkillActivation = agentTools.some(t => t.name === 'activate_skill' || t.name === 'install_skill');
297
+ const harness = resolveModelHarness(this.provider.name, chatCandidates[0] || '', this.config.modelHarness);
298
+ const baseIterations = harness.maxIterations ?? this.config.maxIterations;
319
299
  const effectiveMaxIterations = hasSkillActivation
320
- ? this.config.maxIterations + SKILL_ITERATION_BOOST
321
- : this.config.maxIterations;
322
- const chatCandidates = this.resolveModelCandidates('chat');
300
+ ? baseIterations + SKILL_ITERATION_BOOST
301
+ : baseIterations;
302
+ this.logPhase('harness.resolved', sessionId, {
303
+ model: chatCandidates[0] || '',
304
+ harnessMaxIterations: harness.maxIterations ?? null,
305
+ effectiveMaxIterations,
306
+ });
323
307
  const agent = createAgent(this.provider, {
324
308
  model: chatCandidates[0],
325
309
  modelFallbacks: chatCandidates.slice(1),
@@ -327,11 +311,16 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
327
311
  tools: agentTools,
328
312
  maxIterations: effectiveMaxIterations,
329
313
  turnTimeout: this.config.timeout,
314
+ contextWindow: contextBudget.contextWindow,
315
+ reservedToolNames: RESERVED_TOOL_NAMES,
316
+ reservedToolNamePrefixes: RESERVED_TOOL_NAME_PREFIXES,
330
317
  });
331
318
  const userMessageWithHistory = buildUserMessageWithHistory(historyMessages, content);
332
319
  let result;
333
320
  try {
321
+ this.logPhase('agent.run.start', sessionId, { model: chatCandidates[0] || '' });
334
322
  result = await agent.run(userMessageWithHistory, []);
323
+ this.logPhase('agent.run.end', sessionId, { iterations: result.iterations });
335
324
  }
336
325
  finally {
337
326
  agent.dispose();
@@ -345,8 +334,18 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
345
334
  content: reply,
346
335
  platform: platform || '',
347
336
  })).catch(() => { });
337
+ this.logPhase('turn.end', sessionId, { path: toolRun.mode === 'pre-exec-fast-path' ? 'fast' : 'agent' });
348
338
  return parseOutput(reply);
349
339
  }
340
+ buildDisciplinedPrompt(basePrompt) {
341
+ const discipline = `# Discipline\n${FIXED_DISCIPLINE_RULES.map(rule => `- ${rule}`).join('\n')}`;
342
+ return `${discipline}\n\n${basePrompt}`;
343
+ }
344
+ logPhase(phase, sessionId, extra = {}) {
345
+ if (!this.phaseTraceEnabled)
346
+ return;
347
+ logger.info({ phase, sessionId, ...extra }, '[AGENT_PHASE]');
348
+ }
350
349
  async processMultimodal(parts, context, onChunk) {
351
350
  const { senderId, sceneId, platform } = context;
352
351
  const sessionId = SessionManager.generateId(platform || '', senderId || '', sceneId);
@@ -355,9 +354,9 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
355
354
  if (!rateCheck.allowed) {
356
355
  return parseOutput(rateCheck.message || '请稍后再试');
357
356
  }
358
- const historyMessages = await this.buildHistoryMessages(sessionId);
357
+ const rawHistoryMessages = await this.buildHistoryMessages(sessionId);
359
358
  const profileSummary = await this.userProfiles.buildProfileSummary(userId);
360
- const personaEnhanced = buildEnhancedPersona(this.config, profileSummary, '');
359
+ const personaEnhanced = this.buildDisciplinedPrompt(buildEnhancedPersona(this.config, profileSummary, ''));
361
360
  // Build text summary describing the multimodal content
362
361
  const textFragments = [];
363
362
  const llmParts = [];
@@ -388,6 +387,16 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
388
387
  }
389
388
  const textContent = textFragments.join(' ') || '[多模态消息]';
390
389
  const visionCandidates = this.resolveModelCandidates('vision');
390
+ const { messages: historyMessages, result: pruneResult } = pruneHistoryWithBudget({
391
+ messages: rawHistoryMessages,
392
+ config: this.config,
393
+ provider: this.provider,
394
+ modelRegistry: this.modelRegistry,
395
+ model: visionCandidates[0],
396
+ });
397
+ if (pruneResult.droppedCount > 0) {
398
+ logger.debug(`[多模态上下文窗口] 丢弃 ${pruneResult.droppedCount} 条历史消息 (${pruneResult.droppedTokens} tokens)`);
399
+ }
391
400
  const messages = [
392
401
  { role: 'system', content: personaEnhanced },
393
402
  ...historyMessages,
@@ -441,6 +450,29 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
441
450
  return parseOutput(reply);
442
451
  }
443
452
  // ── Internal helpers ────────────────────────────────────────────────
453
+ /**
454
+ * 为内置工具注入 `extra.web_search_locale`:
455
+ * - 若调用方已在 `context.extra.web_search_locale` 中设置,则规范化后沿用;
456
+ * - 否则读取用户档案 `preferred_language` / `language`;
457
+ * - 均未设置时不在 extra 中写入,web_search 默认使用中文市场。
458
+ */
459
+ async attachWebSearchLocale(context, userId) {
460
+ const extra = { ...(context.extra ?? {}) };
461
+ const existing = extra[WEB_SEARCH_LOCALE_EXTRA_KEY];
462
+ if (typeof existing === 'string' && existing.trim()) {
463
+ extra[WEB_SEARCH_LOCALE_EXTRA_KEY] = normalizeWebSearchLocaleHint(existing);
464
+ return { ...context, extra };
465
+ }
466
+ const [preferred, language] = await Promise.all([
467
+ this.userProfiles.get(userId, 'preferred_language'),
468
+ this.userProfiles.get(userId, 'language'),
469
+ ]);
470
+ const hint = (preferred ?? language)?.trim();
471
+ if (hint) {
472
+ extra[WEB_SEARCH_LOCALE_EXTRA_KEY] = normalizeWebSearchLocaleHint(hint);
473
+ }
474
+ return { ...context, extra };
475
+ }
444
476
  async buildHistoryMessages(sessionId) {
445
477
  return this.memory.buildContext(sessionId);
446
478
  }