@zhin.js/core 1.3.1 → 1.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 (358) hide show
  1. package/README.md +66 -11
  2. package/lib/adapter.d.ts +41 -3
  3. package/lib/adapter.js +110 -6
  4. package/lib/agent-prompt.d.ts +0 -1
  5. package/lib/agent-prompt.js +0 -1
  6. package/lib/built/adapter-process.d.ts +11 -2
  7. package/lib/built/adapter-process.js +43 -2
  8. package/lib/built/agent-preset.d.ts +0 -1
  9. package/lib/built/agent-preset.js +0 -1
  10. package/lib/built/ai-access.d.ts +36 -0
  11. package/lib/built/ai-access.js +46 -0
  12. package/lib/built/ai-outbound/adapter-access.d.ts +3 -0
  13. package/lib/built/ai-outbound/adapter-access.js +9 -0
  14. package/lib/built/ai-outbound/extensions/onebot-keyboard.d.ts +2 -0
  15. package/lib/built/ai-outbound/extensions/onebot-keyboard.js +67 -0
  16. package/lib/built/ai-outbound/extensions/qq-message.d.ts +3 -0
  17. package/lib/built/ai-outbound/extensions/qq-message.js +23 -0
  18. package/lib/built/ai-outbound/index.d.ts +9 -0
  19. package/lib/built/ai-outbound/index.js +9 -0
  20. package/lib/built/ai-outbound/parse.d.ts +13 -0
  21. package/lib/built/ai-outbound/parse.js +94 -0
  22. package/lib/built/ai-outbound/plain-mention-rewrite.d.ts +6 -0
  23. package/lib/built/ai-outbound/plain-mention-rewrite.js +37 -0
  24. package/lib/built/ai-outbound/prompt.d.ts +11 -0
  25. package/lib/built/ai-outbound/prompt.js +44 -0
  26. package/lib/built/ai-outbound/resolve.d.ts +4 -0
  27. package/lib/built/ai-outbound/resolve.js +64 -0
  28. package/lib/built/ai-outbound/structured-detect.d.ts +3 -0
  29. package/lib/built/ai-outbound/structured-detect.js +7 -0
  30. package/lib/built/ai-outbound/types.d.ts +60 -0
  31. package/lib/built/ai-outbound/types.js +5 -0
  32. package/lib/built/ai-trigger.d.ts +5 -1
  33. package/lib/built/ai-trigger.js +3 -7
  34. package/lib/built/authorization.d.ts +0 -1
  35. package/lib/built/authorization.js +0 -1
  36. package/lib/built/command.d.ts +2 -1
  37. package/lib/built/command.js +14 -4
  38. package/lib/built/common-adapter-tools.d.ts +25 -26
  39. package/lib/built/common-adapter-tools.js +48 -49
  40. package/lib/built/component.d.ts +0 -1
  41. package/lib/built/component.js +1 -3
  42. package/lib/built/config.d.ts +4 -1
  43. package/lib/built/config.js +26 -5
  44. package/lib/built/connect-endpoint-instance.d.ts +0 -1
  45. package/lib/built/connect-endpoint-instance.js +3 -2
  46. package/lib/built/database.d.ts +0 -1
  47. package/lib/built/database.js +1 -3
  48. package/lib/built/dispatcher.d.ts +6 -6
  49. package/lib/built/dispatcher.js +20 -8
  50. package/lib/built/endpoint-commands.d.ts +3 -0
  51. package/lib/built/endpoint-commands.js +99 -0
  52. package/lib/built/endpoint-lifecycle-service.d.ts +28 -0
  53. package/lib/built/endpoint-lifecycle-service.js +241 -0
  54. package/lib/built/endpoint-lifecycle.d.ts +0 -1
  55. package/lib/built/endpoint-lifecycle.js +0 -1
  56. package/lib/built/endpoint-manager.d.ts +34 -0
  57. package/lib/built/endpoint-manager.js +1 -0
  58. package/lib/built/generated-qrcode.d.ts +24 -0
  59. package/lib/built/generated-qrcode.js +45 -0
  60. package/lib/built/generic-segment-mapper.d.ts +6 -0
  61. package/lib/built/generic-segment-mapper.js +232 -0
  62. package/lib/built/html-renderer-loader.d.ts +13 -0
  63. package/lib/built/html-renderer-loader.js +33 -0
  64. package/lib/built/html-segment-fallback.d.ts +2 -2
  65. package/lib/built/html-segment-fallback.js +0 -1
  66. package/lib/built/html-to-text.d.ts +0 -1
  67. package/lib/built/html-to-text.js +0 -1
  68. package/lib/built/inbound-pipeline.d.ts +0 -1
  69. package/lib/built/inbound-pipeline.js +0 -1
  70. package/lib/built/inbound-runner.d.ts +0 -1
  71. package/lib/built/inbound-runner.js +0 -1
  72. package/lib/built/interactive-segment-contract.d.ts +6 -0
  73. package/lib/built/interactive-segment-contract.js +9 -0
  74. package/lib/built/interactive-segments/action.d.ts +17 -0
  75. package/lib/built/interactive-segments/action.js +54 -0
  76. package/lib/built/interactive-segments/button-spec.d.ts +10 -0
  77. package/lib/built/interactive-segments/button-spec.js +21 -0
  78. package/lib/built/interactive-segments/handlers.d.ts +9 -0
  79. package/lib/built/interactive-segments/handlers.js +58 -0
  80. package/lib/built/interactive-segments/index.d.ts +7 -0
  81. package/lib/built/interactive-segments/index.js +7 -0
  82. package/lib/built/interactive-segments/keyboard-segment.d.ts +12 -0
  83. package/lib/built/interactive-segments/keyboard-segment.js +13 -0
  84. package/lib/built/interactive-segments/onebot-keyboard.d.ts +10 -0
  85. package/lib/built/interactive-segments/onebot-keyboard.js +53 -0
  86. package/lib/built/interactive-segments/resolve.d.ts +9 -0
  87. package/lib/built/interactive-segments/resolve.js +84 -0
  88. package/lib/built/interactive-segments/types.d.ts +62 -0
  89. package/lib/built/interactive-segments/types.js +13 -0
  90. package/lib/built/introspection-format.d.ts +10 -0
  91. package/lib/built/introspection-format.js +28 -0
  92. package/lib/built/login-assist.d.ts +1 -2
  93. package/lib/built/login-assist.js +0 -1
  94. package/lib/built/management-command-guard.d.ts +15 -0
  95. package/lib/built/management-command-guard.js +25 -0
  96. package/lib/built/message-enrich.d.ts +0 -1
  97. package/lib/built/message-enrich.js +0 -1
  98. package/lib/built/message-filter.d.ts +0 -1
  99. package/lib/built/message-filter.js +1 -3
  100. package/lib/built/optional-peer-import.d.ts +3 -0
  101. package/lib/built/optional-peer-import.js +33 -0
  102. package/lib/built/outbound-media-contract.d.ts +22 -0
  103. package/lib/built/outbound-media-contract.js +10 -0
  104. package/lib/built/outbound-media-utils.d.ts +9 -0
  105. package/lib/built/outbound-media-utils.js +62 -0
  106. package/lib/built/permission.d.ts +0 -1
  107. package/lib/built/permission.js +1 -3
  108. package/lib/built/permit-check.d.ts +0 -1
  109. package/lib/built/permit-check.js +0 -1
  110. package/lib/built/permit-parse.d.ts +0 -1
  111. package/lib/built/permit-parse.js +0 -1
  112. package/lib/built/platform-permit.d.ts +5 -6
  113. package/lib/built/platform-permit.js +11 -12
  114. package/lib/built/prepend-quote-context.d.ts +0 -1
  115. package/lib/built/prepend-quote-context.js +0 -1
  116. package/lib/built/qrcode-segment.d.ts +18 -0
  117. package/lib/built/qrcode-segment.js +78 -0
  118. package/lib/built/queue-im-field-contract.d.ts +6 -1
  119. package/lib/built/queue-im-field-contract.js +10 -1
  120. package/lib/built/rich-segments/adapter-policies.d.ts +9 -0
  121. package/lib/built/rich-segments/adapter-policies.js +27 -0
  122. package/lib/built/rich-segments/base.d.ts +11 -0
  123. package/lib/built/rich-segments/base.js +24 -0
  124. package/lib/built/rich-segments/builtins.d.ts +4 -0
  125. package/lib/built/rich-segments/builtins.js +40 -0
  126. package/lib/built/rich-segments/capabilities.d.ts +6 -0
  127. package/lib/built/rich-segments/capabilities.js +39 -0
  128. package/lib/built/rich-segments/html-segment.d.ts +15 -0
  129. package/lib/built/rich-segments/html-segment.js +65 -0
  130. package/lib/built/rich-segments/index.d.ts +13 -0
  131. package/lib/built/rich-segments/index.js +13 -0
  132. package/lib/built/rich-segments/markdown-segment.d.ts +14 -0
  133. package/lib/built/rich-segments/markdown-segment.js +61 -0
  134. package/lib/built/rich-segments/markdown-to-text.d.ts +3 -0
  135. package/lib/built/rich-segments/markdown-to-text.js +27 -0
  136. package/lib/built/rich-segments/qrcode-segment.d.ts +18 -0
  137. package/lib/built/rich-segments/qrcode-segment.js +73 -0
  138. package/lib/built/rich-segments/registry.d.ts +16 -0
  139. package/lib/built/rich-segments/registry.js +52 -0
  140. package/lib/built/rich-segments/resolve.d.ts +5 -0
  141. package/lib/built/rich-segments/resolve.js +87 -0
  142. package/lib/built/rich-segments/tts-segment.d.ts +13 -0
  143. package/lib/built/rich-segments/tts-segment.js +51 -0
  144. package/lib/built/rich-segments/types.d.ts +84 -0
  145. package/lib/built/rich-segments/types.js +17 -0
  146. package/lib/built/roles.d.ts +0 -1
  147. package/lib/built/roles.js +0 -1
  148. package/lib/built/runtime-io.d.ts +0 -1
  149. package/lib/built/runtime-io.js +0 -1
  150. package/lib/built/schedule.d.ts +55 -0
  151. package/lib/built/schedule.js +112 -0
  152. package/lib/built/schema-endpoint-manager.d.ts +17 -0
  153. package/lib/built/schema-endpoint-manager.js +73 -0
  154. package/lib/built/schema-feature.d.ts +0 -1
  155. package/lib/built/schema-feature.js +1 -3
  156. package/lib/built/segment-contract/assert.d.ts +4 -0
  157. package/lib/built/segment-contract/assert.js +30 -0
  158. package/lib/built/segment-contract/delivery.d.ts +5 -0
  159. package/lib/built/segment-contract/delivery.js +40 -0
  160. package/lib/built/segment-contract/image.d.ts +5 -0
  161. package/lib/built/segment-contract/image.js +10 -0
  162. package/lib/built/segment-contract/index.d.ts +8 -0
  163. package/lib/built/segment-contract/index.js +7 -0
  164. package/lib/built/segment-contract/media.d.ts +8 -0
  165. package/lib/built/segment-contract/media.js +39 -0
  166. package/lib/built/segment-contract/mention.d.ts +10 -0
  167. package/lib/built/segment-contract/mention.js +26 -0
  168. package/lib/built/segment-contract/preview.d.ts +3 -0
  169. package/lib/built/segment-contract/preview.js +159 -0
  170. package/lib/built/segment-contract/types.d.ts +70 -0
  171. package/lib/built/segment-contract/types.js +5 -0
  172. package/lib/built/segment-contract/validate.d.ts +138 -0
  173. package/lib/built/segment-contract/validate.js +124 -0
  174. package/lib/built/skill.d.ts +0 -1
  175. package/lib/built/skill.js +0 -1
  176. package/lib/built/speech-loader.d.ts +14 -0
  177. package/lib/built/speech-loader.js +32 -0
  178. package/lib/built/tool.d.ts +0 -1
  179. package/lib/built/tool.js +1 -3
  180. package/lib/command.d.ts +12 -7
  181. package/lib/command.js +38 -16
  182. package/lib/component.d.ts +0 -1
  183. package/lib/component.js +0 -1
  184. package/lib/endpoint-capabilities.d.ts +3 -1
  185. package/lib/endpoint-capabilities.js +0 -1
  186. package/lib/endpoint.d.ts +0 -1
  187. package/lib/endpoint.js +0 -1
  188. package/lib/errors.d.ts +0 -1
  189. package/lib/errors.js +0 -1
  190. package/lib/host-plugin-registry.d.ts +0 -1
  191. package/lib/host-plugin-registry.js +0 -1
  192. package/lib/im-scene.d.ts +29 -0
  193. package/lib/im-scene.js +77 -0
  194. package/lib/im-session-id.d.ts +25 -12
  195. package/lib/im-session-id.js +35 -17
  196. package/lib/index.d.ts +25 -5
  197. package/lib/index.js +22 -4
  198. package/lib/jsx-dev-runtime.d.ts +0 -1
  199. package/lib/jsx-dev-runtime.js +0 -1
  200. package/lib/jsx-runtime.d.ts +0 -1
  201. package/lib/jsx-runtime.js +0 -1
  202. package/lib/jsx.d.ts +0 -1
  203. package/lib/jsx.js +0 -1
  204. package/lib/message-quote.d.ts +1 -2
  205. package/lib/message-quote.js +2 -3
  206. package/lib/message.d.ts +12 -2
  207. package/lib/message.js +16 -1
  208. package/lib/models/system-log.d.ts +0 -1
  209. package/lib/models/system-log.js +0 -1
  210. package/lib/models/user.d.ts +0 -1
  211. package/lib/models/user.js +0 -1
  212. package/lib/notice.d.ts +0 -1
  213. package/lib/notice.js +0 -1
  214. package/lib/plugin-context.d.ts +0 -1
  215. package/lib/plugin-context.js +0 -1
  216. package/lib/plugin.d.ts +11 -2
  217. package/lib/plugin.js +22 -23
  218. package/lib/prompt.d.ts +0 -1
  219. package/lib/prompt.js +1 -2
  220. package/lib/request.d.ts +0 -1
  221. package/lib/request.js +0 -1
  222. package/lib/tool-zod.d.ts +0 -1
  223. package/lib/tool-zod.js +0 -1
  224. package/lib/types-generator.d.ts +0 -1
  225. package/lib/types-generator.js +0 -1
  226. package/lib/types.d.ts +30 -11
  227. package/lib/types.js +0 -1
  228. package/lib/utils.d.ts +57 -12
  229. package/lib/utils.js +54 -19
  230. package/package.json +18 -9
  231. package/lib/adapter.d.ts.map +0 -1
  232. package/lib/adapter.js.map +0 -1
  233. package/lib/agent-prompt.d.ts.map +0 -1
  234. package/lib/agent-prompt.js.map +0 -1
  235. package/lib/built/adapter-process.d.ts.map +0 -1
  236. package/lib/built/adapter-process.js.map +0 -1
  237. package/lib/built/agent-preset.d.ts.map +0 -1
  238. package/lib/built/agent-preset.js.map +0 -1
  239. package/lib/built/ai-trigger.d.ts.map +0 -1
  240. package/lib/built/ai-trigger.js.map +0 -1
  241. package/lib/built/authorization.d.ts.map +0 -1
  242. package/lib/built/authorization.js.map +0 -1
  243. package/lib/built/command.d.ts.map +0 -1
  244. package/lib/built/command.js.map +0 -1
  245. package/lib/built/common-adapter-tools.d.ts.map +0 -1
  246. package/lib/built/common-adapter-tools.js.map +0 -1
  247. package/lib/built/component.d.ts.map +0 -1
  248. package/lib/built/component.js.map +0 -1
  249. package/lib/built/config.d.ts.map +0 -1
  250. package/lib/built/config.js.map +0 -1
  251. package/lib/built/connect-endpoint-instance.d.ts.map +0 -1
  252. package/lib/built/connect-endpoint-instance.js.map +0 -1
  253. package/lib/built/cron.d.ts +0 -75
  254. package/lib/built/cron.d.ts.map +0 -1
  255. package/lib/built/cron.js +0 -122
  256. package/lib/built/cron.js.map +0 -1
  257. package/lib/built/database.d.ts.map +0 -1
  258. package/lib/built/database.js.map +0 -1
  259. package/lib/built/dispatcher.d.ts.map +0 -1
  260. package/lib/built/dispatcher.js.map +0 -1
  261. package/lib/built/endpoint-lifecycle.d.ts.map +0 -1
  262. package/lib/built/endpoint-lifecycle.js.map +0 -1
  263. package/lib/built/html-segment-fallback.d.ts.map +0 -1
  264. package/lib/built/html-segment-fallback.js.map +0 -1
  265. package/lib/built/html-to-text.d.ts.map +0 -1
  266. package/lib/built/html-to-text.js.map +0 -1
  267. package/lib/built/inbound-pipeline.d.ts.map +0 -1
  268. package/lib/built/inbound-pipeline.js.map +0 -1
  269. package/lib/built/inbound-runner.d.ts.map +0 -1
  270. package/lib/built/inbound-runner.js.map +0 -1
  271. package/lib/built/login-assist.d.ts.map +0 -1
  272. package/lib/built/login-assist.js.map +0 -1
  273. package/lib/built/mcp-mesh-registrar.d.ts +0 -9
  274. package/lib/built/mcp-mesh-registrar.d.ts.map +0 -1
  275. package/lib/built/mcp-mesh-registrar.js +0 -17
  276. package/lib/built/mcp-mesh-registrar.js.map +0 -1
  277. package/lib/built/message-enrich.d.ts.map +0 -1
  278. package/lib/built/message-enrich.js.map +0 -1
  279. package/lib/built/message-filter.d.ts.map +0 -1
  280. package/lib/built/message-filter.js.map +0 -1
  281. package/lib/built/permission.d.ts.map +0 -1
  282. package/lib/built/permission.js.map +0 -1
  283. package/lib/built/permit-check.d.ts.map +0 -1
  284. package/lib/built/permit-check.js.map +0 -1
  285. package/lib/built/permit-parse.d.ts.map +0 -1
  286. package/lib/built/permit-parse.js.map +0 -1
  287. package/lib/built/platform-permit.d.ts.map +0 -1
  288. package/lib/built/platform-permit.js.map +0 -1
  289. package/lib/built/prepend-quote-context.d.ts.map +0 -1
  290. package/lib/built/prepend-quote-context.js.map +0 -1
  291. package/lib/built/queue-im-field-contract.d.ts.map +0 -1
  292. package/lib/built/queue-im-field-contract.js.map +0 -1
  293. package/lib/built/roles.d.ts.map +0 -1
  294. package/lib/built/roles.js.map +0 -1
  295. package/lib/built/runtime-io.d.ts.map +0 -1
  296. package/lib/built/runtime-io.js.map +0 -1
  297. package/lib/built/schema-feature.d.ts.map +0 -1
  298. package/lib/built/schema-feature.js.map +0 -1
  299. package/lib/built/skill.d.ts.map +0 -1
  300. package/lib/built/skill.js.map +0 -1
  301. package/lib/built/tool.d.ts.map +0 -1
  302. package/lib/built/tool.js.map +0 -1
  303. package/lib/command.d.ts.map +0 -1
  304. package/lib/command.js.map +0 -1
  305. package/lib/component.d.ts.map +0 -1
  306. package/lib/component.js.map +0 -1
  307. package/lib/endpoint-capabilities.d.ts.map +0 -1
  308. package/lib/endpoint-capabilities.js.map +0 -1
  309. package/lib/endpoint.d.ts.map +0 -1
  310. package/lib/endpoint.js.map +0 -1
  311. package/lib/errors.d.ts.map +0 -1
  312. package/lib/errors.js.map +0 -1
  313. package/lib/host-plugin-registry.d.ts.map +0 -1
  314. package/lib/host-plugin-registry.js.map +0 -1
  315. package/lib/im-session-id.d.ts.map +0 -1
  316. package/lib/im-session-id.js.map +0 -1
  317. package/lib/index.d.ts.map +0 -1
  318. package/lib/index.js.map +0 -1
  319. package/lib/jsx-dev-runtime.d.ts.map +0 -1
  320. package/lib/jsx-dev-runtime.js.map +0 -1
  321. package/lib/jsx-runtime.d.ts.map +0 -1
  322. package/lib/jsx-runtime.js.map +0 -1
  323. package/lib/jsx.d.ts.map +0 -1
  324. package/lib/jsx.js.map +0 -1
  325. package/lib/message-quote.d.ts.map +0 -1
  326. package/lib/message-quote.js.map +0 -1
  327. package/lib/message.d.ts.map +0 -1
  328. package/lib/message.js.map +0 -1
  329. package/lib/models/system-log.d.ts.map +0 -1
  330. package/lib/models/system-log.js.map +0 -1
  331. package/lib/models/user.d.ts.map +0 -1
  332. package/lib/models/user.js.map +0 -1
  333. package/lib/notice.d.ts.map +0 -1
  334. package/lib/notice.js.map +0 -1
  335. package/lib/plugin-context.d.ts.map +0 -1
  336. package/lib/plugin-context.js.map +0 -1
  337. package/lib/plugin.d.ts.map +0 -1
  338. package/lib/plugin.js.map +0 -1
  339. package/lib/prompt.d.ts.map +0 -1
  340. package/lib/prompt.js.map +0 -1
  341. package/lib/request.d.ts.map +0 -1
  342. package/lib/request.js.map +0 -1
  343. package/lib/scheduler/scheduler.d.ts +0 -49
  344. package/lib/scheduler/scheduler.d.ts.map +0 -1
  345. package/lib/scheduler/scheduler.js +0 -352
  346. package/lib/scheduler/scheduler.js.map +0 -1
  347. package/lib/scheduler/types.d.ts +0 -71
  348. package/lib/scheduler/types.d.ts.map +0 -1
  349. package/lib/scheduler/types.js +0 -8
  350. package/lib/scheduler/types.js.map +0 -1
  351. package/lib/tool-zod.d.ts.map +0 -1
  352. package/lib/tool-zod.js.map +0 -1
  353. package/lib/types-generator.d.ts.map +0 -1
  354. package/lib/types-generator.js.map +0 -1
  355. package/lib/types.d.ts.map +0 -1
  356. package/lib/types.js.map +0 -1
  357. package/lib/utils.d.ts.map +0 -1
  358. package/lib/utils.js.map +0 -1
