@lemoncat7/dsh-partner 2.11.6 → 2.21.5

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 (355) hide show
  1. package/README.md +3 -0
  2. package/docs/character-cards-and-renewal.md +1 -1
  3. package/docs/qq-attention.md +51 -0
  4. package/docs/qq-channel.md +80 -0
  5. package/docs/releases/2.11.7.md +9 -0
  6. package/docs/releases/2.12.0.md +14 -0
  7. package/docs/releases/2.13.0.md +9 -0
  8. package/docs/releases/2.14.0.md +9 -0
  9. package/docs/releases/2.15.0.md +9 -0
  10. package/docs/releases/2.15.1.md +9 -0
  11. package/docs/releases/2.16.0.md +18 -0
  12. package/docs/releases/2.17.0.md +23 -0
  13. package/docs/releases/2.17.1.md +9 -0
  14. package/docs/releases/2.18.0.md +9 -0
  15. package/docs/releases/2.18.1.md +5 -0
  16. package/docs/releases/2.19.0.md +14 -0
  17. package/docs/releases/2.19.1.md +7 -0
  18. package/docs/releases/2.19.2.md +9 -0
  19. package/docs/releases/2.19.3.md +5 -0
  20. package/docs/releases/2.20.0.md +10 -0
  21. package/docs/releases/2.20.1.md +8 -0
  22. package/docs/releases/2.21.0.md +7 -0
  23. package/docs/releases/2.21.1.md +8 -0
  24. package/docs/releases/2.21.2.md +10 -0
  25. package/docs/releases/2.21.3.md +7 -0
  26. package/docs/releases/2.21.4.md +8 -0
  27. package/docs/releases/2.21.5.md +15 -0
  28. package/docs/tool-entry-compatibility.md +11 -0
  29. package/lib/agent-runtime.d.ts +17 -0
  30. package/lib/agent-runtime.d.ts.map +1 -1
  31. package/lib/agent-runtime.js +313 -52
  32. package/lib/agent-runtime.js.map +1 -1
  33. package/lib/api.d.ts +1 -0
  34. package/lib/api.d.ts.map +1 -1
  35. package/lib/api.js +93 -27
  36. package/lib/api.js.map +1 -1
  37. package/lib/channel-message.d.ts +14 -0
  38. package/lib/channel-message.d.ts.map +1 -1
  39. package/lib/channel-message.js.map +1 -1
  40. package/lib/channels/delivery-policy.js +1 -1
  41. package/lib/channels/delivery-policy.js.map +1 -1
  42. package/lib/channels/direct/dispatcher.d.ts +2 -2
  43. package/lib/channels/direct/dispatcher.d.ts.map +1 -1
  44. package/lib/channels/direct/dispatcher.js +13 -4
  45. package/lib/channels/direct/dispatcher.js.map +1 -1
  46. package/lib/channels/direct/login.d.ts.map +1 -1
  47. package/lib/channels/direct/login.js +4 -0
  48. package/lib/channels/direct/login.js.map +1 -1
  49. package/lib/channels/direct/media.d.ts +2 -0
  50. package/lib/channels/direct/media.d.ts.map +1 -1
  51. package/lib/channels/direct/media.js +27 -23
  52. package/lib/channels/direct/media.js.map +1 -1
  53. package/lib/channels/direct/message-format.js +127 -127
  54. package/lib/channels/direct/message-format.js.map +1 -1
  55. package/lib/channels/direct/transport.d.ts +26 -3
  56. package/lib/channels/direct/transport.d.ts.map +1 -1
  57. package/lib/channels/direct/transport.js +31 -5
  58. package/lib/channels/direct/transport.js.map +1 -1
  59. package/lib/channels/manager.d.ts +26 -0
  60. package/lib/channels/manager.d.ts.map +1 -1
  61. package/lib/channels/manager.js +538 -148
  62. package/lib/channels/manager.js.map +1 -1
  63. package/lib/channels/notification-delivery.d.ts +4 -0
  64. package/lib/channels/notification-delivery.d.ts.map +1 -1
  65. package/lib/channels/notification-delivery.js +15 -5
  66. package/lib/channels/notification-delivery.js.map +1 -1
  67. package/lib/channels/notification-route.d.ts.map +1 -1
  68. package/lib/channels/notification-route.js +10 -4
  69. package/lib/channels/notification-route.js.map +1 -1
  70. package/lib/channels/notification-timeout.d.ts.map +1 -1
  71. package/lib/channels/notification-timeout.js +2 -0
  72. package/lib/channels/notification-timeout.js.map +1 -1
  73. package/lib/channels/outbound-media.d.ts.map +1 -1
  74. package/lib/channels/outbound-media.js +2 -0
  75. package/lib/channels/outbound-media.js.map +1 -1
  76. package/lib/channels/qq/action-catalog.d.ts +38 -0
  77. package/lib/channels/qq/action-catalog.d.ts.map +1 -0
  78. package/lib/channels/qq/action-catalog.js +2731 -0
  79. package/lib/channels/qq/action-catalog.js.map +1 -0
  80. package/lib/channels/qq/actions.d.ts +21 -0
  81. package/lib/channels/qq/actions.d.ts.map +1 -0
  82. package/lib/channels/qq/actions.js +226 -0
  83. package/lib/channels/qq/actions.js.map +1 -0
  84. package/lib/channels/qq/affection-adapter.d.ts +3 -0
  85. package/lib/channels/qq/affection-adapter.d.ts.map +1 -0
  86. package/lib/channels/qq/affection-adapter.js +16 -0
  87. package/lib/channels/qq/affection-adapter.js.map +1 -0
  88. package/lib/channels/qq/attention-classifier.d.ts +10 -0
  89. package/lib/channels/qq/attention-classifier.d.ts.map +1 -0
  90. package/lib/channels/qq/attention-classifier.js +62 -0
  91. package/lib/channels/qq/attention-classifier.js.map +1 -0
  92. package/lib/channels/qq/authority.d.ts +10 -0
  93. package/lib/channels/qq/authority.d.ts.map +1 -0
  94. package/lib/channels/qq/authority.js +50 -0
  95. package/lib/channels/qq/authority.js.map +1 -0
  96. package/lib/channels/qq/autonomy.d.ts +30 -0
  97. package/lib/channels/qq/autonomy.d.ts.map +1 -0
  98. package/lib/channels/qq/autonomy.js +88 -0
  99. package/lib/channels/qq/autonomy.js.map +1 -0
  100. package/lib/channels/qq/catalog.d.ts +14 -0
  101. package/lib/channels/qq/catalog.d.ts.map +1 -0
  102. package/lib/channels/qq/catalog.js +34 -0
  103. package/lib/channels/qq/catalog.js.map +1 -0
  104. package/lib/channels/qq/connection.d.ts +28 -0
  105. package/lib/channels/qq/connection.d.ts.map +1 -0
  106. package/lib/channels/qq/connection.js +200 -0
  107. package/lib/channels/qq/connection.js.map +1 -0
  108. package/lib/channels/qq/identity-binding.d.ts +14 -0
  109. package/lib/channels/qq/identity-binding.d.ts.map +1 -0
  110. package/lib/channels/qq/identity-binding.js +58 -0
  111. package/lib/channels/qq/identity-binding.js.map +1 -0
  112. package/lib/channels/qq/latency.d.ts +22 -0
  113. package/lib/channels/qq/latency.d.ts.map +1 -0
  114. package/lib/channels/qq/latency.js +21 -0
  115. package/lib/channels/qq/latency.js.map +1 -0
  116. package/lib/channels/qq/message.d.ts +6 -0
  117. package/lib/channels/qq/message.d.ts.map +1 -0
  118. package/lib/channels/qq/message.js +49 -0
  119. package/lib/channels/qq/message.js.map +1 -0
  120. package/lib/channels/qq/reply-rules.d.ts +30 -0
  121. package/lib/channels/qq/reply-rules.d.ts.map +1 -0
  122. package/lib/channels/qq/reply-rules.js +72 -0
  123. package/lib/channels/qq/reply-rules.js.map +1 -0
  124. package/lib/channels/qq/reply-tool.d.ts +6 -0
  125. package/lib/channels/qq/reply-tool.d.ts.map +1 -0
  126. package/lib/channels/qq/reply-tool.js +113 -0
  127. package/lib/channels/qq/reply-tool.js.map +1 -0
  128. package/lib/channels/qq/settings.d.ts +42 -0
  129. package/lib/channels/qq/settings.d.ts.map +1 -0
  130. package/lib/channels/qq/settings.js +68 -0
  131. package/lib/channels/qq/settings.js.map +1 -0
  132. package/lib/channels/qq/sticker-adapter.d.ts +5 -0
  133. package/lib/channels/qq/sticker-adapter.d.ts.map +1 -0
  134. package/lib/channels/qq/sticker-adapter.js +43 -0
  135. package/lib/channels/qq/sticker-adapter.js.map +1 -0
  136. package/lib/channels/qq/transport.d.ts +29 -0
  137. package/lib/channels/qq/transport.d.ts.map +1 -0
  138. package/lib/channels/qq/transport.js +187 -0
  139. package/lib/channels/qq/transport.js.map +1 -0
  140. package/lib/channels/reply-access.d.ts +25 -0
  141. package/lib/channels/reply-access.d.ts.map +1 -0
  142. package/lib/channels/reply-access.js +29 -0
  143. package/lib/channels/reply-access.js.map +1 -0
  144. package/lib/channels/weixin/connect.d.ts +3 -1
  145. package/lib/channels/weixin/connect.d.ts.map +1 -1
  146. package/lib/character/activity-tool.d.ts +7 -0
  147. package/lib/character/activity-tool.d.ts.map +1 -0
  148. package/lib/character/activity-tool.js +38 -0
  149. package/lib/character/activity-tool.js.map +1 -0
  150. package/lib/character/affection-adapter.d.ts +13 -0
  151. package/lib/character/affection-adapter.d.ts.map +1 -0
  152. package/lib/character/affection-adapter.js +13 -0
  153. package/lib/character/affection-adapter.js.map +1 -0
  154. package/lib/character/affection-context.d.ts +7 -0
  155. package/lib/character/affection-context.d.ts.map +1 -0
  156. package/lib/character/affection-context.js +33 -0
  157. package/lib/character/affection-context.js.map +1 -0
  158. package/lib/character/affection.d.ts +47 -0
  159. package/lib/character/affection.d.ts.map +1 -0
  160. package/lib/character/affection.js +41 -0
  161. package/lib/character/affection.js.map +1 -0
  162. package/lib/character/conversation-behavior.d.ts +1 -1
  163. package/lib/character/conversation-behavior.d.ts.map +1 -1
  164. package/lib/character/conversation-behavior.js +5 -3
  165. package/lib/character/conversation-behavior.js.map +1 -1
  166. package/lib/character/domain.d.ts +5 -0
  167. package/lib/character/domain.d.ts.map +1 -1
  168. package/lib/character/domain.js +21 -4
  169. package/lib/character/domain.js.map +1 -1
  170. package/lib/character/identity-guide.d.ts +4 -0
  171. package/lib/character/identity-guide.d.ts.map +1 -0
  172. package/lib/character/identity-guide.js +14 -0
  173. package/lib/character/identity-guide.js.map +1 -0
  174. package/lib/character/idle-contact.d.ts +12 -5
  175. package/lib/character/idle-contact.d.ts.map +1 -1
  176. package/lib/character/idle-contact.js +50 -21
  177. package/lib/character/idle-contact.js.map +1 -1
  178. package/lib/character/post-reply.d.ts +19 -0
  179. package/lib/character/post-reply.d.ts.map +1 -0
  180. package/lib/character/post-reply.js +33 -0
  181. package/lib/character/post-reply.js.map +1 -0
  182. package/lib/character/preview.d.ts.map +1 -1
  183. package/lib/character/preview.js +9 -1
  184. package/lib/character/preview.js.map +1 -1
  185. package/lib/character/relationship-adapter.d.ts +18 -0
  186. package/lib/character/relationship-adapter.d.ts.map +1 -0
  187. package/lib/character/relationship-adapter.js +18 -0
  188. package/lib/character/relationship-adapter.js.map +1 -0
  189. package/lib/character/sleep-service.d.ts +35 -0
  190. package/lib/character/sleep-service.d.ts.map +1 -0
  191. package/lib/character/sleep-service.js +278 -0
  192. package/lib/character/sleep-service.js.map +1 -0
  193. package/lib/character/sleep.d.ts +43 -0
  194. package/lib/character/sleep.d.ts.map +1 -0
  195. package/lib/character/sleep.js +36 -0
  196. package/lib/character/sleep.js.map +1 -0
  197. package/lib/character/state-policy.d.ts +4 -0
  198. package/lib/character/state-policy.d.ts.map +1 -0
  199. package/lib/character/state-policy.js +14 -0
  200. package/lib/character/state-policy.js.map +1 -0
  201. package/lib/character/store.d.ts.map +1 -1
  202. package/lib/character/store.js +3 -3
  203. package/lib/character/store.js.map +1 -1
  204. package/lib/chat/conversation.js +1 -1
  205. package/lib/chat/conversation.js.map +1 -1
  206. package/lib/chat/protocol.d.ts +8 -0
  207. package/lib/chat/protocol.d.ts.map +1 -1
  208. package/lib/chat/protocol.js +24 -5
  209. package/lib/chat/protocol.js.map +1 -1
  210. package/lib/chat/sticker-adapter.d.ts +34 -0
  211. package/lib/chat/sticker-adapter.d.ts.map +1 -0
  212. package/lib/chat/sticker-adapter.js +30 -0
  213. package/lib/chat/sticker-adapter.js.map +1 -0
  214. package/lib/chat/tools.d.ts +2 -1
  215. package/lib/chat/tools.d.ts.map +1 -1
  216. package/lib/chat/tools.js +59 -13
  217. package/lib/chat/tools.js.map +1 -1
  218. package/lib/client-api.d.ts +21 -1
  219. package/lib/client-api.d.ts.map +1 -1
  220. package/lib/client-api.js.map +1 -1
  221. package/lib/client.d.ts.map +1 -1
  222. package/lib/client.js +6388 -2685
  223. package/lib/client.js.map +4 -4
  224. package/lib/collaboration/composition.d.ts +2 -0
  225. package/lib/collaboration/composition.d.ts.map +1 -1
  226. package/lib/collaboration/composition.js +32 -10
  227. package/lib/collaboration/composition.js.map +1 -1
  228. package/lib/collaboration/tool-discovery.d.ts +12 -0
  229. package/lib/collaboration/tool-discovery.d.ts.map +1 -0
  230. package/lib/collaboration/tool-discovery.js +148 -0
  231. package/lib/collaboration/tool-discovery.js.map +1 -0
  232. package/lib/companions/identity-tool.d.ts +176 -0
  233. package/lib/companions/identity-tool.d.ts.map +1 -0
  234. package/lib/companions/identity-tool.js +67 -0
  235. package/lib/companions/identity-tool.js.map +1 -0
  236. package/lib/companions/identity.d.ts +24 -0
  237. package/lib/companions/identity.d.ts.map +1 -0
  238. package/lib/companions/identity.js +49 -0
  239. package/lib/companions/identity.js.map +1 -0
  240. package/lib/companions/management-tool.d.ts +1 -1
  241. package/lib/companions/management-tool.d.ts.map +1 -1
  242. package/lib/companions/management-tool.js +4 -2
  243. package/lib/companions/management-tool.js.map +1 -1
  244. package/lib/companions/management.d.ts +21 -9
  245. package/lib/companions/management.d.ts.map +1 -1
  246. package/lib/companions/management.js +18 -4
  247. package/lib/companions/management.js.map +1 -1
  248. package/lib/companions/service.js +1 -0
  249. package/lib/companions/service.js.map +1 -1
  250. package/lib/companions/session-configuration.js +2 -2
  251. package/lib/companions/session-configuration.js.map +1 -1
  252. package/lib/domain.d.ts +37 -1
  253. package/lib/domain.d.ts.map +1 -1
  254. package/lib/domain.js +6 -0
  255. package/lib/domain.js.map +1 -1
  256. package/lib/execution/agent-support.d.ts +1 -1
  257. package/lib/execution/agent-support.d.ts.map +1 -1
  258. package/lib/execution/agent-support.js +7 -2
  259. package/lib/execution/agent-support.js.map +1 -1
  260. package/lib/execution/operation-tool-access.d.ts +13 -0
  261. package/lib/execution/operation-tool-access.d.ts.map +1 -0
  262. package/lib/execution/operation-tool-access.js +49 -0
  263. package/lib/execution/operation-tool-access.js.map +1 -0
  264. package/lib/execution/service.d.ts.map +1 -1
  265. package/lib/execution/service.js +2 -10
  266. package/lib/execution/service.js.map +1 -1
  267. package/lib/execution/tool-access-adapter.d.ts +23 -0
  268. package/lib/execution/tool-access-adapter.d.ts.map +1 -0
  269. package/lib/execution/tool-access-adapter.js +25 -0
  270. package/lib/execution/tool-access-adapter.js.map +1 -0
  271. package/lib/heartbeat.js +1 -1
  272. package/lib/index.d.ts.map +1 -1
  273. package/lib/index.js +32 -2
  274. package/lib/index.js.map +1 -1
  275. package/lib/memory-domain.d.ts +1 -0
  276. package/lib/memory-domain.d.ts.map +1 -1
  277. package/lib/memory-prompt-context.js +1 -0
  278. package/lib/memory-prompt-context.js.map +1 -1
  279. package/lib/memory-reflection.d.ts.map +1 -1
  280. package/lib/memory-reflection.js +16 -5
  281. package/lib/memory-reflection.js.map +1 -1
  282. package/lib/memory-scope.d.ts +2 -1
  283. package/lib/memory-scope.d.ts.map +1 -1
  284. package/lib/memory-scope.js +3 -1
  285. package/lib/memory-scope.js.map +1 -1
  286. package/lib/memory-store.d.ts +1 -1
  287. package/lib/observation-knowledge-entry.d.ts +2 -0
  288. package/lib/observation-knowledge-entry.d.ts.map +1 -0
  289. package/lib/observation-knowledge-entry.js +13 -0
  290. package/lib/observation-knowledge-entry.js.map +1 -0
  291. package/lib/observation-loop.d.ts.map +1 -1
  292. package/lib/observation-loop.js +3 -0
  293. package/lib/observation-loop.js.map +1 -1
  294. package/lib/storage/split-state.d.ts +1 -0
  295. package/lib/storage/split-state.d.ts.map +1 -1
  296. package/lib/storage/split-state.js +9 -2
  297. package/lib/storage/split-state.js.map +1 -1
  298. package/lib/store.d.ts.map +1 -1
  299. package/lib/store.js +7 -0
  300. package/lib/store.js.map +1 -1
  301. package/lib/ui/affection-panel.d.ts +10 -0
  302. package/lib/ui/affection-panel.d.ts.map +1 -0
  303. package/lib/ui/affection-panel.js +44 -0
  304. package/lib/ui/affection-panel.js.map +1 -0
  305. package/lib/ui/capability-editor.d.ts.map +1 -1
  306. package/lib/ui/capability-editor.js +1 -1
  307. package/lib/ui/capability-editor.js.map +1 -1
  308. package/lib/ui/channels-panel.d.ts.map +1 -1
  309. package/lib/ui/channels-panel.js +13 -9
  310. package/lib/ui/channels-panel.js.map +1 -1
  311. package/lib/ui/character-editor.d.ts +3 -1
  312. package/lib/ui/character-editor.d.ts.map +1 -1
  313. package/lib/ui/character-editor.js +20 -18
  314. package/lib/ui/character-editor.js.map +1 -1
  315. package/lib/ui/character-memory-editor.d.ts +6 -1
  316. package/lib/ui/character-memory-editor.d.ts.map +1 -1
  317. package/lib/ui/character-memory-editor.js +17 -11
  318. package/lib/ui/character-memory-editor.js.map +1 -1
  319. package/lib/ui/companion-draft.d.ts +3 -0
  320. package/lib/ui/companion-draft.d.ts.map +1 -1
  321. package/lib/ui/companion-draft.js +1 -1
  322. package/lib/ui/companion-draft.js.map +1 -1
  323. package/lib/ui/identity-editor.d.ts.map +1 -1
  324. package/lib/ui/identity-editor.js +12 -6
  325. package/lib/ui/identity-editor.js.map +1 -1
  326. package/lib/ui/idle-contact-editor.d.ts.map +1 -1
  327. package/lib/ui/idle-contact-editor.js +3 -2
  328. package/lib/ui/idle-contact-editor.js.map +1 -1
  329. package/lib/ui/memory/memory-panel.d.ts.map +1 -1
  330. package/lib/ui/memory/memory-panel.js +5 -3
  331. package/lib/ui/memory/memory-panel.js.map +1 -1
  332. package/lib/ui/push-draft.d.ts +5 -5
  333. package/lib/ui/qq-capability-settings.d.ts +9 -0
  334. package/lib/ui/qq-capability-settings.d.ts.map +1 -0
  335. package/lib/ui/qq-capability-settings.js +24 -0
  336. package/lib/ui/qq-capability-settings.js.map +1 -0
  337. package/lib/ui/qq-channel-settings.d.ts +13 -0
  338. package/lib/ui/qq-channel-settings.d.ts.map +1 -0
  339. package/lib/ui/qq-channel-settings.js +51 -0
  340. package/lib/ui/qq-channel-settings.js.map +1 -0
  341. package/lib/ui/qq-identity-binding.d.ts +9 -0
  342. package/lib/ui/qq-identity-binding.d.ts.map +1 -0
  343. package/lib/ui/qq-identity-binding.js +6 -0
  344. package/lib/ui/qq-identity-binding.js.map +1 -0
  345. package/lib/ui/qq-voice-reply-settings.d.ts +9 -0
  346. package/lib/ui/qq-voice-reply-settings.d.ts.map +1 -0
  347. package/lib/ui/qq-voice-reply-settings.js +23 -0
  348. package/lib/ui/qq-voice-reply-settings.js.map +1 -0
  349. package/lib/ui/role-reference.js +1 -1
  350. package/lib/ui/role-reference.js.map +1 -1
  351. package/lib/ui/sleep-editor.d.ts +10 -0
  352. package/lib/ui/sleep-editor.d.ts.map +1 -0
  353. package/lib/ui/sleep-editor.js +45 -0
  354. package/lib/ui/sleep-editor.js.map +1 -0
  355. package/package.json +33 -5
