@zhin.js/agent 0.1.14 → 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 -84
  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,40 +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
- // <function=name>…</function>
51
- cleaned = cleaned.replace(/<function=[^>]*>[\s\S]*?<\/function>/gi, '');
52
- // <|plugin|>…<|/plugin|> (some Chinese models)
53
- cleaned = cleaned.replace(/<\|plugin\|>[\s\S]*?<\|\/plugin\|>/gi, '');
54
- // <<<tool_call>>> … <<<end>>> style
55
- cleaned = cleaned.replace(/<<<tool_call>>>[\s\S]*?<<<end>>>/gi, '');
56
- return cleaned.trim();
57
- }
58
40
  // ============================================================================
59
41
  // ZhinAgent
60
42
  // ============================================================================
@@ -73,9 +55,11 @@ export class ZhinAgent {
73
55
  activeSkillsContext = '';
74
56
  skillsSummaryXML = '';
75
57
  modelRegistry = null;
58
+ phaseTraceEnabled;
76
59
  constructor(provider, config) {
77
60
  this.provider = provider;
78
61
  this.config = { ...DEFAULT_CONFIG, ...config };
62
+ this.phaseTraceEnabled = isPhaseTraceEnabled(this.config);
79
63
  this.sessions = createMemorySessionManager();
80
64
  this.memory = new ConversationMemory({
81
65
  minTopicRounds: this.config.minTopicRounds,
@@ -101,6 +85,7 @@ export class ZhinAgent {
101
85
  }
102
86
  setModelRegistry(registry) {
103
87
  this.modelRegistry = registry;
88
+ this.subagentManager?.setModelRegistry(registry);
104
89
  }
105
90
  upgradeMemoryToDatabase(msgModel, sumModel) {
106
91
  this.memory.upgradeToDatabase(msgModel, sumModel);
@@ -113,8 +98,10 @@ export class ZhinAgent {
113
98
  provider: this.provider,
114
99
  workspace: process.cwd(),
115
100
  createTools,
101
+ subagentTools: this.config.subagentTools,
116
102
  maxIterations: this.config.maxSubagentIterations,
117
103
  execPolicyConfig: this.config,
104
+ modelRegistry: this.modelRegistry,
118
105
  });
119
106
  logger.debug('SubagentManager initialized');
120
107
  }
@@ -181,12 +168,19 @@ export class ZhinAgent {
181
168
  const { senderId, sceneId, platform } = context;
182
169
  const sessionId = SessionManager.generateId(platform || '', senderId || '', sceneId);
183
170
  const userId = senderId || 'unknown';
171
+ this.logPhase('turn.start', sessionId, {
172
+ mode: 'text',
173
+ provider: this.provider.name,
174
+ });
184
175
  // 0. Rate limit
185
176
  const rateCheck = this.rateLimiter.check(userId);
186
177
  if (!rateCheck.allowed) {
178
+ this.logPhase('turn.rate_limited', sessionId, { userId });
187
179
  logger.debug(`[速率限制] 用户 ${userId} 被限制: ${rateCheck.message}`);
188
180
  return parseOutput(rateCheck.message || '请稍后再试');
189
181
  }
182
+ // 0.5 工具上下文:web_search 语言(档案 preferred_language / language,否则默认中文)
183
+ const contextForTools = await this.attachWebSearchLocale(context, userId);
190
184
  triggerAIHook(createAIHookEvent('message', 'received', sessionId, {
191
185
  userId,
192
186
  content,
@@ -194,22 +188,21 @@ export class ZhinAgent {
194
188
  })).catch(() => { });
195
189
  // 1. Collect tools
196
190
  const tFilter = now();
197
- const allTools = collectRelevantTools(content, context, externalTools, {
191
+ const allTools = collectRuntimeTools({
192
+ content,
193
+ context: contextForTools,
194
+ externalTools,
198
195
  config: this.config,
199
196
  skillRegistry: this.skillRegistry,
200
197
  externalRegistered: this.externalTools,
198
+ sessionId,
199
+ userId,
200
+ memory: this.memory,
201
+ userProfiles: this.userProfiles,
202
+ subagentManager: this.subagentManager,
201
203
  });
202
- // Inject context-aware built-in tools on keyword match
203
- if (KEYWORD_TRIGGERS.chatHistory.test(content)) {
204
- allTools.push(createChatHistoryTool(sessionId, this.memory));
205
- }
206
- if (KEYWORD_TRIGGERS.userProfile.test(content)) {
207
- allTools.push(createUserProfileTool(userId, this.userProfiles));
208
- }
209
- if (this.subagentManager && KEYWORD_TRIGGERS.spawnTask.test(content)) {
210
- allTools.push(createSpawnTaskTool(context, this.subagentManager));
211
- }
212
204
  const filterMs = (now() - tFilter).toFixed(0);
205
+ this.logPhase('tools.collected', sessionId, { count: allTools.length });
213
206
  logger.info(`[工具过滤] ${allTools.length} 个工具: ${allTools.map(t => t.name).join(', ') || '(无)'}`);
214
207
  // 2. History + profile (parallel)
215
208
  const tMem = now();
@@ -217,82 +210,71 @@ export class ZhinAgent {
217
210
  this.buildHistoryMessages(sessionId),
218
211
  this.userProfiles.buildProfileSummary(userId),
219
212
  ]);
220
- const contextTokens = this.config.contextTokens ?? DEFAULT_CONTEXT_TOKENS;
221
- const maxHistoryShare = this.config.maxHistoryShare ?? 0.5;
222
- const pruneResult = pruneHistoryForContext({
213
+ const chatCandidates = this.resolveModelCandidates('chat');
214
+ const { messages: historyMessages, result: pruneResult, budget: contextBudget, } = pruneHistoryWithBudget({
223
215
  messages: rawHistoryMessages,
224
- maxContextTokens: contextTokens,
225
- maxHistoryShare,
216
+ config: this.config,
217
+ provider: this.provider,
218
+ modelRegistry: this.modelRegistry,
219
+ model: chatCandidates[0],
226
220
  });
227
- let historyMessages = pruneResult.messages;
228
221
  if (pruneResult.droppedCount > 0) {
229
222
  logger.debug(`[上下文窗口] 丢弃 ${pruneResult.droppedCount} 条历史消息 (${pruneResult.droppedTokens} tokens)`);
230
223
  }
231
224
  const memMs = (now() - tMem).toFixed(0);
225
+ this.logPhase('context.ready', sessionId, { historyCount: historyMessages.length });
232
226
  // 2.5 Tone + persona
233
227
  const toneHint = this.config.toneAwareness ? detectTone(content).hint : '';
234
228
  const personaEnhanced = buildEnhancedPersona(this.config, profileSummary, toneHint);
235
229
  // 3. No tools → chat path (prefer per-session model, then lightweight model)
236
230
  if (allTools.length === 0) {
231
+ this.logPhase('path.chat', sessionId, { toolCount: 0 });
237
232
  const liteModel = this.config.chatLiteModel || undefined;
238
- 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}` : ''}`);
239
235
  logger.debug(`[闲聊路径] 过滤=${filterMs}ms, 记忆=${memMs}ms (${historyMessages.length}条), 0 工具`);
240
236
  const tLLM = now();
241
- 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);
242
239
  reply = stripHallucinatedToolCalls(reply);
243
240
  const llmMs = (now() - tLLM).toFixed(0);
241
+ this.logPhase('chat.llm.end', sessionId, { durationMs: Number(llmMs) });
244
242
  logger.info(`[闲聊路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, LLM=${llmMs}ms, 总=${(now() - t0).toFixed(0)}ms`);
245
243
  await this.saveToSession(sessionId, content, reply, sceneId);
244
+ this.logPhase('turn.end', sessionId, { path: 'chat' });
246
245
  return parseOutput(reply);
247
246
  }
248
247
  logger.debug(`[工具路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, ${allTools.length} 工具 (${allTools.map(t => t.name).join(', ')})`);
249
248
  // 4. Pre-executable tools
250
- const preExecTools = [];
251
- for (const tool of allTools) {
252
- if (tool.preExecutable)
253
- 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(', ')}`);
254
253
  }
255
- // 5. Pre-execution
256
- let preData = '';
257
- if (preExecTools.length > 0) {
258
- const tPre = now();
259
- logger.debug(`预执行: ${preExecTools.map(t => t.name).join(', ')}`);
260
- const results = await Promise.allSettled(preExecTools.map(async (tool) => {
261
- const result = await Promise.race([
262
- tool.execute({}),
263
- new Promise((_, rej) => setTimeout(() => rej(new Error('超时')), this.config.preExecTimeout)),
264
- ]);
265
- return { name: tool.name, result };
266
- }));
267
- for (const r of results) {
268
- if (r.status === 'fulfilled') {
269
- let s = typeof r.value.result === 'string' ? r.value.result : JSON.stringify(r.value.result);
270
- if (s.length > 500) {
271
- s = s.slice(0, 500) + `\n... (truncated, ${s.length} chars total)`;
272
- }
273
- preData += `\n【${r.value.name}】${s}`;
274
- }
275
- }
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) {
276
261
  logger.debug(`预执行耗时: ${(now() - tPre).toFixed(0)}ms`);
277
262
  }
278
263
  // 6. Path selection
279
264
  let reply;
280
- const hasNonPreExecTools = allTools.some(t => !t.preExecutable);
281
- if (!hasNonPreExecTools && preData) {
265
+ if (toolRun.mode === 'pre-exec-fast-path') {
266
+ this.logPhase('path.pre_exec_fast', sessionId, { toolCount: allTools.length });
282
267
  // Fast path
283
268
  const tLLM = now();
284
- const prompt = `${personaEnhanced}
285
-
286
- Pre-fetched data (from user's question):
287
- ${preData}
288
-
289
- 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));
290
270
  logger.info(`[System Prompt] fast-path: ${prompt.length} chars`);
271
+ this.logPhase('fast.llm.start', sessionId, { model: chatCandidates[0] || '' });
291
272
  reply = await this.streamChatWithHistory(content, prompt, historyMessages, onChunk);
273
+ this.logPhase('fast.llm.end', sessionId, { durationMs: Math.round(now() - tLLM) });
292
274
  logger.info(`[快速路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, LLM=${(now() - tLLM).toFixed(0)}ms, 总=${(now() - t0).toFixed(0)}ms`);
293
275
  }
294
276
  else {
295
- // Agent path
277
+ this.logPhase('path.agent', sessionId, { toolCount: allTools.length });
296
278
  const tAgent = now();
297
279
  logger.debug(`Agent 路径: ${allTools.length} 个工具`);
298
280
  const contextHint = buildContextHint(context, content);
@@ -312,10 +294,16 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
312
294
  // Adaptive maxIterations: boost when skills are active (multi-step skill flows)
313
295
  const SKILL_ITERATION_BOOST = 3;
314
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;
315
299
  const effectiveMaxIterations = hasSkillActivation
316
- ? this.config.maxIterations + SKILL_ITERATION_BOOST
317
- : this.config.maxIterations;
318
- 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
+ });
319
307
  const agent = createAgent(this.provider, {
320
308
  model: chatCandidates[0],
321
309
  modelFallbacks: chatCandidates.slice(1),
@@ -323,11 +311,16 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
323
311
  tools: agentTools,
324
312
  maxIterations: effectiveMaxIterations,
325
313
  turnTimeout: this.config.timeout,
314
+ contextWindow: contextBudget.contextWindow,
315
+ reservedToolNames: RESERVED_TOOL_NAMES,
316
+ reservedToolNamePrefixes: RESERVED_TOOL_NAME_PREFIXES,
326
317
  });
327
318
  const userMessageWithHistory = buildUserMessageWithHistory(historyMessages, content);
328
319
  let result;
329
320
  try {
321
+ this.logPhase('agent.run.start', sessionId, { model: chatCandidates[0] || '' });
330
322
  result = await agent.run(userMessageWithHistory, []);
323
+ this.logPhase('agent.run.end', sessionId, { iterations: result.iterations });
331
324
  }
332
325
  finally {
333
326
  agent.dispose();
@@ -341,8 +334,18 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
341
334
  content: reply,
342
335
  platform: platform || '',
343
336
  })).catch(() => { });
