@openclaw/qqbot 2026.5.2 → 2026.5.3-beta.1

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 (203) hide show
  1. package/dist/api.js +646 -0
  2. package/dist/approval-cg0SVahb.js +94 -0
  3. package/dist/channel-N6Y_Rcjp.js +551 -0
  4. package/dist/channel-plugin-api.js +2 -0
  5. package/dist/channel.setup-ByCRAe5H.js +25 -0
  6. package/dist/config-D6545NkC.js +94 -0
  7. package/dist/config-schema-DFcjQw73.js +309 -0
  8. package/dist/exec-approvals-COUsM6wZ.js +138 -0
  9. package/dist/gateway-CmSUJKSt.js +6726 -0
  10. package/dist/handler-runtime-Bqm6N0WG.js +120 -0
  11. package/dist/index.js +29 -0
  12. package/dist/narrowing-BoieBTIU.js +25 -0
  13. package/dist/outbound-BJfhwrPg.js +1357 -0
  14. package/dist/request-context-DXtpwWui.js +921 -0
  15. package/dist/resolve-D_06fV6-.js +284 -0
  16. package/dist/runtime-BJAS3eXW.js +18 -0
  17. package/dist/runtime-api.js +2 -0
  18. package/dist/secret-contract-api.js +56 -0
  19. package/dist/sender-p-B14eLG.js +1987 -0
  20. package/dist/setup-entry.js +15 -0
  21. package/dist/setup-plugin-api.js +2 -0
  22. package/dist/string-normalize-Ci6NM5DE.js +98 -0
  23. package/dist/target-parser-Y0prnrXD.js +245 -0
  24. package/package.json +15 -6
  25. package/api.ts +0 -56
  26. package/channel-plugin-api.ts +0 -1
  27. package/index.ts +0 -29
  28. package/runtime-api.ts +0 -9
  29. package/setup-entry.ts +0 -9
  30. package/setup-plugin-api.ts +0 -3
  31. package/src/bridge/approval/capability.ts +0 -237
  32. package/src/bridge/approval/handler-runtime.ts +0 -204
  33. package/src/bridge/bootstrap.ts +0 -135
  34. package/src/bridge/channel-entry.ts +0 -18
  35. package/src/bridge/commands/framework-context-adapter.ts +0 -60
  36. package/src/bridge/commands/framework-registration.ts +0 -47
  37. package/src/bridge/commands/from-parser.test.ts +0 -86
  38. package/src/bridge/commands/from-parser.ts +0 -60
  39. package/src/bridge/commands/result-dispatcher.ts +0 -76
  40. package/src/bridge/config-shared.ts +0 -132
  41. package/src/bridge/config.ts +0 -111
  42. package/src/bridge/gateway.ts +0 -174
  43. package/src/bridge/logger.ts +0 -31
  44. package/src/bridge/narrowing.ts +0 -31
  45. package/src/bridge/plugin-version.test.ts +0 -146
  46. package/src/bridge/plugin-version.ts +0 -102
  47. package/src/bridge/runtime.ts +0 -25
  48. package/src/bridge/sdk-adapter.ts +0 -131
  49. package/src/bridge/setup/finalize.ts +0 -144
  50. package/src/bridge/setup/surface.ts +0 -34
  51. package/src/bridge/tools/channel.ts +0 -58
  52. package/src/bridge/tools/index.ts +0 -15
  53. package/src/bridge/tools/remind.test.ts +0 -124
  54. package/src/bridge/tools/remind.ts +0 -91
  55. package/src/channel.setup.ts +0 -33
  56. package/src/channel.ts +0 -288
  57. package/src/command-auth.test.ts +0 -62
  58. package/src/config-schema.ts +0 -84
  59. package/src/config.test.ts +0 -364
  60. package/src/engine/access/access-control.test.ts +0 -198
  61. package/src/engine/access/access-control.ts +0 -226
  62. package/src/engine/access/index.ts +0 -16
  63. package/src/engine/access/resolve-policy.test.ts +0 -59
  64. package/src/engine/access/resolve-policy.ts +0 -57
  65. package/src/engine/access/sender-match.test.ts +0 -60
  66. package/src/engine/access/sender-match.ts +0 -55
  67. package/src/engine/access/types.ts +0 -53
  68. package/src/engine/adapter/audio.port.ts +0 -27
  69. package/src/engine/adapter/commands.port.ts +0 -22
  70. package/src/engine/adapter/history.port.ts +0 -52
  71. package/src/engine/adapter/index.ts +0 -139
  72. package/src/engine/adapter/mention-gate.port.ts +0 -50
  73. package/src/engine/adapter/types.ts +0 -38
  74. package/src/engine/api/api-client.ts +0 -212
  75. package/src/engine/api/media-chunked.test.ts +0 -336
  76. package/src/engine/api/media-chunked.ts +0 -622
  77. package/src/engine/api/media.ts +0 -218
  78. package/src/engine/api/messages.ts +0 -293
  79. package/src/engine/api/retry.ts +0 -217
  80. package/src/engine/api/routes.ts +0 -95
  81. package/src/engine/api/token.ts +0 -271
  82. package/src/engine/approval/index.test.ts +0 -22
  83. package/src/engine/approval/index.ts +0 -224
  84. package/src/engine/commands/builtin/log-helpers.ts +0 -319
  85. package/src/engine/commands/builtin/register-all.ts +0 -17
  86. package/src/engine/commands/builtin/register-approve.ts +0 -201
  87. package/src/engine/commands/builtin/register-basic.ts +0 -95
  88. package/src/engine/commands/builtin/register-clear-storage.ts +0 -187
  89. package/src/engine/commands/builtin/register-logs.ts +0 -20
  90. package/src/engine/commands/builtin/register-streaming.ts +0 -137
  91. package/src/engine/commands/builtin/state.ts +0 -31
  92. package/src/engine/commands/slash-command-auth.ts +0 -48
  93. package/src/engine/commands/slash-command-handler.ts +0 -146
  94. package/src/engine/commands/slash-commands-impl.test.ts +0 -8
  95. package/src/engine/commands/slash-commands-impl.ts +0 -61
  96. package/src/engine/commands/slash-commands.ts +0 -199
  97. package/src/engine/config/credential-backup.test.ts +0 -88
  98. package/src/engine/config/credential-backup.ts +0 -107
  99. package/src/engine/config/credentials.ts +0 -76
  100. package/src/engine/config/group.test.ts +0 -234
  101. package/src/engine/config/group.ts +0 -299
  102. package/src/engine/config/resolve.test.ts +0 -152
  103. package/src/engine/config/resolve.ts +0 -283
  104. package/src/engine/config/setup-logic.ts +0 -84
  105. package/src/engine/engine-import-boundary.test.ts +0 -73
  106. package/src/engine/gateway/codec.ts +0 -47
  107. package/src/engine/gateway/constants.ts +0 -117
  108. package/src/engine/gateway/event-dispatcher.ts +0 -177
  109. package/src/engine/gateway/gateway-connection.ts +0 -371
  110. package/src/engine/gateway/gateway.ts +0 -291
  111. package/src/engine/gateway/inbound-attachments.test.ts +0 -126
  112. package/src/engine/gateway/inbound-attachments.ts +0 -360
  113. package/src/engine/gateway/inbound-context.ts +0 -195
  114. package/src/engine/gateway/inbound-pipeline.self-echo.test.ts +0 -218
  115. package/src/engine/gateway/inbound-pipeline.ts +0 -235
  116. package/src/engine/gateway/interaction-handler.ts +0 -220
  117. package/src/engine/gateway/message-queue.test.ts +0 -282
  118. package/src/engine/gateway/message-queue.ts +0 -499
  119. package/src/engine/gateway/outbound-dispatch.test.ts +0 -231
  120. package/src/engine/gateway/outbound-dispatch.ts +0 -575
  121. package/src/engine/gateway/reconnect.ts +0 -199
  122. package/src/engine/gateway/stages/access-stage.ts +0 -132
  123. package/src/engine/gateway/stages/assembly-stage.ts +0 -156
  124. package/src/engine/gateway/stages/content-stage.test.ts +0 -77
  125. package/src/engine/gateway/stages/content-stage.ts +0 -77
  126. package/src/engine/gateway/stages/envelope-stage.test.ts +0 -152
  127. package/src/engine/gateway/stages/envelope-stage.ts +0 -144
  128. package/src/engine/gateway/stages/group-gate-stage.ts +0 -292
  129. package/src/engine/gateway/stages/index.ts +0 -18
  130. package/src/engine/gateway/stages/quote-stage.ts +0 -113
  131. package/src/engine/gateway/stages/refidx-stage.ts +0 -62
  132. package/src/engine/gateway/stages/stub-contexts.ts +0 -116
  133. package/src/engine/gateway/types.ts +0 -264
  134. package/src/engine/gateway/typing-keepalive.ts +0 -79
  135. package/src/engine/group/activation.test.ts +0 -114
  136. package/src/engine/group/activation.ts +0 -147
  137. package/src/engine/group/history.test.ts +0 -314
  138. package/src/engine/group/history.ts +0 -321
  139. package/src/engine/group/mention.test.ts +0 -141
  140. package/src/engine/group/mention.ts +0 -197
  141. package/src/engine/group/message-gating.test.ts +0 -188
  142. package/src/engine/group/message-gating.ts +0 -216
  143. package/src/engine/messaging/decode-media-path.ts +0 -82
  144. package/src/engine/messaging/media-source.ts +0 -215
  145. package/src/engine/messaging/media-type-detect.ts +0 -37
  146. package/src/engine/messaging/outbound-audio-port.ts +0 -38
  147. package/src/engine/messaging/outbound-deliver.ts +0 -810
  148. package/src/engine/messaging/outbound-media-send.ts +0 -702
  149. package/src/engine/messaging/outbound-reply.ts +0 -27
  150. package/src/engine/messaging/outbound-result-helpers.ts +0 -54
  151. package/src/engine/messaging/outbound-types.ts +0 -45
  152. package/src/engine/messaging/outbound.ts +0 -485
  153. package/src/engine/messaging/reply-dispatcher.ts +0 -597
  154. package/src/engine/messaging/reply-limiter.ts +0 -164
  155. package/src/engine/messaging/sender.ts +0 -729
  156. package/src/engine/messaging/streaming-c2c.ts +0 -1192
  157. package/src/engine/messaging/streaming-media-send.ts +0 -544
  158. package/src/engine/messaging/target-parser.ts +0 -104
  159. package/src/engine/ref/format-message-ref.ts +0 -142
  160. package/src/engine/ref/format-ref-entry.test.ts +0 -60
  161. package/src/engine/ref/format-ref-entry.ts +0 -27
  162. package/src/engine/ref/store.ts +0 -208
  163. package/src/engine/ref/types.ts +0 -27
  164. package/src/engine/session/known-users.ts +0 -137
  165. package/src/engine/session/session-store.ts +0 -204
  166. package/src/engine/tools/channel-api.ts +0 -244
  167. package/src/engine/tools/remind-logic.test.ts +0 -280
  168. package/src/engine/tools/remind-logic.ts +0 -377
  169. package/src/engine/types.ts +0 -313
  170. package/src/engine/utils/attachment-tags.test.ts +0 -186
  171. package/src/engine/utils/attachment-tags.ts +0 -174
  172. package/src/engine/utils/audio.test.ts +0 -250
  173. package/src/engine/utils/audio.ts +0 -585
  174. package/src/engine/utils/data-paths.ts +0 -38
  175. package/src/engine/utils/diagnostics.ts +0 -109
  176. package/src/engine/utils/file-utils.test.ts +0 -72
  177. package/src/engine/utils/file-utils.ts +0 -225
  178. package/src/engine/utils/format.test.ts +0 -68
  179. package/src/engine/utils/format.ts +0 -70
  180. package/src/engine/utils/image-size.test.ts +0 -158
  181. package/src/engine/utils/image-size.ts +0 -249
  182. package/src/engine/utils/log.test.ts +0 -28
  183. package/src/engine/utils/log.ts +0 -61
  184. package/src/engine/utils/media-tags.test.ts +0 -32
  185. package/src/engine/utils/media-tags.ts +0 -177
  186. package/src/engine/utils/payload.test.ts +0 -68
  187. package/src/engine/utils/payload.ts +0 -145
  188. package/src/engine/utils/platform-storage-laziness.test.ts +0 -63
  189. package/src/engine/utils/platform.test.ts +0 -148
  190. package/src/engine/utils/platform.ts +0 -343
  191. package/src/engine/utils/request-context.ts +0 -60
  192. package/src/engine/utils/string-normalize.ts +0 -91
  193. package/src/engine/utils/stt.test.ts +0 -104
  194. package/src/engine/utils/stt.ts +0 -100
  195. package/src/engine/utils/text-parsing.test.ts +0 -29
  196. package/src/engine/utils/text-parsing.ts +0 -155
  197. package/src/engine/utils/upload-cache.ts +0 -96
  198. package/src/engine/utils/voice-text.ts +0 -15
  199. package/src/exec-approvals.ts +0 -218
  200. package/src/manifest-schema.test.ts +0 -56
  201. package/src/qqbot-test-support.ts +0 -29
  202. package/src/types.ts +0 -210
  203. package/tsconfig.json +0 -16