@@ -0,0 +1,55 @@
1
+ /**
2
+ * ScheduleFeature — 管理插件注册的内存定时任务
3
+ */
4
+ import { Feature, FeatureJSON, type ScheduleKind } from '@zhin.js/kernel';
5
+ import type { HolidayInput, ScatterInput } from '@zhin.js/kernel';
6
+ export interface ScheduleDescriptor {
7
+ kind: ScheduleKind | 'every' | 'at';
8
+ /** 6 段 cron(solar/lunar/workday/freeDay/holiday) */
9
+ cron?: string;
10
+ everyMs?: number;
11
+ atMs?: number;
12
+ scatterInput?: ScatterInput;
13
+ holidayInput?: HolidayInput;
14
+ tz?: string;
15
+ }
16
+ export interface ScheduleHandle {
17
+ id: string;
18
+ descriptor: ScheduleDescriptor;
19
+ dispose: () => void;
20
+ }
21
+ export interface ScheduleContextExtensions {
22
+ addSchedule(descriptor: ScheduleDescriptor, callback: () => void | Promise<void>, id?: string): () => void;
23
+ }
24
+ declare module '../plugin.js' {
25
+ namespace Plugin {
26
+ interface Extensions extends ScheduleContextExtensions {
27
+ }
28
+ interface Contexts {
29
+ schedule: ScheduleFeature;
30
+ }
31
+ }
32
+ }
33
+ export declare class ScheduleFeature extends Feature<ScheduleHandle> {
34
+ readonly name: "schedule";
35
+ readonly icon = "Clock";
36
+ readonly desc = "\u65E5\u5386\u8C03\u5EA6";
37
+ readonly byName: Map<string, ScheduleHandle>;
38
+ add(handle: ScheduleHandle, pluginName: string): () => void;
39
+ remove(handle: ScheduleHandle): boolean;
40
+ get(id: string): ScheduleHandle | undefined;
41
+ stopAll(): void;
42
+ getStatus(): Array<{
43
+ id: string;
44
+ kind: string;
45
+ expression?: string;
46
+ running: boolean;
47
+ nextExecution: Date | null;
48
+ plugin: string;
49
+ }>;
50
+ dispose(): void;
51
+ toJSON(pluginName?: string): FeatureJSON;
52
+ get extensions(): {
53
+ addSchedule(descriptor: ScheduleDescriptor, callback: () => void | Promise<void>, id?: string): () => void;
54
+ };
55
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * ScheduleFeature — 管理插件注册的内存定时任务
3
+ */
4
+ import { Feature, ScheduleEngine, getScheduleEngine, setScheduleEngine, } from '@zhin.js/kernel';
5
+ function ensureEngine() {
6
+ let engine = getScheduleEngine();
7
+ if (!engine) {
8
+ engine = new ScheduleEngine();
9
+ setScheduleEngine(engine);
10
+ }
11
+ return engine;
12
+ }
13
+ export class ScheduleFeature extends Feature {
14
+ name = 'schedule';
15
+ icon = 'Clock';
16
+ desc = '日历调度';
17
+ byName = new Map();
18
+ add(handle, pluginName) {
19
+ this.byName.set(handle.id, handle);
20
+ return super.add(handle, pluginName);
21
+ }
22
+ remove(handle) {
23
+ if (!this.byName.has(handle.id) && !this.items.includes(handle)) {
24
+ return false;
25
+ }
26
+ this.byName.delete(handle.id);
27
+ const removed = super.remove(handle);
28
+ if (removed) {
29
+ handle.dispose();
30
+ }
31
+ return removed;
32
+ }
33
+ get(id) {
34
+ return this.byName.get(id);
35
+ }
36
+ stopAll() {
37
+ for (const handle of this.items) {
38
+ handle.dispose();
39
+ }
40
+ }
41
+ getStatus() {
42
+ const engine = getScheduleEngine();
43
+ const engineStatus = engine?.getStatus() ?? [];
44
+ const byId = new Map(engineStatus.map((s) => [s.id, s]));
45
+ return this.items.map((handle) => {
46
+ let pluginName = 'unknown';
47
+ for (const [name, items] of this.pluginItems) {
48
+ if (items.includes(handle)) {
49
+ pluginName = name;
50
+ break;
51
+ }
52
+ }
53
+ const st = byId.get(handle.id);
54
+ return {
55
+ id: handle.id,
56
+ kind: handle.descriptor.kind,
57
+ expression: handle.descriptor.cron,
58
+ running: st?.running ?? true,
59
+ nextExecution: st?.nextExecution ?? null,
60
+ plugin: pluginName,
61
+ };
62
+ });
63
+ }
64
+ dispose() {
65
+ this.stopAll();
66
+ }
67
+ toJSON(pluginName) {
68
+ const list = pluginName ? this.getByPlugin(pluginName) : this.items;
69
+ return {
70
+ name: this.name,
71
+ icon: this.icon,
72
+ desc: this.desc,
73
+ count: list.length,
74
+ items: list.map((h) => ({
75
+ id: h.id,
76
+ kind: h.descriptor.kind,
77
+ cron: h.descriptor.cron,
78
+ })),
79
+ };
80
+ }
81
+ get extensions() {
82
+ const feature = this;
83
+ return {
84
+ addSchedule(descriptor, callback, id) {
85
+ const plugin = this;
86
+ const jobId = id ?? `sched_${Math.random().toString(36).slice(2, 10)}`;
87
+ const engine = ensureEngine();
88
+ const disposeEngine = engine.register(jobId, descriptor.kind, async () => {
89
+ await callback();
90
+ }, {
91
+ cron: descriptor.cron,
92
+ everyMs: descriptor.everyMs,
93
+ atMs: descriptor.atMs,
94
+ scatterInput: descriptor.scatterInput,
95
+ holidayInput: descriptor.holidayInput,
96
+ tz: descriptor.tz,
97
+ });
98
+ const handle = {
99
+ id: jobId,
100
+ descriptor,
101
+ dispose: () => {
102
+ disposeEngine();
103
+ },
104
+ };
105
+ const dispose = feature.add(handle, plugin.name);
106
+ plugin.recordFeatureContribution(feature.name, jobId);
107
+ plugin.onDispose(dispose);
108
+ return dispose;
109
+ },
110
+ };
111
+ }
112
+ }
@@ -0,0 +1,17 @@
1
+ import type { Schema } from '@zhin.js/schema';
2
+ import { Adapter } from '../adapter.js';
3
+ import type { EndpointConfigRecord, EndpointManager, ProvisionContext } from './endpoint-manager.js';
4
+ export declare class SchemaEndpointManager implements EndpointManager {
5
+ private readonly adapter;
6
+ private readonly schema;
7
+ constructor(adapter: Adapter, schema: Schema);
8
+ supportsProvision(): boolean;
9
+ listEndpoints(): EndpointConfigRecord[];
10
+ addEndpoint(ctx: ProvisionContext): Promise<EndpointConfigRecord>;
11
+ editEndpoint(name: string, ctx: ProvisionContext): Promise<EndpointConfigRecord>;
12
+ removeEndpoint(name: string): Promise<boolean>;
13
+ startEndpoint(name: string, ctx: ProvisionContext): Promise<void>;
14
+ stopEndpoint(name: string): Promise<boolean>;
15
+ }
16
+ export declare function resolveEndpointManager(adapter: Adapter): EndpointManager | null;
17
+ export declare function adapterSupportsProvision(adapter: Adapter): boolean;
@@ -0,0 +1,73 @@
1
+ import { Prompt } from '../prompt.js';
2
+ function readConfigEndpoints(root, context) {
3
+ const configService = root.inject('config');
4
+ const raw = configService?.getRaw(configService.primaryFile);
5
+ return (raw?.endpoints ?? []).filter((e) => e.context === context);
6
+ }
7
+ export class SchemaEndpointManager {
8
+ adapter;
9
+ schema;
10
+ constructor(adapter, schema) {
11
+ this.adapter = adapter;
12
+ this.schema = schema;
13
+ }
14
+ supportsProvision() {
15
+ return true;
16
+ }
17
+ listEndpoints() {
18
+ return readConfigEndpoints(this.adapter.plugin.root, String(this.adapter.name));
19
+ }
20
+ async addEndpoint(ctx) {
21
+ const prompt = new Prompt(this.adapter.plugin, ctx.message);
22
+ await ctx.onStatusUpdate(`请按提示填写 ${String(this.adapter.name)} endpoint 配置:`);
23
+ const name = await prompt.text('Endpoint 名称(zhin.config endpoints[].name):');
24
+ const fields = await prompt.getValueWithSchema(this.schema);
25
+ return {
26
+ context: String(this.adapter.name),
27
+ name: name.trim(),
28
+ ...fields,
29
+ };
30
+ }
31
+ async editEndpoint(name, ctx) {
32
+ const existing = this.listEndpoints().find((e) => e.name === name);
33
+ if (!existing) {
34
+ throw new Error(`配置中不存在 ${String(this.adapter.name)}/${name}`);
35
+ }
36
+ await ctx.onStatusUpdate(`编辑 ${String(this.adapter.name)}/${name},留空字段将保留原值。`);
37
+ const prompt = new Prompt(this.adapter.plugin, ctx.message);
38
+ const fields = await prompt.getValueWithSchema(this.schema);
39
+ return {
40
+ ...existing,
41
+ ...fields,
42
+ context: String(this.adapter.name),
43
+ name,
44
+ };
45
+ }
46
+ async removeEndpoint(name) {
47
+ return this.listEndpoints().some((e) => e.name === name);
48
+ }
49
+ async startEndpoint(name, ctx) {
50
+ const rec = this.listEndpoints().find((e) => e.name === name);
51
+ if (!rec)
52
+ throw new Error(`配置中不存在 ${String(this.adapter.name)}/${name}`);
53
+ await ctx.onStatusUpdate(`正在连接 ${String(this.adapter.name)}/${name}…`);
54
+ }
55
+ async stopEndpoint(name) {
56
+ return this.adapter.endpoints.has(name);
57
+ }
58
+ }
59
+ export function resolveEndpointManager(adapter) {
60
+ const custom = adapter.getEndpointManager?.();
61
+ if (custom)
62
+ return custom;
63
+ const schema = adapter.getEndpointConfigSchema?.() ??
64
+ adapter.constructor.endpointConfigSchema;
65
+ if (schema) {
66
+ return new SchemaEndpointManager(adapter, schema);
67
+ }
68
+ return null;
69
+ }
70
+ export function adapterSupportsProvision(adapter) {
71
+ const manager = resolveEndpointManager(adapter);
72
+ return manager?.supportsProvision() ?? false;
73
+ }
@@ -75,4 +75,3 @@ export declare class SchemaFeature extends Feature<SchemaRecord> {
75
75
  }): Required<T>;