337
+ this.logPhase('turn.end', sessionId, { path: toolRun.mode === 'pre-exec-fast-path' ? 'fast' : 'agent' });
344
338
  return parseOutput(reply);
345
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
+ }
346
349
  async processMultimodal(parts, context, onChunk) {
347
350
  const { senderId, sceneId, platform } = context;
348
351
  const sessionId = SessionManager.generateId(platform || '', senderId || '', sceneId);
@@ -351,9 +354,9 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
351
354
  if (!rateCheck.allowed) {
352
355
  return parseOutput(rateCheck.message || '请稍后再试');
353
356
  }
354
- const historyMessages = await this.buildHistoryMessages(sessionId);
357
+ const rawHistoryMessages = await this.buildHistoryMessages(sessionId);
355
358
  const profileSummary = await this.userProfiles.buildProfileSummary(userId);
356
- const personaEnhanced = buildEnhancedPersona(this.config, profileSummary, '');
359
+ const personaEnhanced = this.buildDisciplinedPrompt(buildEnhancedPersona(this.config, profileSummary, ''));
357
360
  // Build text summary describing the multimodal content
358
361
  const textFragments = [];
359
362
  const llmParts = [];
@@ -384,6 +387,16 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
384
387
  }
385
388
  const textContent = textFragments.join(' ') || '[多模态消息]';
386
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
+ }
387
400
  const messages = [
388
401
  { role: 'system', content: personaEnhanced },
389
402
  ...historyMessages,
@@ -437,6 +450,29 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
437
450
  return parseOutput(reply);
438
451
  }
439
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
+ }
440
476
  async buildHistoryMessages(sessionId) {
441
477
  return this.memory.buildContext(sessionId);
442
478
  }