@@ -0,0 +1,187 @@
1
+ import { qqGroupPeer, qqSettings } from './settings.js';
2
+ import { OneBotConnection, OneBotError } from './connection.js';
3
+ import { oneBotMessage, qqId } from './message.js';
4
+ import { imageType, readOutboundMedia } from '../direct/media.js';
5
+ import { PARTNER_MEDIA_MAX_BYTES, safeMediaName } from '../../channel-message.js';
6
+ /** Only public QQ media hosts; never forward the OneBot token to media URLs. */
7
+ export function qqMediaUrl(source) {
8
+ let url;
9
+ try {
10
+ url = new URL(source);
11
+ }
12
+ catch {
13
+ throw new Error('QQ 附件没有可下载地址,请重新发送原图或文件');
14
+ }
15
+ const domains = ['qpic.cn', 'gtimg.cn', 'multimedia.nt.qq.com'];
16
+ // qq.com is restricted to known download services, not arbitrary QQ links.
17
+ const known = domains.some(host => url.hostname === host || url.hostname.endsWith('.' + host))
18
+ || ['c2c.qpic.cn', 'gzc-download.ftn.qq.com', 'sz-download.ftn.qq.com'].includes(url.hostname);
19
+ if (!known || !['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.port && !['80', '443'].includes(url.port))
20
+ throw new Error('QQ 附件地址不属于受支持的媒体下载服务');
21
+ return url;
22
+ }
23
+ export class OneBotTransport {
24
+ config;
25
+ expected;
26
+ connection;
27
+ constructor(config, token, expected, connection) {
28
+ this.config = config;
29
+ this.expected = expected;
30
+ this.connection = connection ?? new OneBotConnection(config.baseUrl, token);
31
+ }
32
+ async validate(signal = AbortSignal.timeout(30000)) {
33
+ // Independent read-only checks share one round trip; all must pass before delivery.
34
+ const [who, status] = await Promise.all([this.connection.call('get_login_info', {}, signal), this.connection.call('get_status', {}, signal)]);
35
+ const accountId = qqId(who?.user_id);
36
+ if (!accountId || this.expected && accountId !== this.expected.accountId)
37
+ throw new OneBotError('QQ 登录账号无效或已变化,请重新配置渠道', false);
38
+ if (status?.online !== true || status?.good === false)
39
+ throw new OneBotError('SnowLuma QQ 尚未上线,请先在远程桌面登录');
40
+ const group = this.config.targetId.startsWith('group:') ? this.config.targetId.slice(6) : undefined;
41
+ if (group) {
42
+ const member = qqGroupPeer(this.expected?.peerId ?? '');
43
+ const policy = qqSettings(this.config.qq);
44
+ if (!qqId(group) || !member || member.groupId !== group || !policy.groupReplies || !policy.groupIds.includes(group))
45
+ throw new OneBotError('群回复未开启或目标群未授权', false);
46
+ const [groups, info] = await Promise.all([this.connection.call('get_group_list', {}, signal), this.connection.call('get_group_member_info', { group_id: Number(group), user_id: Number(member.userId) }, signal)]);
47
+ if (!Array.isArray(groups) || !groups.some(g => qqId(g.group_id) === group))
48
+ throw new OneBotError('机器人已不在目标群中', false);
49
+ if (qqId(info?.user_id) !== member.userId || qqId(info?.group_id) !== group)
50
+ throw new OneBotError('群成员身份已变化', false);
51
+ return { accountId, peerId: this.expected.peerId };
52
+ }
53
+ const peerId = this.config.targetId;
54
+ if (peerId) {
55
+ if (!qqId(peerId) || peerId === accountId)
56
+ throw new OneBotError('QQ 联系人号码无效', false);
57
+ const friends = await this.connection.call('get_friend_list', {}, signal);
58
+ if (!Array.isArray(friends) || !friends.some(friend => qqId(friend?.user_id) === peerId))
59
+ throw new OneBotError('目标 QQ 不在好友列表中,请先添加好友', false);
60
+ if (this.expected?.peerId && this.expected.peerId !== peerId)
61
+ throw new OneBotError('QQ 联系人身份已变化', false);
62
+ }
63
+ return { accountId, peerId };
64
+ }
65
+ async poll(signal, waitMs) {
66
+ const identity = await this.validate(signal);
67
+ const events = await this.connection.read(signal, waitMs);
68
+ const messages = events.map(event => oneBotMessage(event, identity.accountId, this.config.targetId, qqSettings(this.config.qq))).filter((event) => Boolean(event));
69
+ for (const message of messages) {
70
+ const group = message.qqGroup;
71
+ if (group?.replyToId) {
72
+ const target = this.connection.quotedTarget(group.groupId, group.replyToId, identity.accountId);
73
+ if (target)
74
+ group.replyTo = target;
75
+ }
76
+ }
77
+ return { cursor: 'onebot-live', messages };
78
+ }
79
+ async sendText(userId, text, signal, authorize) {
80
+ if (!text.trim())
81
+ return;
82
+ await this.recipient(userId, signal);
83
+ // QQ receives plain text segments. CQ-looking model output cannot become an action.
84
+ const chars = Array.from(text);
85
+ for (let offset = 0; offset < chars.length; offset += 3000) {
86
+ authorize?.();
87
+ const result = await this.connection.call(this.sendAction(userId), { ...this.destination(userId), message: [...(offset === 0 ? this.mention(userId) : []), { type: 'text', data: { text: chars.slice(offset, offset + 3000).join('') } }] }, signal);
88
+ if (!result || !['string', 'number'].includes(typeof result.message_id))
89
+ throw new OneBotError('QQ 未确认文本发送结果', false);
90
+ }
91
+ }
92
+ async recipient(userId, signal) {
93
+ const identity = await this.validate(signal);
94
+ if (!qqGroupPeer(userId) && !qqSettings(this.config.qq).privateReplies)
95
+ throw new OneBotError('私聊回复已关闭', false);
96
+ if (!this.config.targetId || identity.peerId !== userId)
97
+ throw new OneBotError('QQ 消息接收人与已授权联系人不匹配', false);
98
+ }
99
+ async sendAttachment(userId, file, signal, allowed) {
100
+ if (!allowed())
101
+ throw Error('渠道或联系人授权已撤销');
102
+ await this.recipient(userId, signal);
103
+ const data = await readOutboundMedia(file, signal);
104
+ if (!allowed())
105
+ throw Error('渠道或联系人授权已撤销');
106
+ const image = imageType(data);
107
+ if (image) {
108
+ if (!qqSettings(this.config.qq).imagesEnabled)
109
+ throw new OneBotError('QQ 图片与表情包发送已关闭', false);
110
+ const sent = await this.connection.call(this.sendAction(userId), { ...this.destination(userId), message: [{ type: 'image', data: { file: 'base64://' + data.toString('base64') } }] }, signal);
111
+ if (!sent || !['string', 'number'].includes(typeof sent.message_id))
112
+ throw new OneBotError('QQ 未确认图片发送结果', false);
113
+ }
114
+ else {
115
+ // SnowLuma accepts base64 uploads; container-local paths would point at the wrong host.
116
+ const sent = await this.connection.call(qqGroupPeer(userId) ? 'upload_group_file' : 'upload_private_file', { ...this.destination(userId), file: 'base64://' + data.toString('base64'), name: safeMediaName(file.name, '附件.bin') }, signal);
117
+ if (typeof sent?.file_id !== 'string' || !sent.file_id)
118
+ throw new OneBotError('QQ 未确认文件发送结果', false);
119
+ }
120
+ }
121
+ sendAction(userId) { return qqGroupPeer(userId) ? 'send_group_msg' : 'send_private_msg'; }
122
+ destination(userId) {
123
+ const group = qqGroupPeer(userId);
124
+ return group ? { group_id: Number(group.groupId) } : { user_id: Number(userId) };
125
+ }
126
+ mention(userId) {
127
+ const group = qqGroupPeer(userId);
128
+ return group && qqSettings(this.config.qq).mentionSender ? [{ type: 'at', data: { qq: group.userId } }, { type: 'text', data: { text: ' ' } }] : [];
129
+ }
130
+ async sendCustomFace(userId, emojiId, signal, authorize) {
131
+ if (!qqSettings(this.config.qq).imagesEnabled)
132
+ throw new OneBotError('QQ 图片与表情包发送已关闭', false);
133
+ if (!emojiId || emojiId.length > 512 || /[\x00-\x1f]/.test(emojiId))
134
+ throw new OneBotError('QQ 收藏表情标识无效', false);
135
+ await this.recipient(userId, signal);
136
+ authorize();
137
+ const sent = await this.connection.call('send_custom_face', { ...this.destination(userId), emoji_id: emojiId }, signal);
138
+ if (!sent || !['string', 'number'].includes(typeof sent.message_id))
139
+ throw new OneBotError('QQ 未确认收藏表情发送结果', false);
140
+ }
141
+ async sendFace(userId, faceId, signal, authorize) {
142
+ if (!qqSettings(this.config.qq).facesEnabled)
143
+ throw new OneBotError('QQ 系统表情发送已关闭', false);
144
+ if (!/^\d{1,6}$/.test(faceId))
145
+ throw new OneBotError('QQ 表情编号无效', false);
146
+ await this.recipient(userId, signal);
147
+ authorize();
148
+ const sent = await this.connection.call(this.sendAction(userId), { ...this.destination(userId), message: [...this.mention(userId), { type: 'face', data: { id: faceId } }] }, signal);
149
+ if (!sent || !['string', 'number'].includes(typeof sent.message_id))
150
+ throw new OneBotError('QQ 未确认表情发送结果', false);
151
+ }
152
+ async receiveAttachments(message, signal, allowed, maxBytes = PARTNER_MEDIA_MAX_BYTES) {
153
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 0 || maxBytes > PARTNER_MEDIA_MAX_BYTES)
154
+ throw Error('附件大小限制无效');
155
+ const refs = message.media ?? [];
156
+ if (refs.length > 8)
157
+ throw Error('单条消息最多接收 8 个附件');
158
+ const result = [];
159
+ let total = 0;
160
+ for (const ref of refs) {
161
+ if (!allowed())
162
+ throw Error('渠道或联系人授权已撤销');
163
+ await this.recipient(message.sender, signal);
164
+ if (ref.size !== undefined && (!Number.isSafeInteger(ref.size) || ref.size < 0 || ref.size > maxBytes - total))
165
+ throw Error('QQ 附件超过大小限制');
166
+ const response = await fetch(qqMediaUrl(ref.source), { signal, redirect: 'error' });
167
+ if (!response.ok || !response.body || Number(response.headers.get('content-length')) > maxBytes - total) {
168
+ await response.body?.cancel();
169
+ throw Error('QQ 附件无法下载或超过大小限制');
170
+ }
171
+ const chunks = [];
172
+ for await (const chunk of response.body) {
173
+ total += chunk.length;
174
+ if (total > maxBytes)
175
+ throw Error('QQ 附件总大小超过限制');
176
+ chunks.push(chunk);
177
+ }
178
+ if (!allowed())
179
+ throw Error('渠道或联系人授权已撤销');
180
+ const data = Buffer.concat(chunks), type = imageType(data);
181
+ const rawType = response.headers.get('content-type')?.split(';')[0]?.trim() ?? '';
182
+ result.push({ data, name: safeMediaName(ref.name ?? '', type ? 'QQ图片.' + type.split('/')[1] : 'QQ附件.bin'), kind: type ? 'image' : 'file', mediaType: type ?? (/^[a-z0-9.+-]+\/[a-z0-9.+-]+$/i.test(rawType) ? rawType : 'application/octet-stream') });
183
+ }
184
+ return result;
185
+ }
186
+ }
187
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../src/channels/qq/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type QqSettings } from './qq/settings.js';
2
+ interface ReplyAccessState {
3
+ channels: readonly {
4
+ id: string;
5
+ enabled: boolean;
6
+ platform?: string;
7
+ qq?: Partial<QqSettings>;
8
+ direct?: {
9
+ targetId: string;
10
+ };
11
+ }[];
12
+ pairings: readonly {
13
+ channelId: string;
14
+ userId: string;
15
+ status: string;
16
+ directTargetId?: string;
17
+ }[];
18
+ }
19
+ /** Group membership is encoded by the verified channel peer, never message text.
20
+ * A whitelisted QQ group grants chat access; other connected groups require member approval. */
21
+ export declare function channelReplyAllowed(state: ReplyAccessState, channelId: string, userId: string, targetId?: string): boolean;
22
+ /** Preserve direct-room routing; QQ group replies need no synthetic per-member grant. */
23
+ export declare function directReplyTarget(state: ReplyAccessState, channelId: string, userId: string): string;
24
+ export {};
25
+ //# sourceMappingURL=reply-access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-access.d.ts","sourceRoot":"","sources":["../../src/channels/reply-access.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE3E,UAAU,gBAAgB;IACxB,QAAQ,EAAE,SAAS;QAAC,EAAE,EAAC,MAAM,CAAC;QAAA,OAAO,EAAC,OAAO,CAAC;QAAA,QAAQ,CAAC,EAAC,MAAM,CAAC;QAAA,EAAE,CAAC,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAAA,MAAM,CAAC,EAAC;YAAC,QAAQ,EAAC,MAAM,CAAA;SAAC,CAAA;KAAC,EAAE,CAAA;IACnH,QAAQ,EAAE,SAAS;QAAC,SAAS,EAAC,MAAM,CAAC;QAAA,MAAM,EAAC,MAAM,CAAC;QAAA,MAAM,EAAC,MAAM,CAAC;QAAA,cAAc,CAAC,EAAC,MAAM,CAAA;KAAC,EAAE,CAAA;CAC3F;AAED;gGACgG;AAChG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,EAAE,MAAM,EAAC,MAAM,EAAE,QAAQ,CAAC,EAAC,MAAM,GAAE,OAAO,CAgBtH;AAED,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,KAAK,EAAC,gBAAgB,EAAE,SAAS,EAAC,MAAM,EAAE,MAAM,EAAC,MAAM,GAAE,MAAM,CAIhG"}
@@ -0,0 +1,29 @@
1
+ import { qqGroupPeer, qqSettings } from './qq/settings.js';
2
+ /** Group membership is encoded by the verified channel peer, never message text.
3
+ * A whitelisted QQ group grants chat access; other connected groups require member approval. */
4
+ export function channelReplyAllowed(state, channelId, userId, targetId) {
5
+ const channel = state.channels.find(c => c.id === channelId);
6
+ if (!channel?.enabled)
7
+ return false;
8
+ const pairing = state.pairings.find(p => p.channelId === channelId && p.userId === userId);
9
+ if (channel.platform === 'qq') {
10
+ const settings = qqSettings(channel.qq), group = qqGroupPeer(userId);
11
+ if (group) {
12
+ const target = `group:${group.groupId}`;
13
+ return settings.groupReplies && settings.groupIds.includes(group.groupId) && pairing?.status !== 'blocked'
14
+ && (settings.autonomousGroupIds.includes(group.groupId) || pairing?.status === 'approved')
15
+ && (!channel.direct?.targetId || channel.direct.targetId === target)
16
+ && (!targetId || targetId === target) && (!pairing?.directTargetId || pairing.directTargetId === target);
17
+ }
18
+ if (!settings.privateReplies)
19
+ return false;
20
+ }
21
+ return pairing?.status === 'approved' && (!targetId || !pairing.directTargetId || pairing.directTargetId === targetId);
22
+ }
23
+ /** Preserve direct-room routing; QQ group replies need no synthetic per-member grant. */
24
+ export function directReplyTarget(state, channelId, userId) {
25
+ const channel = state.channels.find(c => c.id === channelId);
26
+ const group = channel?.platform === 'qq' ? qqGroupPeer(userId) : undefined;
27
+ return channel?.direct?.targetId || (group ? `group:${group.groupId}` : state.pairings.find(p => p.channelId === channelId && p.userId === userId)?.directTargetId) || '';
28
+ }
29
+ //# sourceMappingURL=reply-access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-access.js","sourceRoot":"","sources":["../../src/channels/reply-access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAO3E;gGACgG;AAChG,MAAM,UAAU,mBAAmB,CAAC,KAAuB,EAAE,SAAgB,EAAE,MAAa,EAAE,QAAgB;IAC5G,MAAM,OAAO,GAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA,EAAE,CAAA,CAAC,CAAC,EAAE,KAAG,SAAS,CAAC,CAAA;IACtD,IAAG,CAAC,OAAO,EAAE,OAAO;QAAC,OAAO,KAAK,CAAA;IACjC,MAAM,OAAO,GAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA,EAAE,CAAA,CAAC,CAAC,SAAS,KAAG,SAAS,IAAE,CAAC,CAAC,MAAM,KAAG,MAAM,CAAC,CAAA;IAChF,IAAG,OAAO,CAAC,QAAQ,KAAG,IAAI,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,EAAC,KAAK,GAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAC/D,IAAG,KAAK,EAAE,CAAC;YACT,MAAM,MAAM,GAAC,SAAS,KAAK,CAAC,OAAO,EAAE,CAAA;YACrC,OAAO,QAAQ,CAAC,YAAY,IAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAE,OAAO,EAAE,MAAM,KAAG,SAAS;mBAChG,CAAC,QAAQ,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAE,OAAO,EAAE,MAAM,KAAG,UAAU,CAAC;mBACnF,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,IAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,KAAG,MAAM,CAAC;mBAC7D,CAAC,CAAC,QAAQ,IAAE,QAAQ,KAAG,MAAM,CAAC,IAAE,CAAC,CAAC,OAAO,EAAE,cAAc,IAAE,OAAO,CAAC,cAAc,KAAG,MAAM,CAAC,CAAA;QACjG,CAAC;QACD,IAAG,CAAC,QAAQ,CAAC,cAAc;YAAC,OAAO,KAAK,CAAA;IAC1C,CAAC;IACD,OAAO,OAAO,EAAE,MAAM,KAAG,UAAU,IAAE,CAAC,CAAC,QAAQ,IAAE,CAAC,OAAO,CAAC,cAAc,IAAE,OAAO,CAAC,cAAc,KAAG,QAAQ,CAAC,CAAA;AAC9G,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,iBAAiB,CAAC,KAAsB,EAAE,SAAgB,EAAE,MAAa;IACvF,MAAM,OAAO,GAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA,EAAE,CAAA,CAAC,CAAC,EAAE,KAAG,SAAS,CAAC,CAAA;IACtD,MAAM,KAAK,GAAC,OAAO,EAAE,QAAQ,KAAG,IAAI,CAAA,CAAC,CAAA,WAAW,CAAC,MAAM,CAAC,CAAA,CAAC,CAAA,SAAS,CAAA;IAClE,OAAO,OAAO,EAAE,MAAM,EAAE,QAAQ,IAAI,CAAC,KAAK,CAAA,CAAC,CAAA,SAAS,KAAK,CAAC,OAAO,EAAE,CAAA,CAAC,CAAA,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA,EAAE,CAAA,CAAC,CAAC,SAAS,KAAG,SAAS,IAAE,CAAC,CAAC,MAAM,KAAG,MAAM,CAAC,EAAE,cAAc,CAAC,IAAI,EAAE,CAAA;AAC/J,CAAC"}
@@ -10,7 +10,9 @@ export declare function connectWeixin(login: ConfirmedLogin, runtime: {
10
10
  }): Promise<{
11
11
  enabled: boolean;
12
12
  updatedAt: number;
13
- platform?: "weixin" | "matrix" | "mattermost";
13
+ qq?: import("../qq/settings.js").QqSettings;
14
+ qqActivity?: import("../qq/actions.js").QqActionReceipt[];
15
+ platform?: "weixin" | "matrix" | "mattermost" | "qq";
14
16
  direct?: {
15
17
  baseUrl: string;
16
18
  targetId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/channels/weixin/connect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGhD,yEAAyE;AACzE,wBAAsB,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE;IAClE,KAAK,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,sBAAsB,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CACnF;;;;;;;;cAqBK,CAAC;;;;;;;GAiBN"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/channels/weixin/connect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGhD,yEAAyE;AACzE,wBAAsB,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE;IAClE,KAAK,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,sBAAsB,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CACnF;;;;;;;;;;cA+BkD,CAAC;;;;;;;GAOnD"}
@@ -0,0 +1,7 @@
1
+ import type { ToolDefinition } from '@deepseek-ai/dsh-tools';
2
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
3
+ import type { PartnerStore } from '../store.js';
4
+ /** A terminal receipt, never a magic text token that could accidentally be sent to QQ. */
5
+ export declare function isSilentActivityResult(event: SessionEvent): boolean;
6
+ export declare function idleActivityFinishTool(owner: string, store: PartnerStore): ToolDefinition;
7
+ //# sourceMappingURL=activity-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-tool.d.ts","sourceRoot":"","sources":["../../src/character/activity-tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG/C,0FAA0F;AAC1F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAInE;AACD,wBAAgB,sBAAsB,CAAC,KAAK,EAAC,MAAM,EAAC,KAAK,EAAC,YAAY,GAAE,cAAc,CAuBrF"}
@@ -0,0 +1,38 @@
1
+ import { activityPolicyCurrent } from './post-reply.js';
2
+ import { isIdleContactNotice, lastIdleContactUser, idleContactRouteAllowed } from './idle-contact.js';
3
+ /** A terminal receipt, never a magic text token that could accidentally be sent to QQ. */
4
+ export function isSilentActivityResult(event) {
5
+ if (event.type !== 'tool/result' && event.type !== 'tool/ptc-dispatch')
6
+ return false;
7
+ if (event.type === 'tool/result' ? event.data.message?.isError : event.data.isError)
8
+ return false;
9
+ return event.data.meta?.kind === 'partner-activity-silent-v1';
10
+ }
11
+ export function idleActivityFinishTool(owner, store) {
12
+ return {
13
+ name: 'partner_activity_finish',
14
+ description: '安静结束系统发起的闲时自主活动。已使用工具完成活动、已经发送语音或不想行动时调用;不发送聊天正文。仅限当前自主活动,不可用来跳过用户消息或工作任务。需要聊天则用正常最终回复或 partner_chat_reply。',
15
+ parameters: { type: 'object', properties: { reason: { type: 'string', maxLength: 300 } }, required: ['reason'], additionalProperties: false },
16
+ output: { schema: { type: 'object' }, render: () => [{ type: 'text', text: '本次自主活动已结束,不发送聊天正文。' }], presentationMeta: (_args, value) => value },
17
+ presentCall: () => ({ card: 'generic', title: '自主活动结束' }),
18
+ async execute(raw, exec) {
19
+ exec.signal.throwIfAborted();
20
+ const agent = exec.agent, events = agent?.session.snapshotEvents() ?? [];
21
+ const start = [...events].reverse().find(e => e.type === 'turn/start')?.seq ?? -1;
22
+ const inputs = events.filter(e => e.seq > start && e.type === 'user/message' && (e.data.source.kind === 'user' || !('form' in e.data.source) || !['snapshot', 'catalog', 'instructions', 'recall'].includes(e.data.source.form ?? '')));
23
+ const notice = inputs.find(isIdleContactNotice);
24
+ const state = store.snapshot(), companion = state.companions.find(c => c.id === owner);
25
+ const route = state.sessions.find(r => r.companionId === owner && r.sessionId === agent?.session.id && notice?.type === 'user/message' && r.idleContactState?.messageId === notice.data.id);
26
+ if (!companion || !route || !activityPolicyCurrent(state, companion, route) || store.isCompanionRemoving(owner) || !idleContactRouteAllowed(state, companion, route.id) || notice?.type !== 'user/message' || inputs.some(e => !isIdleContactNotice(e)) || route.idleContactState?.messageId !== notice.data.id || lastIdleContactUser(events)?.id !== route.idleContactState.userMessageId)
27
+ throw Error('只能结束当前系统发起的自主活动,不能忽略用户消息或其他任务');
28
+ const { reason } = raw;
29
+ if (typeof reason !== 'string' || !reason.trim() || reason.length > 300)
30
+ throw Error('请简要记录活动结果或不行动的原因');
31
+ if (typeof exec.concludeTurn !== 'function')
32
+ throw Error('当前宿主不支持安静结束活动');
33
+ exec.concludeTurn();
34
+ return { kind: 'partner-activity-silent-v1', reason: reason.trim(), messageId: notice.data.id };
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=activity-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-tool.js","sourceRoot":"","sources":["../../src/character/activity-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { ChannelSession, WeixinChannel } from '../domain.js';
2
+ export interface AffectionAudience {
3
+ route: ChannelSession;
4
+ channel?: WeixinChannel;
5
+ autonomous?: boolean;
6
+ }
7
+ export interface AffectionAdapter {
8
+ resolve(audience: AffectionAudience): boolean | undefined;
9
+ }
10
+ /** Default channels participate; QQ supplies its own verified-account restriction. */
11
+ export declare const defaultAffectionAdapter: AffectionAdapter;
12
+ export declare function affectionAudienceAllowed(audience: AffectionAudience): boolean;
13
+ //# sourceMappingURL=affection-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affection-adapter.d.ts","sourceRoot":"","sources":["../../src/character/affection-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjE,MAAM,WAAW,iBAAiB;IAAG,KAAK,EAAE,cAAc,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE;AAC3G,MAAM,WAAW,gBAAgB;IAAG,OAAO,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,GAAG,SAAS,CAAA;CAAE;AAC/F,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,EAAE,gBAAmC,CAAA;AAEzE,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAG7E"}
@@ -0,0 +1,13 @@
1
+ import { qqAffectionAdapter } from '../channels/qq/affection-adapter.js';
2
+ /** Default channels participate; QQ supplies its own verified-account restriction. */
3
+ export const defaultAffectionAdapter = { resolve: () => true };
4
+ const adapters = [qqAffectionAdapter];
5
+ export function affectionAudienceAllowed(audience) {
6
+ for (const adapter of adapters) {
7
+ const result = adapter.resolve(audience);
8
+ if (result !== undefined)
9
+ return result;
10
+ }
11
+ return defaultAffectionAdapter.resolve(audience) === true;
12
+ }
13
+ //# sourceMappingURL=affection-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affection-adapter.js","sourceRoot":"","sources":["../../src/character/affection-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAA;AAGxE,sFAAsF;AACtF,MAAM,CAAC,MAAM,uBAAuB,GAAmB,EAAC,OAAO,EAAC,GAAE,EAAE,CAAA,IAAI,EAAC,CAAA;AACzE,MAAM,QAAQ,GAA6B,CAAC,kBAAkB,CAAC,CAAA;AAC/D,MAAM,UAAU,wBAAwB,CAAC,QAA2B;IAClE,KAAI,MAAM,OAAO,IAAI,QAAQ,EAAC,CAAC;QAAA,MAAM,MAAM,GAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAAA,IAAG,MAAM,KAAG,SAAS;YAAC,OAAO,MAAM,CAAA;IAAA,CAAC;IAC1G,OAAO,uBAAuB,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAG,IAAI,CAAA;AACzD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
2
+ import type { PartnerState } from '../domain.js';
3
+ /** Resolve from persisted provenance, never from names or text claiming ownership. */
4
+ export declare function affectionForInput(state: PartnerState, owner: string, sessionId: string, input: SessionEvent): boolean;
5
+ export declare function currentAffectionAudience(state: PartnerState, owner: string, sessionId: string, events: readonly SessionEvent[]): boolean;
6
+ export declare function affectionTurnEligible(state: PartnerState, owner: string, sessionId: string, events: readonly SessionEvent[]): boolean;
7
+ //# sourceMappingURL=affection-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affection-context.d.ts","sourceRoot":"","sources":["../../src/character/affection-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAKhD,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAWrH;AACD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAGxI;AACD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAGrI"}
@@ -0,0 +1,33 @@
1
+ import { isInternalTaskNotice } from '../channels/delivery-policy.js';
2
+ import { isIdleContactNotice } from './idle-contact.js';
3
+ import { affectionAudienceAllowed } from './affection-adapter.js';
4
+ /** Resolve from persisted provenance, never from names or text claiming ownership. */
5
+ export function affectionForInput(state, owner, sessionId, input) {
6
+ if (input.type !== 'user/message' || isInternalTaskNotice(input))
7
+ return false;
8
+ const routes = state.sessions.filter(r => r.companionId === owner && r.sessionId === sessionId);
9
+ const autonomous = isIdleContactNotice(input);
10
+ if (!autonomous && input.data.source.kind !== 'user')
11
+ return false;
12
+ const route = autonomous ? routes.find(r => r.idleContactState?.messageId === input.data.id)
13
+ : routes.find(r => r.kind === 'channel' && r.inboundMessageIds?.includes(input.data.id)) ?? routes.find(r => r.kind === 'local');
14
+ if (!route)
15
+ return false;
16
+ const channel = state.channels?.find(c => c.id === route.channelId && c.companionId === owner);
17
+ if (route.kind === 'channel' && !channel)
18
+ return false;
19
+ return affectionAudienceAllowed({ route, ...(channel ? { channel } : {}), autonomous: autonomous && route.idleContactState?.kind !== 'post-reply' });
20
+ }
21
+ export function currentAffectionAudience(state, owner, sessionId, events) {
22
+ for (let i = events.length - 1; i >= 0; i--) {
23
+ const e = events[i];
24
+ if (e.type === 'user/message' && (e.data.source.kind === 'user' || isIdleContactNotice(e) || isInternalTaskNotice(e)))
25
+ return affectionForInput(state, owner, sessionId, e);
26
+ }
27
+ return false;
28
+ }
29
+ export function affectionTurnEligible(state, owner, sessionId, events) {
30
+ const inputs = events.filter(e => e.type === 'user/message' && (e.data.source.kind === 'user' || isIdleContactNotice(e) || isInternalTaskNotice(e)));
31
+ return inputs.length > 0 && inputs.every(e => e.type === 'user/message' && e.data.source.kind === 'user' && affectionForInput(state, owner, sessionId, e));
32
+ }
33
+ //# sourceMappingURL=affection-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affection-context.js","sourceRoot":"","sources":["../../src/character/affection-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { Companion } from '../domain.js';
2
+ /** One relationship progression per companion, shared by all eligible audiences. */
3
+ export interface AffectionState {
4
+ score: number;
5
+ updatedAt: number;
6
+ lastAwardAt: number;
7
+ lastTurnId: string;
8
+ }
9
+ export declare const AFFECTION_INITIAL = 20;
10
+ export declare const AFFECTION_INTERVAL: number;
11
+ export declare const AFFECTION_LEVELS: readonly [{
12
+ readonly min: 0;
13
+ readonly name: "相识";
14
+ readonly behavior: "自然接话,有具体话题时主动分享。";
15
+ }, {
16
+ readonly min: 20;
17
+ readonly name: "熟悉";
18
+ readonly behavior: "更愿意分享兴趣、日常感想和轻松的玩笑。";
19
+ }, {
20
+ readonly min: 40;
21
+ readonly name: "亲近";
22
+ readonly behavior: "更愿意主动找话题、分享发现,按语境使用表情。";
23
+ }, {
24
+ readonly min: 60;
25
+ readonly name: "信赖";
26
+ readonly behavior: "更愿意延续共同话题、主动关心,合适时使用已开启的语音。";
27
+ }, {
28
+ readonly min: 80;
29
+ readonly name: "默契";
30
+ readonly behavior: "更自然地表达牵挂、分享心事,主动使用适合当前相处的已授权互动能力。";
31
+ }];
32
+ export declare function affectionEnabled(companion: Pick<Companion, 'characterCard'>): boolean;
33
+ export declare function affectionProgress(state?: AffectionState): {
34
+ score: number;
35
+ level: number;
36
+ name: "相识" | "熟悉" | "亲近" | "信赖" | "默契";
37
+ behavior: "自然接话,有具体话题时主动分享。" | "更愿意分享兴趣、日常感想和轻松的玩笑。" | "更愿意主动找话题、分享发现,按语境使用表情。" | "更愿意延续共同话题、主动关心,合适时使用已开启的语音。" | "更自然地表达牵挂、分享心事,主动使用适合当前相处的已授权互动能力。";
38
+ nextName: "相识" | "熟悉" | "亲近" | "信赖" | "默契" | null;
39
+ nextAt: number;
40
+ remaining: number;
41
+ multiplier: number;
42
+ updatedAt: number;
43
+ };
44
+ export declare function awardAffection(companion: Companion, turnId: string, at: number): boolean;
45
+ export declare function affectionMultiplier(companion: Companion, eligible: boolean): number;
46
+ export declare function renderAffection(companion: Companion, eligible: boolean): string;
47
+ //# sourceMappingURL=affection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affection.d.ts","sourceRoot":"","sources":["../../src/character/affection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAC7G,eAAO,MAAM,iBAAiB,KAAK,CAAA;AACnC,eAAO,MAAM,kBAAkB,QAAc,CAAA;AAC7C,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;EAMnB,CAAA;AACV,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAC,eAAe,CAAC,GAAG,OAAO,CAEpF;AACD,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,cAAc;;;;;;;;;;EAKvD;AACD,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CASxF;AACD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAEnF;AACD,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAI/E"}
@@ -0,0 +1,41 @@
1
+ export const AFFECTION_INITIAL = 20;
2
+ export const AFFECTION_INTERVAL = 10 * 60_000;
3
+ export const AFFECTION_LEVELS = [
4
+ { min: 0, name: '相识', behavior: '自然接话,有具体话题时主动分享。' },
5
+ { min: 20, name: '熟悉', behavior: '更愿意分享兴趣、日常感想和轻松的玩笑。' },
6
+ { min: 40, name: '亲近', behavior: '更愿意主动找话题、分享发现,按语境使用表情。' },
7
+ { min: 60, name: '信赖', behavior: '更愿意延续共同话题、主动关心,合适时使用已开启的语音。' },
8
+ { min: 80, name: '默契', behavior: '更自然地表达牵挂、分享心事,主动使用适合当前相处的已授权互动能力。' },
9
+ ];
10
+ export function affectionEnabled(companion) {
11
+ return companion.characterCard?.enabled === true && companion.characterCard.affectionEnabled !== false;
12
+ }
13
+ export function affectionProgress(state) {
14
+ const score = Number.isFinite(state?.score) ? Math.max(0, Math.min(100, Math.round(state.score))) : AFFECTION_INITIAL;
15
+ const index = Math.min(AFFECTION_LEVELS.length - 1, Math.floor(score / 20)), level = AFFECTION_LEVELS[index];
16
+ const next = AFFECTION_LEVELS[index + 1];
17
+ return { score, level: index + 1, name: level.name, behavior: level.behavior, nextName: next?.name ?? null, nextAt: next?.min ?? 100, remaining: next ? next.min - score : 0, multiplier: 1 + score / 100, updatedAt: state?.updatedAt ?? 0 };
18
+ }
19
+ export function awardAffection(companion, turnId, at) {
20
+ if (!affectionEnabled(companion) || !turnId || !Number.isFinite(at) || at <= 0)
21
+ return false;
22
+ const previous = companion.affection;
23
+ if (previous && (previous.lastTurnId === turnId || at - previous.lastAwardAt < AFFECTION_INTERVAL))
24
+ return false;
25
+ const score = affectionProgress(previous).score;
26
+ if (score >= 100)
27
+ return false;
28
+ companion.affection = { score: score + 1, updatedAt: at, lastAwardAt: at, lastTurnId: turnId };
29
+ // Progress is runtime state; do not invalidate identity drafts or rebuild tools.
30
+ return true;
31
+ }
32
+ export function affectionMultiplier(companion, eligible) {
33
+ return eligible && affectionEnabled(companion) ? affectionProgress(companion.affection).multiplier : 1;
34
+ }
35
+ export function renderAffection(companion, eligible) {
36
+ if (!eligible || !affectionEnabled(companion))
37
+ return '';
38
+ const p = affectionProgress(companion.affection);
39
+ return `【当前共同好感度】${p.score}/100 · Lv.${p.level} ${p.name}。\n${p.behavior}\n这是本伙伴与适用对象共用的互动进度,QQ 多个归属账号共用;它不证明不同账号是同一人,不共享或编造他们各自的经历。保持原角色和关系,不因低等级疏远、不因高等级强制亲昵。好感度影响互动意愿,不解锁工具或绕过权限;尊重对方当下意愿,不催回复、不为加分重复联系,也不要求用户取悦你。无需在聊天中报告分数。`;
40
+ }
41
+ //# sourceMappingURL=affection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affection.js","sourceRoot":"","sources":["../../src/character/affection.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { type CharacterCard } from './domain.js';
2
2
  /** Shared chat preset, independent of role prose and transport. No tool filtering. */
3
3
  export declare function renderConversationBehavior(card?: CharacterCard): string;
4
4
  /** Short refresh at each real user turn; no timers, extra LLM calls or synthetic user events. */
5
- export declare function renderConversationTurn(card: CharacterCard | undefined, consecutiveUserMessages: number): string;
5
+ export declare function renderConversationTurn(card: CharacterCard | undefined, consecutiveUserMessages: number, autonomous?: boolean): string;
6
6
  /** Repeat the active delivery preferences at the current turn, including after compaction. */
7
7
  export declare function renderChatDeliveryGuidance(card?: CharacterCard): string;
8
8
  /** A small, current role anchor prevents transport reminders from becoming the conversation's voice. */
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-behavior.d.ts","sourceRoot":"","sources":["../../src/character/conversation-behavior.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAEjE,sFAAsF;AACtF,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAiBvE;AAED,iGAAiG;AACjG,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,EAAE,uBAAuB,EAAE,MAAM,GAAG,MAAM,CAS/G;AAED,8FAA8F;AAC9F,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAYvE;AAED,wGAAwG;AACxG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAQhE"}
1
+ {"version":3,"file":"conversation-behavior.d.ts","sourceRoot":"","sources":["../../src/character/conversation-behavior.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAEjE,sFAAsF;AACtF,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAiBvE;AAED,iGAAiG;AACjG,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,EAAE,uBAAuB,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,MAAM,CAWnI;AAED,8FAA8F;AAC9F,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAYvE;AAED,wGAAwG;AACxG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAQhE"}
@@ -19,15 +19,17 @@ export function renderConversationBehavior(card) {
19
19
  ].filter(Boolean).join('\n\n');
20
20
  }
21
21
  /** Short refresh at each real user turn; no timers, extra LLM calls or synthetic user events. */
22
- export function renderConversationTurn(card, consecutiveUserMessages) {
22
+ export function renderConversationTurn(card, consecutiveUserMessages, autonomous = false) {
23
23
  if (!card?.enabled)
24
24
  return '';
25
25
  return [
26
- '【本轮聊天提醒】',
26
+ autonomous ? '【本轮自主活动提醒】不是用户新消息,可安静结束,不要求聊天。' : '【本轮聊天提醒】',
27
27
  consecutiveUserMessages > 1 ? `对方连续发了 ${consecutiveUserMessages} 条消息,请结合起来理解,不逐条机械答复。` : '结合眼前发言和仍在继续的话题回应。',
28
28
  renderChatDeliveryGuidance(card),
29
29
  renderTurnRoleAnchor(card),
30
- '使用当前角色的反应方式,历史里的客服腔不必延续;说完有内容的话即可,不自动补建议、选项或追问。若有实际任务,继续使用全部已授权工具完成;纯闲聊不套用工作汇报。直接私聊需要可见回复。',
30
+ '使用当前角色的反应方式,历史里的客服腔不必延续;说完有内容的话即可,不自动补建议、选项或追问。若有实际任务,继续使用全部已授权工具完成;纯闲聊不套用工作汇报。',
31
+ '查工具、改资料或处理故障后,你仍是同一个角色。给出实际结果或必要限制就够,不自动加认错开场、责任声明、能力声明或自我点评;用户要求详细分析、正式文档时再展开。对方说你像 AI,是在表达不喜欢这句说话方式:直接接住当下的话,不复述自己的错误句子,不写“我刚才太像……,我应该说……”的整改报告。',
32
+ autonomous ? '这轮可调用 partner_activity_finish 安静结束;聊天、语音或其他活动按实际需要选择,工具已表达完毕就不再重复汇报。' : '直接私聊需要可见回复。',
31
33
  ].join('\n');
32
34
  }
33
35
  /** Repeat the active delivery preferences at the current turn, including after compaction. */