@@ -1,113 +0,0 @@
1
- /**
2
- * Quote stage — resolve the quoted-reply (`refMsgIdx`) if any.
3
- *
4
- * Three-level fallback mirrors the standalone build:
5
- * 1. RefIndex cache hit → rich ReplyToInfo
6
- * 2. `msg_elements[0]` present → re-process the quoted body
7
- * 3. Otherwise → id-only placeholder so the pipeline still knows it's a reply
8
- */
9
-
10
- import {
11
- formatMessageReferenceForAgent,
12
- type AttachmentProcessor,
13
- } from "../../ref/format-message-ref.js";
14
- import { formatRefEntryForAgent, getRefIndex } from "../../ref/store.js";
15
- import { MSG_TYPE_QUOTE } from "../../utils/text-parsing.js";
16
- import { formatVoiceText } from "../../utils/voice-text.js";
17
- import { processAttachments } from "../inbound-attachments.js";
18
- import type { InboundPipelineDeps, ReplyToInfo } from "../inbound-context.js";
19
- import type { QueuedMessage } from "../message-queue.js";
20
-
21
- /**
22
- * Resolve the quote metadata for an inbound event.
23
- *
24
- * Returns `undefined` when the event is not a reply at all.
25
- */
26
- export async function resolveQuote(
27
- event: QueuedMessage,
28
- deps: InboundPipelineDeps,
29
- ): Promise<ReplyToInfo | undefined> {
30
- if (!event.refMsgIdx) {
31
- return undefined;
32
- }
33
-
34
- const { account, log } = deps;
35
-
36
- // ---- Layer 1: cache hit ----
37
- const refEntry = getRefIndex(event.refMsgIdx);
38
- if (refEntry) {
39
- log?.debug?.(
40
- `Quote detected via refMsgIdx cache: refMsgIdx=${event.refMsgIdx}, sender=${refEntry.senderName ?? refEntry.senderId}`,
41
- );
42
- return {
43
- id: event.refMsgIdx,
44
- body: formatRefEntryForAgent(refEntry),
45
- sender: refEntry.senderName ?? refEntry.senderId,
46
- isQuote: true,
47
- };
48
- }
49
-
50
- // ---- Layer 2: fall back to msg_elements[0] if this is a quote type ----
51
- if (event.msgType === MSG_TYPE_QUOTE && event.msgElements?.[0]) {
52
- try {
53
- const refElement = event.msgElements[0];
54
- const refData = {
55
- content: refElement.content ?? "",
56
- attachments: refElement.attachments,
57
- };
58
- const attachmentProcessor: AttachmentProcessor = {
59
- processAttachments: async (atts, refCtx) => {
60
- const result = await processAttachments(
61
- atts as Array<{
62
- content_type: string;
63
- url: string;
64
- filename?: string;
65
- voice_wav_url?: string;
66
- asr_refer_text?: string;
67
- }>,
68
- {
69
- accountId: account.accountId,
70
- cfg: refCtx.cfg,
71
- audioConvert: deps.adapters.audioConvert,
72
- log: refCtx.log,
73
- },
74
- );
75
- return {
76
- attachmentInfo: result.attachmentInfo,
77
- voiceTranscripts: result.voiceTranscripts,
78
- voiceTranscriptSources: result.voiceTranscriptSources,
79
- attachmentLocalPaths: result.attachmentLocalPaths,
80
- };
81
- },
82
- formatVoiceText: (transcripts) => formatVoiceText(transcripts),
83
- };
84
- const refPeerId =
85
- event.type === "group" && event.groupOpenid ? event.groupOpenid : event.senderId;
86
- const refBody = await formatMessageReferenceForAgent(
87
- refData,
88
- { appId: account.appId, peerId: refPeerId, cfg: account.config, log },
89
- attachmentProcessor,
90
- );
91
- log?.debug?.(
92
- `Quote detected via msg_elements[0] (cache miss): id=${event.refMsgIdx}, content="${(refBody ?? "").slice(0, 80)}..."`,
93
- );
94
- return {
95
- id: event.refMsgIdx,
96
- body: refBody || undefined,
97
- isQuote: true,
98
- };
99
- } catch (refErr) {
100
- log?.error(`Failed to format quoted message from msg_elements: ${String(refErr)}`);
101
- }
102
- } else {
103
- log?.debug?.(
104
- `Quote detected but no cache and msgType=${event.msgType}: refMsgIdx=${event.refMsgIdx}`,
105
- );
106
- }
107
-
108
- // ---- Layer 3: id-only placeholder ----
109
- return {
110
- id: event.refMsgIdx,
111
- isQuote: true,
112
- };
113
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * RefIdx persistence stage — writes the current message into the shared
3
- * `refIndex` cache so future quote resolutions can find it.
4
- *
5
- * The stage also attaches voice transcripts (and their source) onto the
6
- * cached attachment summaries so replies-to-this-message can render the
7
- * original audio content inline instead of just a file handle.
8
- *
9
- * Pure data pipeline (no network I/O). Sync return value.
10
- */
11
-
12
- import { setRefIndex } from "../../ref/store.js";
13
- import { buildAttachmentSummaries } from "../../utils/text-parsing.js";
14
- import type { ProcessedAttachments } from "../inbound-attachments.js";
15
- import type { QueuedMessage } from "../message-queue.js";
16
-
17
- /**
18
- * Cache the current message under `msgIdx` (or the fallback `refIdx`
19
- * returned by the typing-indicator call) so later quotes resolve.
20
- *
21
- * No-op when neither id is available.
22
- */
23
- export function writeRefIndex(params: {
24
- event: QueuedMessage;
25
- parsedContent: string;
26
- processed: ProcessedAttachments;
27
- /** Optional refIdx returned by `InputNotify` — used when `msgIdx` is missing. */
28
- inputNotifyRefIdx?: string;
29
- }): void {
30
- const { event, parsedContent, processed, inputNotifyRefIdx } = params;
31
-
32
- const currentMsgIdx = event.msgIdx ?? inputNotifyRefIdx;
33
- if (!currentMsgIdx) {
34
- return;
35
- }
36
-
37
- const attSummaries = buildAttachmentSummaries(event.attachments, processed.attachmentLocalPaths);
38
- if (attSummaries && processed.voiceTranscripts.length > 0) {
39
- let voiceIdx = 0;
40
- for (const att of attSummaries) {
41
- if (att.type === "voice" && voiceIdx < processed.voiceTranscripts.length) {
42
- att.transcript = processed.voiceTranscripts[voiceIdx];
43
- if (voiceIdx < processed.voiceTranscriptSources.length) {
44
- att.transcriptSource = processed.voiceTranscriptSources[voiceIdx] as
45
- | "stt"
46
- | "asr"
47
- | "tts"
48
- | "fallback";
49
- }
50
- voiceIdx++;
51
- }
52
- }
53
- }
54
-
55
- setRefIndex(currentMsgIdx, {
56
- content: parsedContent,
57
- senderId: event.senderId,
58
- senderName: event.senderName,
59
- timestamp: new Date(event.timestamp).getTime(),
60
- attachments: attSummaries,
61
- });
62
- }
@@ -1,116 +0,0 @@
1
- /**
2
- * Shared `InboundContext` stub builders for early-return paths.
3
- *
4
- * Both the access-control "blocked" path and the group-gate "skipped"
5
- * path need to return a fully populated {@link InboundContext} that the
6
- * upstream handler can inspect without crashing on undefined fields.
7
- * Centralising the stubs here prevents the two paths from drifting.
8
- */
9
-
10
- import type { QQBotAccessResult } from "../../access/index.js";
11
- import type { InboundContext, InboundGroupInfo } from "../inbound-context.js";
12
- import type { QueuedMessage } from "../message-queue.js";
13
- import type { TypingKeepAlive } from "../typing-keepalive.js";
14
-
15
- /** Shared fields every stub context needs. */
16
- interface BaseStubFields {
17
- event: QueuedMessage;
18
- route: { sessionKey: string; accountId: string; agentId?: string };
19
- isGroupChat: boolean;
20
- peerId: string;
21
- qualifiedTarget: string;
22
- fromAddress: string;
23
- }
24
-
25
- /** Build an {@link InboundContext} with all non-routing fields cleared. */
26
- function emptyInboundContext(fields: BaseStubFields): InboundContext {
27
- return {
28
- event: fields.event,
29
- route: fields.route,
30
- isGroupChat: fields.isGroupChat,
31
- peerId: fields.peerId,
32
- qualifiedTarget: fields.qualifiedTarget,
33
- fromAddress: fields.fromAddress,
34
- parsedContent: "",
35
- userContent: "",
36
- quotePart: "",
37
- dynamicCtx: "",
38
- userMessage: "",
39
- agentBody: "",
40
- body: "",
41
- systemPrompts: [],
42
- groupSystemPrompt: undefined,
43
- attachments: {
44
- attachmentInfo: "",
45
- imageUrls: [],
46
- imageMediaTypes: [],
47
- voiceAttachmentPaths: [],
48
- voiceAttachmentUrls: [],
49
- voiceAsrReferTexts: [],
50
- voiceTranscripts: [],
51
- voiceTranscriptSources: [],
52
- attachmentLocalPaths: [],
53
- },
54
- localMediaPaths: [],
55
- localMediaTypes: [],
56
- remoteMediaUrls: [],
57
- remoteMediaTypes: [],
58
- uniqueVoicePaths: [],
59
- uniqueVoiceUrls: [],
60
- uniqueVoiceAsrReferTexts: [],
61
- voiceMediaTypes: [],
62
- hasAsrReferFallback: false,
63
- voiceTranscriptSources: [],
64
- replyTo: undefined,
65
- commandAuthorized: false,
66
- group: undefined,
67
- blocked: false,
68
- skipped: false,
69
- typing: { keepAlive: null },
70
- inputNotifyRefIdx: undefined,
71
- };
72
- }
73
-
74
- /**
75
- * Build an {@link InboundContext} that represents a message blocked by
76
- * access control (policy denial, allowlist mismatch, etc.).
77
- */
78
- export function buildBlockedInboundContext(
79
- params: BaseStubFields & {
80
- access: QQBotAccessResult;
81
- },
82
- ): InboundContext {
83
- return {
84
- ...emptyInboundContext(params),
85
- blocked: true,
86
- blockReason: params.access.reason,
87
- blockReasonCode: params.access.reasonCode,
88
- accessDecision: params.access.decision,
89
- };
90
- }
91
-
92
- /**
93
- * Build an {@link InboundContext} that represents a message stopped by
94
- * the group gate (drop_other_mention, block_unauthorized_command,
95
- * skip_no_mention). Any history side-effects have already been applied
96
- * by the gate stage.
97
- */
98
- export function buildSkippedInboundContext(
99
- params: BaseStubFields & {
100
- group: InboundGroupInfo;
101
- skipReason: NonNullable<InboundContext["skipReason"]>;
102
- access: QQBotAccessResult;
103
- typing: { keepAlive: TypingKeepAlive | null };
104
- inputNotifyRefIdx?: string;
105
- },
106
- ): InboundContext {
107
- return {
108
- ...emptyInboundContext(params),
109
- group: params.group,
110
- skipped: true,
111
- skipReason: params.skipReason,
112
- accessDecision: params.access.decision,
113
- typing: params.typing,
114
- inputNotifyRefIdx: params.inputNotifyRefIdx,
115
- };
116
- }
@@ -1,264 +0,0 @@
1
- /**
2
- * Gateway types.
3
- *
4
- * core/gateway/gateway.ts now imports all dependencies directly (both
5
- * core/ modules and upper-layer files). The only injected dependency
6
- * is `runtime` (PluginRuntime), which is a framework-provided object.
7
- */
8
-
9
- // ============ Logger ============
10
- import type { EngineLogger } from "../types.js";
11
- export type { EngineLogger };
12
-
13
- // ============ Account ============
14
-
15
- /** Re-export GatewayAccount from engine/types.ts (single source of truth). */
16
- import type { GatewayAccount as _GatewayAccount } from "../types.js";
17
- export type GatewayAccount = _GatewayAccount;
18
-
19
- // ============ PluginRuntime subset ============
20
-
21
- /**
22
- * Subset of PluginRuntime used by the gateway.
23
- *
24
- * This is NOT a custom adapter — it's the exact same object shape that
25
- * the framework injects. We define it here so core/ doesn't need to
26
- * depend on the plugin-sdk root barrel.
27
- */
28
- export interface GatewayPluginRuntime {
29
- channel: {
30
- activity: {
31
- record: (params: {
32
- channel: string;
33
- accountId: string;
34
- direction: "inbound" | "outbound";
35
- }) => void;
36
- };
37
- routing: {
38
- resolveAgentRoute: (params: {
39
- cfg: unknown;
40
- channel: string;
41
- accountId: string;
42
- peer: { kind: "group" | "direct"; id: string };
43
- }) => { sessionKey: string; accountId: string; agentId?: string };
44
- };
45
- reply: {
46
- dispatchReplyWithBufferedBlockDispatcher: (params: unknown) => Promise<unknown>;
47
- resolveEffectiveMessagesConfig: (
48
- cfg: unknown,
49
- agentId?: string,
50
- ) => { responsePrefix?: string };
51
- finalizeInboundContext: (fields: Record<string, unknown>) => unknown;
52
- formatInboundEnvelope: (params: unknown) => string;
53
- resolveEnvelopeFormatOptions: (cfg: unknown) => unknown;
54
- };
55
- session: {
56
- resolveStorePath: (store: unknown, params: { agentId: string }) => string;
57
- recordInboundSession: (params: unknown) => Promise<unknown>;
58
- };
59
- turn: {
60
- run: (params: unknown) => Promise<unknown>;
61
- };
62
- text: {
63
- chunkMarkdownText: (text: string, limit: number) => string[];
64
- };
65
- };
66
- tts: {
67
- textToSpeech: (params: {
68
- text: string;
69
- cfg: unknown;
70
- channel: string;
71
- accountId?: string;
72
- }) => Promise<{
73
- success: boolean;
74
- audioPath?: string;
75
- provider?: string;
76
- outputFormat?: string;
77
- error?: string;
78
- }>;
79
- };
80
- /**
81
- * Config API for reading/writing the framework configuration.
82
- *
83
- * Used by the interaction handler (config query/update) directly
84
- * within the engine layer. Optional because not all runtime
85
- * environments provide config write capability.
86
- */
87
- config?: {
88
- current: () => Record<string, unknown>;
89
- replaceConfigFile: (params: {
90
- nextConfig: unknown;
91
- afterWrite: { mode: "auto" };
92
- }) => Promise<unknown>;
93
- };
94
- }
95
-
96
- // ============ Shared result types ============
97
-
98
- /** Re-export ProcessedAttachments from inbound-attachments (single source of truth). */
99
- export type { ProcessedAttachments } from "./inbound-attachments.js";
100
-
101
- /** Outbound result from media sends. */
102
- export interface OutboundResult {
103
- channel: string;
104
- messageId?: string;
105
- timestamp?: string | number;
106
- error?: string;
107
- }
108
-
109
- /** Re-export RefAttachmentSummary for convenience. */
110
- export type { RefAttachmentSummary } from "../ref/types.js";
111
-
112
- // ============ WebSocket Event Types ============
113
-
114
- /** Raw WebSocket payload structure. */
115
- export interface WSPayload {
116
- op: number;
117
- d: unknown;
118
- s?: number;
119
- t?: string;
120
- }
121
-
122
- /** Attachment shape shared by all message event types. */
123
- interface RawMessageAttachment {
124
- content_type: string;
125
- url: string;
126
- filename?: string;
127
- voice_wav_url?: string;
128
- asr_refer_text?: string;
129
- }
130
-
131
- /** Referenced message element (used for quote messages). */
132
- interface RawMsgElement {
133
- msg_idx?: string;
134
- content?: string;
135
- attachments?: Array<
136
- RawMessageAttachment & {
137
- height?: number;
138
- width?: number;
139
- size?: number;
140
- }
141
- >;
142
- }
143
-
144
- export interface C2CMessageEvent {
145
- id: string;
146
- content: string;
147
- timestamp: string;
148
- author: { user_openid: string };
149
- attachments?: RawMessageAttachment[];
150
- message_scene?: { ext?: string[] };
151
- message_type?: number;
152
- msg_elements?: RawMsgElement[];
153
- }
154
-
155
- export interface GuildMessageEvent {
156
- id: string;
157
- content: string;
158
- timestamp: string;
159
- author: { id: string; username?: string };
160
- channel_id: string;
161
- guild_id: string;
162
- attachments?: RawMessageAttachment[];
163
- message_scene?: { ext?: string[] };
164
- }
165
-
166
- export interface GroupMessageEvent {
167
- id: string;
168
- content: string;
169
- timestamp: string;
170
- author: {
171
- member_openid: string;
172
- username?: string;
173
- /** True when the sender is itself a bot. */
174
- bot?: boolean;
175
- };
176
- group_openid: string;
177
- attachments?: RawMessageAttachment[];
178
- /** Optional @mentions list with per-entry is_you / member_openid / nickname. */
179
- mentions?: Array<{
180
- scope?: "all" | "single";
181
- id?: string;
182
- user_openid?: string;
183
- member_openid?: string;
184
- nickname?: string;
185
- username?: string;
186
- bot?: boolean;
187
- /** `true` when this mention targets the bot itself. */
188
- is_you?: boolean;
189
- }>;
190
- message_scene?: { source?: string; ext?: string[] };
191
- message_type?: number;
192
- msg_elements?: RawMsgElement[];
193
- }
194
-
195
- // ============ Gateway Context ============
196
-
197
- import type { EngineAdapters } from "../adapter/index.js";
198
-
199
- /**
200
- * Group-chat behaviour options.
201
- *
202
- * Grouped under a dedicated sub-object on {@link CoreGatewayContext} so
203
- * future additions (admin lookup, proactive push, per-group toggles)
204
- * don't keep polluting the top-level context type.
205
- */
206
- interface GatewayGroupOptions {
207
- /**
208
- * Whether group-chat gating is enabled. Defaults to `true`; set to
209
- * `false` to disable all group processing (e.g. for a DM-only smoke
210
- * test). When disabled, the engine does not allocate a history
211
- * buffer and does not instantiate the session-store reader.
212
- */
213
- enabled?: boolean;
214
- /**
215
- * Whether the framework has text-based control commands enabled. When
216
- * `false`, the group gate skips the "unauthorized command" check and
217
- * the command-bypass path.
218
- */
219
- allowTextCommands?: boolean;
220
- /**
221
- * Optional probe that returns true when `content` is a recognised
222
- * control command. Injected to avoid hard-coding a command list in
223
- * the engine. When omitted, no message is treated as a control
224
- * command and the bypass path never activates.
225
- */
226
- isControlCommand?: (content: string) => boolean;
227
- /**
228
- * Platform hook that contributes a channel-level group intro hint
229
- * (e.g. "当前群: 开发讨论组"). Invoked per-group when building the
230
- * system prompt.
231
- */
232
- resolveIntroHint?: (params: {
233
- cfg: unknown;
234
- accountId: string;
235
- groupId: string;
236
- }) => string | undefined;
237
- /**
238
- * Session-store reader for the `/activation` command override. When
239
- * omitted, the engine loads a default node-based reader lazily.
240
- */
241
- sessionStoreReader?: import("../group/activation.js").SessionStoreReader;
242
- }
243
-
244
- /** Full gateway startup context. */
245
- export interface CoreGatewayContext {
246
- account: GatewayAccount;
247
- abortSignal: AbortSignal;
248
- cfg: unknown;
249
- onReady?: (data: unknown) => void;
250
- /**
251
- * Invoked when a RESUMED event is received after reconnect.
252
- * Falls back to `onReady` when not provided so existing callers
253
- * keep their current behaviour.
254
- */
255
- onResumed?: (data: unknown) => void;
256
- onError?: (error: Error) => void;
257
- log?: EngineLogger;
258
- /** PluginRuntime injected by the framework — same object in both versions. */
259
- runtime: GatewayPluginRuntime;
260
- /** Group-chat tuning options. */
261
- group?: GatewayGroupOptions;
262
- /** Adapter ports — delegates audio, history, mention gating, commands to bridge implementations. */
263
- adapters: EngineAdapters;
264
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * Periodically refresh C2C typing state while a response is in progress.
3
- *
4
- * All I/O operations are injected via constructor parameters so this
5
- * module has zero external dependencies and can run in both plugin versions.
6
- */
7
-
8
- import { formatErrorMessage } from "../utils/format.js";
9
-
10
- /** Function that sends a typing indicator to one user. */
11
- type SendInputNotifyFn = (
12
- token: string,
13
- openid: string,
14
- msgId: string | undefined,
15
- inputSecond: number,
16
- ) => Promise<unknown>;
17
-
18
- /** Refresh every 50s for the QQ API's 60s input-notify window. */
19
- const TYPING_INTERVAL_MS = 50_000;
20
- export const TYPING_INPUT_SECOND = 60;
21
-
22
- export class TypingKeepAlive {
23
- private timer: ReturnType<typeof setInterval> | null = null;
24
- private stopped = false;
25
-
26
- constructor(
27
- private readonly getToken: () => Promise<string>,
28
- private readonly clearCache: () => void,
29
- private readonly sendInputNotify: SendInputNotifyFn,
30
- private readonly openid: string,
31
- private readonly msgId: string | undefined,
32
- private readonly log?: {
33
- info: (msg: string) => void;
34
- error: (msg: string) => void;
35
- debug?: (msg: string) => void;
36
- },
37
- ) {}
38
-
39
- /** Start periodic keep-alive sends. */
40
- start(): void {
41
- if (this.stopped) {
42
- return;
43
- }
44
- this.timer = setInterval(() => {
45
- if (this.stopped) {
46
- this.stop();
47
- return;
48
- }
49
- this.send().catch(() => {});
50
- }, TYPING_INTERVAL_MS);
51
- }
52
-
53
- /** Stop periodic keep-alive sends. */
54
- stop(): void {
55
- this.stopped = true;
56
- if (this.timer) {
57
- clearInterval(this.timer);
58
- this.timer = null;
59
- }
60
- }
61
-
62
- private async send(): Promise<void> {
63
- try {
64
- const token = await this.getToken();
65
- await this.sendInputNotify(token, this.openid, this.msgId, TYPING_INPUT_SECOND);
66
- this.log?.debug?.(`Typing keep-alive sent to ${this.openid}`);
67
- } catch (err) {
68
- try {
69
- this.clearCache();
70
- const token = await this.getToken();
71
- await this.sendInputNotify(token, this.openid, this.msgId, TYPING_INPUT_SECOND);
72
- } catch {
73
- this.log?.debug?.(
74
- `Typing keep-alive failed for ${this.openid}: ${formatErrorMessage(err)}`,
75
- );
76
- }
77
- }
78
- }
79
- }