76
76
  };
77
77
  }
78
- //# sourceMappingURL=schema-feature.d.ts.map
@@ -9,7 +9,6 @@
9
9
  * - Schema.toJSON() 传给前端驱动 PluginConfigForm
10
10
  * - reloadable 标记决定保存后是否自动重载插件
11
11
  */
12
- import { getPlugin } from '../plugin.js';
13
12
  import { Feature } from '@zhin.js/kernel';
14
13
  // ============================================================================
15
14
  // SchemaFeature
@@ -91,7 +90,7 @@ export class SchemaFeature extends Feature {
91
90
  const feature = this;
92
91
  return {
93
92
  declareConfig(key, schema, options) {
94
- const plugin = getPlugin();
93
+ const plugin = this;
95
94
  const reloadable = options?.reloadable ?? true;
96
95
  // 从 Schema 提取默认值
97
96
  const defaults = extractDefaults(schema);
@@ -129,4 +128,3 @@ function extractDefaults(schema) {
129
128
  }
130
129
  return result;
131
130
  }
132
- //# sourceMappingURL=schema-feature.js.map
@@ -0,0 +1,4 @@
1
+ import type { Segment } from './types.js';
2
+ /** 宽松判断:已知 canonical type 走严格校验;未知 type 仅校验顶层形状(adapter 渐进迁移) */
3
+ export declare function isCanonicalSegment(value: unknown): value is Segment;
4
+ export declare function assertCanonicalSegments(segments: unknown): asserts segments is Segment[];
@@ -0,0 +1,30 @@
1
+ import { isStrictCanonicalSegment } from './validate.js';
2
+ const STRICT_CANONICAL_TYPES = new Set([
3
+ 'text', 'mention', 'image', 'reply', 'forward', 'face', 'dice', 'rps',
4
+ ]);
5
+ function isPlainObject(value) {
6
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
7
+ }
8
+ /** 宽松判断:已知 canonical type 走严格校验;未知 type 仅校验顶层形状(adapter 渐进迁移) */
9
+ export function isCanonicalSegment(value) {
10
+ if (!isPlainObject(value) || typeof value.type !== 'string')
11
+ return false;
12
+ if (!isPlainObject(value.data))
13
+ return false;
14
+ if (value.platform !== undefined && !isPlainObject(value.platform))
15
+ return false;
16
+ if (!STRICT_CANONICAL_TYPES.has(value.type)) {
17
+ return true;
18
+ }
19
+ return isStrictCanonicalSegment(value);
20
+ }
21
+ export function assertCanonicalSegments(segments) {
22
+ if (!Array.isArray(segments)) {
23
+ throw new Error('segments must be an array');
24
+ }
25
+ for (let i = 0; i < segments.length; i++) {
26
+ if (!isCanonicalSegment(segments[i])) {
27
+ throw new Error(`segment[${i}] is not canonical`);
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,5 @@
1
+ import type { Segment } from './types.js';
2
+ /**
3
+ * 过滤 agent / AI 出站段,仅保留可经 IM 投递的 canonical 段。
4
+ */
5
+ export declare function segmentsForImDelivery(segments: readonly unknown[]): Segment[];
@@ -0,0 +1,40 @@
1
+ import { isCanonicalSegment } from './assert.js';
2
+ /** IM 可见段白名单(thinking / tool_call 等 AI-only 段过滤) */
3
+ const IM_VISIBLE_TYPES = new Set([
4
+ 'text',
5
+ 'mention',
6
+ 'image',
7
+ 'video',
8
+ 'audio',
9
+ 'voice',
10
+ 'record',
11
+ 'file',
12
+ 'face',
13
+ 'reply',
14
+ 'forward',
15
+ 'link',
16
+ 'dice',
17
+ 'rps',
18
+ 'markdown',
19
+ 'html',
20
+ 'qrcode',
21
+ 'tts',
22
+ 'keyboard',
23
+ ]);
24
+ const AI_ONLY_TYPES = new Set(['thinking', 'tool_call']);
25
+ /**
26
+ * 过滤 agent / AI 出站段,仅保留可经 IM 投递的 canonical 段。
27
+ */
28
+ export function segmentsForImDelivery(segments) {
29
+ const out = [];
30
+ for (const item of segments) {
31
+ if (!isCanonicalSegment(item))
32
+ continue;
33
+ if (AI_ONLY_TYPES.has(item.type))
34
+ continue;
35
+ if (!IM_VISIBLE_TYPES.has(item.type))
36
+ continue;
37
+ out.push(item);
38
+ }
39
+ return out;
40
+ }
@@ -0,0 +1,5 @@
1
+ import type { MediaRef, Segment } from './types.js';
2
+ export declare function createImageSegment(media: MediaRef, options?: {
3
+ alt?: string;
4
+ platform?: Record<string, unknown>;
5
+ }): Segment;
@@ -0,0 +1,10 @@
1
+ export function createImageSegment(media, options) {
2
+ return {
3
+ type: 'image',
4
+ data: {
5
+ media,
6
+ ...(options?.alt ? { alt: options.alt } : {}),
7
+ },
8
+ ...(options?.platform ? { platform: options.platform } : {}),
9
+ };
10
+ }
@@ -0,0 +1,8 @@
1
+ export type { Segment, SegmentBase, MediaRef, TextSegment, MentionSegment, ImageSegment, ReplySegment, ForwardSegment, FaceSegment, DiceSegment, RpsSegment, } from './types.js';
2
+ export { mediaRefSchema, textSegmentSchema, mentionSegmentSchema, imageSegmentSchema, replySegmentSchema, forwardSegmentSchema, faceSegmentSchema, diceSegmentSchema, rpsSegmentSchema, canonicalSegmentSchema, segmentArraySchema, } from './validate.js';
3
+ export { assertCanonicalSegments, isCanonicalSegment } from './assert.js';
4
+ export { segmentsForImDelivery } from './delivery.js';
5
+ export { isMediaRef, mediaRefFromLegacyData, mediaRefToLegacyFields } from './media.js';
6
+ export { createImageSegment } from './image.js';
7
+ export { formatSegmentPreview } from './preview.js';
8
+ export { readMentionTarget, readMentionName, readMentionSegmentTarget } from './mention.js';
@@ -0,0 +1,7 @@
1
+ export { mediaRefSchema, textSegmentSchema, mentionSegmentSchema, imageSegmentSchema, replySegmentSchema, forwardSegmentSchema, faceSegmentSchema, diceSegmentSchema, rpsSegmentSchema, canonicalSegmentSchema, segmentArraySchema, } from './validate.js';
2
+ export { assertCanonicalSegments, isCanonicalSegment } from './assert.js';
3
+ export { segmentsForImDelivery } from './delivery.js';
4
+ export { isMediaRef, mediaRefFromLegacyData, mediaRefToLegacyFields } from './media.js';
5
+ export { createImageSegment } from './image.js';
6
+ export { formatSegmentPreview } from './preview.js';
7
+ export { readMentionTarget, readMentionName, readMentionSegmentTarget } from './mention.js';
@@ -0,0 +1,8 @@
1
+ import type { MediaRef } from './types.js';
2
+ import { isMediaRef } from './validate.js';
3
+ export { isMediaRef };
4
+ export declare function mediaRefFromLegacyData(data: Record<string, unknown>): MediaRef | undefined;
5
+ export declare function mediaRefToLegacyFields(media: MediaRef): {
6
+ url?: string;
7
+ file?: string;
8
+ };
@@ -0,0 +1,39 @@
1
+ import { isMediaRef } from './validate.js';
2
+ export { isMediaRef };
3
+ export function mediaRefFromLegacyData(data) {
4
+ if (isMediaRef(data.media)) {
5
+ return data.media;
6
+ }
7
+ const mimeType = typeof data.mime_type === 'string' ? data.mime_type : undefined;
8
+ const base64 = typeof data.base64 === 'string' && data.base64.trim()
9
+ ? data.base64.trim()
10
+ : typeof data.data === 'string' && data.data.trim() && !String(data.data).startsWith('http')
11
+ ? data.data.trim()
12
+ : undefined;
13
+ if (base64) {
14
+ return { kind: 'base64', value: base64, ...(mimeType ? { mime_type: mimeType } : {}) };
15
+ }
16
+ const raw = [data.url, data.file, data.src, data.href]
17
+ .find((v) => typeof v === 'string' && v.trim().length > 0);
18
+ if (!raw)
19
+ return undefined;
20
+ const value = raw.trim();
21
+ if (value.startsWith('base64://')) {
22
+ return { kind: 'base64', value: value.slice('base64://'.length), ...(mimeType ? { mime_type: mimeType } : {}) };
23
+ }
24
+ if (value.startsWith('http://') || value.startsWith('https://')) {
25
+ return { kind: 'url', value, ...(mimeType ? { mime_type: mimeType } : {}) };
26
+ }
27
+ if (value.startsWith('/') || /^[a-zA-Z]:[\\/]/.test(value)) {
28
+ return { kind: 'path', value, ...(mimeType ? { mime_type: mimeType } : {}) };
29
+ }
30
+ return { kind: 'url', value, ...(mimeType ? { mime_type: mimeType } : {}) };
31
+ }
32
+ export function mediaRefToLegacyFields(media) {
33
+ if (media.kind === 'url')
34
+ return { url: media.value, file: media.value };
35
+ if (media.kind === 'path')
36
+ return { file: media.value, url: media.value };
37
+ const encoded = media.value.startsWith('base64://') ? media.value : `base64://${media.value}`;
38
+ return { file: encoded, url: encoded };
39
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Canonical mention field readers (SSOT).
3
+ */
4
+ export declare function readMentionTarget(data: Record<string, unknown> | undefined): string;
5
+ export declare function readMentionName(data: Record<string, unknown> | undefined): string | undefined;
6
+ /** Resolve @ target from at / mention segment. */
7
+ export declare function readMentionSegmentTarget(seg: {
8
+ type: unknown;
9
+ data?: unknown;
10
+ }): string;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Canonical mention field readers (SSOT).
3
+ */
4
+ export function readMentionTarget(data) {
5
+ if (!data)
6
+ return '';
7
+ const raw = data.target ?? data.user_id ?? data.qq ?? data.id;
8
+ if (raw === 'all')
9
+ return 'all';
10
+ return raw != null ? String(raw) : '';
11
+ }
12
+ export function readMentionName(data) {
13
+ if (!data)
14
+ return undefined;
15
+ const name = data.name ?? data.nickname ?? data.username;
16
+ return typeof name === 'string' && name.trim() ? name.trim() : undefined;
17
+ }
18
+ function isRecord(value) {
19
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
20
+ }
21
+ /** Resolve @ target from at / mention segment. */
22
+ export function readMentionSegmentTarget(seg) {
23
+ if (seg.type !== 'at' && seg.type !== 'mention')
24
+ return '';
25
+ return readMentionTarget(isRecord(seg.data) ? seg.data : undefined);
26
+ }
@@ -0,0 +1,3 @@
1
+ import type { SegmentBase } from './types.js';
2
+ /** Single canonical segment → compact human-readable preview for logs. */
3
+ export declare function formatSegmentPreview(item: SegmentBase): string;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Canonical Segment[] log / debug preview (SSOT).
3
+ * @see docs/architecture/segment-content-model.md
4
+ */
5
+ import { htmlToFallbackText } from '../html-to-text.js';
6
+ import { readMentionName, readMentionTarget } from './mention.js';
7
+ import { mediaRefFromLegacyData } from './media.js';
8
+ const PREVIEW_MAX = 80;
9
+ function clip(text, max = PREVIEW_MAX) {
10
+ const normalized = text.trim();
11
+ if (normalized.length <= max)
12
+ return normalized;
13
+ return `${normalized.slice(0, max)}…`;
14
+ }
15
+ function previewMedia(data) {
16
+ const media = mediaRefFromLegacyData(data);
17
+ if (!media)
18
+ return undefined;
19
+ if (media.kind === 'base64') {
20
+ const mime = media.mime_type ?? 'data';
21
+ return `base64:${mime}[${media.value.length}]`;
22
+ }
23
+ if (media.kind === 'path') {
24
+ const base = media.value.split(/[/\\]/).pop() ?? media.value;
25
+ return clip(base, 48);
26
+ }
27
+ return clip(media.value, 60);
28
+ }
29
+ function previewMediaSegment(type, data) {
30
+ const media = previewMedia(data);
31
+ const alt = typeof data.alt === 'string'
32
+ ? data.alt
33
+ : typeof data.name === 'string'
34
+ ? data.name
35
+ : undefined;
36
+ if (media && alt)
37
+ return `[${type}:${media} alt=${clip(alt, 24)}]`;
38
+ if (media)
39
+ return `[${type}:${media}]`;
40
+ return `[${type}]`;
41
+ }
42
+ /** Single canonical segment → compact human-readable preview for logs. */
43
+ export function formatSegmentPreview(item) {
44
+ const { type } = item;
45
+ const data = item.data ?? {};
46
+ switch (type) {
47
+ case 'text':
48
+ return typeof data.text === 'string' ? data.text : '';
49
+ case 'mention': {
50
+ const target = readMentionTarget(data);
51
+ if (target === 'all')
52
+ return '@all';
53
+ const name = readMentionName(data);
54
+ if (name)
55
+ return `@${name}`;
56
+ return `@${target}`;
57
+ }
58
+ case 'at': {
59
+ const target = readMentionTarget(data);
60
+ const name = readMentionName(data);
61
+ if (name)
62
+ return `@${name}`;
63
+ return `@${target}`;
64
+ }
65
+ case 'image':
66
+ case 'video':
67
+ case 'audio':
68
+ case 'voice':
69
+ case 'record':
70
+ case 'file':
71
+ return previewMediaSegment(type, data);
72
+ case 'face': {
73
+ const id = data.id ?? data.face_id;
74
+ const name = typeof data.name === 'string'
75
+ ? data.name
76
+ : typeof data.text === 'string'
77
+ ? data.text
78
+ : undefined;
79
+ if (id != null && name)
80
+ return `[face:${id} ${name}]`;
81
+ if (id != null)
82
+ return `[face:${id}]`;
83
+ if (name)
84
+ return `{face}(${name})`;
85
+ return '[face]';
86
+ }
87
+ case 'reply': {
88
+ const id = data.message_id ?? data.id;
89
+ return id ? `↩${id}` : '[reply]';
90
+ }
91
+ case 'forward': {
92
+ const id = data.forward_id ?? data.id;
93
+ const title = typeof data.title === 'string' ? data.title : undefined;
94
+ const count = Array.isArray(data.messages) ? data.messages.length : 0;
95
+ let out = `[forward${id ? `:${id}` : ''}`;
96
+ if (title)
97
+ out += ` ${clip(title, 32)}`;
98
+ if (count > 0)
99
+ out += ` ×${count}`;
100
+ return `${out}]`;
101
+ }
102
+ case 'link': {
103
+ const url = typeof data.url === 'string' ? data.url : '';
104
+ const text = typeof data.text === 'string' ? data.text : '';
105
+ if (text && url)
106
+ return clip(`${text} <${url}>`);
107
+ return clip(url || text || '[link]');
108
+ }
109
+ case 'dice':
110
+ return data.result != null ? `{dice}(${data.result})` : '{dice}';
111
+ case 'rps':
112
+ return data.result != null ? `{rps}(${data.result})` : '{rps}';
113
+ case 'html': {
114
+ if (typeof data.text === 'string' && data.text)
115
+ return clip(data.text);
116
+ if (typeof data.html === 'string') {
117
+ const stripped = htmlToFallbackText(data.html);
118
+ return stripped ? clip(`[html] ${stripped}`) : '[html]';
119
+ }
120
+ return '[html]';
121
+ }
122
+ case 'qrcode': {
123
+ const text = typeof data.text === 'string' ? data.text : '';
124
+ return text ? clip(`[qrcode] ${text}`) : '[qrcode]';
125
+ }
126
+ case 'markdown': {
127
+ const text = typeof data.content === 'string'
128
+ ? data.content
129
+ : typeof data.text === 'string'
130
+ ? data.text
131
+ : '';
132
+ return text ? clip(`[markdown] ${text}`) : '[markdown]';
133
+ }
134
+ case 'tts': {
135
+ const text = typeof data.text === 'string' ? data.text : '';
136
+ return text ? clip(`[tts] ${text}`) : '[tts]';
137
+ }
138
+ case 'keyboard': {
139
+ const rows = Array.isArray(data.rows)
140
+ ? data.rows.length
141
+ : Array.isArray(data.buttons)
142
+ ? data.buttons.length
143
+ : 0;
144
+ return rows > 0 ? `[keyboard:${rows}]` : '[keyboard]';
145
+ }
146
+ case 'thinking': {
147
+ const text = typeof data.text === 'string' ? data.text : '';
148
+ return text ? clip(`[thinking] ${text}`, 60) : '[thinking]';
149
+ }
150
+ case 'tool_call': {
151
+ const name = typeof data.name === 'string' ? data.name : 'tool';
152
+ return `[tool:${name}]`;
153
+ }
154
+ default:
155
+ if (typeof data.text === 'string' && data.text)
156
+ return `{${type}}(${clip(data.text)})`;
157
+ return `{${type}}`;
158
+ }
159
+ }