@qwen-code/channel-base 0.19.3 → 0.19.4
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.
- package/README.md +111 -35
- package/dist/AcpBridge.d.ts +10 -16
- package/dist/AcpBridge.js +30 -1
- package/dist/AcpBridge.js.map +1 -1
- package/dist/ChannelAgentBridge.d.ts +48 -0
- package/dist/ChannelAgentBridge.js +2 -0
- package/dist/ChannelAgentBridge.js.map +1 -0
- package/dist/ChannelBase.d.ts +157 -6
- package/dist/ChannelBase.js +1372 -51
- package/dist/ChannelBase.js.map +1 -1
- package/dist/ChannelLoopScheduler.d.ts +44 -0
- package/dist/ChannelLoopScheduler.js +275 -0
- package/dist/ChannelLoopScheduler.js.map +1 -0
- package/dist/ChannelLoopStore.d.ts +47 -0
- package/dist/ChannelLoopStore.js +195 -0
- package/dist/ChannelLoopStore.js.map +1 -0
- package/dist/DaemonChannelBridge.d.ts +2 -2
- package/dist/DaemonChannelBridge.js +16 -2
- package/dist/DaemonChannelBridge.js.map +1 -1
- package/dist/SenderGate.d.ts +1 -0
- package/dist/SenderGate.js +13 -0
- package/dist/SenderGate.js.map +1 -1
- package/dist/SessionRouter.d.ts +14 -13
- package/dist/SessionRouter.js +202 -48
- package/dist/SessionRouter.js.map +1 -1
- package/dist/group-history-store.d.ts +26 -0
- package/dist/group-history-store.js +242 -0
- package/dist/group-history-store.js.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/sanitize.d.ts +60 -0
- package/dist/sanitize.js +117 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/types.d.ts +30 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
export { getGlobalQwenDir, resolvePath } from './paths.js';
|
|
2
2
|
export { AcpBridge } from './AcpBridge.js';
|
|
3
|
-
export type {
|
|
3
|
+
export type { AvailableCommand, ChannelAgentBridge, SessionDiedEvent, ToolCallEvent, } from './ChannelAgentBridge.js';
|
|
4
|
+
export type { AcpBridgeOptions } from './AcpBridge.js';
|
|
4
5
|
export { DaemonChannelBridge } from './DaemonChannelBridge.js';
|
|
5
6
|
export type { DaemonChannelBridgeOptions, DaemonChannelEvent, DaemonChannelSessionClient, DaemonChannelSessionFactory, DaemonChannelSessionFactoryRequest, DaemonPromptCompleteEvent, DaemonPermissionRequestEvent, DaemonPermissionResolvedEvent, } from './DaemonChannelBridge.js';
|
|
6
7
|
export { BlockStreamer } from './BlockStreamer.js';
|
|
7
8
|
export type { BlockStreamerOptions } from './BlockStreamer.js';
|
|
8
9
|
export { ChannelBase } from './ChannelBase.js';
|
|
9
|
-
export type { ChannelBaseOptions } from './ChannelBase.js';
|
|
10
|
+
export type { ChannelBaseOptions, ChannelLoopController, } from './ChannelBase.js';
|
|
11
|
+
export { ChannelLoopScheduler } from './ChannelLoopScheduler.js';
|
|
12
|
+
export type { ChannelLoopSchedulerOptions, ChannelLoopRunner, } from './ChannelLoopScheduler.js';
|
|
13
|
+
export { ChannelLoopStore } from './ChannelLoopStore.js';
|
|
14
|
+
export type { ChannelLoop, ChannelLoopInput, ChannelLoopPatch, ChannelLoopStatus, ChannelLoopStoreOptions, } from './ChannelLoopStore.js';
|
|
10
15
|
export { PairingStore } from './PairingStore.js';
|
|
11
16
|
export type { PairingRequest } from './PairingStore.js';
|
|
12
17
|
export { GroupGate } from './GroupGate.js';
|
|
@@ -14,4 +19,5 @@ export type { GroupCheckResult } from './GroupGate.js';
|
|
|
14
19
|
export { SenderGate } from './SenderGate.js';
|
|
15
20
|
export type { SenderCheckResult } from './SenderGate.js';
|
|
16
21
|
export { SessionRouter } from './SessionRouter.js';
|
|
22
|
+
export { sanitizeSenderName, sanitizePromptText, sanitizeLogText, } from './sanitize.js';
|
|
17
23
|
export type { Attachment, BlockStreamingChunkConfig, BlockStreamingCoalesceConfig, ChannelConfig, ChannelPlugin, ChannelType, DispatchMode, Envelope, GroupConfig, GroupPolicy, SenderPolicy, SessionScope, SessionTarget, } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,11 @@ export { AcpBridge } from './AcpBridge.js';
|
|
|
3
3
|
export { DaemonChannelBridge } from './DaemonChannelBridge.js';
|
|
4
4
|
export { BlockStreamer } from './BlockStreamer.js';
|
|
5
5
|
export { ChannelBase } from './ChannelBase.js';
|
|
6
|
+
export { ChannelLoopScheduler } from './ChannelLoopScheduler.js';
|
|
7
|
+
export { ChannelLoopStore } from './ChannelLoopStore.js';
|
|
6
8
|
export { PairingStore } from './PairingStore.js';
|
|
7
9
|
export { GroupGate } from './GroupGate.js';
|
|
8
10
|
export { SenderGate } from './SenderGate.js';
|
|
9
11
|
export { SessionRouter } from './SessionRouter.js';
|
|
12
|
+
export { sanitizeSenderName, sanitizePromptText, sanitizeLogText, } from './sanitize.js';
|
|
10
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAQ3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAW/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAKjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAQzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,GAChB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Characters that must be neutralized in ANY attacker-controlled text we embed
|
|
3
|
+
* into a prompt, independent of the wrapper's own delimiters: the C1 control
|
|
4
|
+
* block (U+0080-U+009F) - notably NEL (U+0085), a Unicode line break (UAX#14 BK
|
|
5
|
+
* class) that renders as a new line, i.e. prompt-line injection - plus the
|
|
6
|
+
* Unicode line/paragraph separators (U+2028/U+2029, likewise rendered as
|
|
7
|
+
* newlines) and the bidirectional override/isolate controls (U+202A-U+202E,
|
|
8
|
+
* U+2066-U+2069 -> trojan-source, where the visual order differs from the
|
|
9
|
+
* logical byte order). Also strips common zero-width format chars that make
|
|
10
|
+
* visually identical names/text compare differently. ASCII C0/DEL (incl. CR/LF)
|
|
11
|
+
* are stripped by each caller.
|
|
12
|
+
*/
|
|
13
|
+
export declare const PROMPT_UNSAFE_INVISIBLES: RegExp;
|
|
14
|
+
/**
|
|
15
|
+
* Neutralize a platform display name before embedding it in a `[name]` prompt
|
|
16
|
+
* tag: strip the bracket/newline delimiters, C0/DEL control chars, and the
|
|
17
|
+
* Unicode line/bidi controls above that would let a crafted nickname break out
|
|
18
|
+
* of the tag, inject extra lines, or smuggle terminal escape sequences, then
|
|
19
|
+
* cap the length. Shared by ChannelBase group attribution and adapters that
|
|
20
|
+
* self-prefix (e.g. QQ), so the rules stay identical everywhere.
|
|
21
|
+
*/
|
|
22
|
+
export declare function sanitizeSenderName(name: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Neutralize attacker-controlled text embedded inside a `"..."` prompt wrapper
|
|
25
|
+
* (reply quotes, attachment filenames): strip C0/DEL control chars, the
|
|
26
|
+
* wrapper's own quote/bracket delimiters, and the Unicode line/bidi controls
|
|
27
|
+
* above, then cap the length. Shared so the reply-quote and filename paths
|
|
28
|
+
* can't drift apart. On truncation a single-char ellipsis is appended (kept
|
|
29
|
+
* within maxLen) so the agent can tell a quote/filename was cut rather than
|
|
30
|
+
* silently ending mid-token.
|
|
31
|
+
*/
|
|
32
|
+
export declare function sanitizeQuotedText(text: string, maxLen: number): string;
|
|
33
|
+
export declare function sanitizePromptText(text: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Neutralize an attacker-influenced filesystem path before rendering it on
|
|
36
|
+
* its own line in a prompt (`... saved to: <path>`). Unlike
|
|
37
|
+
* sanitizeQuotedText, this PRESERVES `[`, `]`, `"`, and spaces: those are
|
|
38
|
+
* valid, common path characters (e.g. Next.js `app/[slug]/page.tsx`, a
|
|
39
|
+
* quoted segment, a space in a folder name), and a path rendered alone on a
|
|
40
|
+
* line cannot use them to break out of that line, so stripping them would
|
|
41
|
+
* only corrupt the path and make the agent's read-file tool miss a file that
|
|
42
|
+
* exists on disk. We strip ONLY what can break or reorder the line: C0/DEL
|
|
43
|
+
* controls (incl. CR/LF -> prompt-line injection) and the Unicode line/para
|
|
44
|
+
* separators + bidi overrides (trojan-source). Length is capped generously
|
|
45
|
+
* (1024) as defense-in-depth: well beyond any real path, but enough to stop a
|
|
46
|
+
* pathological attacker filename from ballooning the prompt unboundedly.
|
|
47
|
+
*/
|
|
48
|
+
export declare function sanitizePromptPath(path: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Neutralize attacker-controlled text before it is written to a single-line
|
|
51
|
+
* stderr audit/diagnostic log. Caps to `maxLen` code points, renders ASCII
|
|
52
|
+
* newlines as a visible `\n` escape (so a multi-line payload stays one readable
|
|
53
|
+
* log line instead of collapsing to a space), then strips everything that could
|
|
54
|
+
* forge or corrupt a log line: PROMPT_UNSAFE_INVISIBLES (the C1 block incl. NEL
|
|
55
|
+
* U+0085, the Unicode line/paragraph separators U+2028/U+2029, and the bidi
|
|
56
|
+
* override/isolate controls — all of which render as a line break or reorder
|
|
57
|
+
* text) AND the C0/DEL controls (CR could overwrite the line, ESC could inject
|
|
58
|
+
* ANSI/OSC). Shared by every audit-log site so the strip set can't drift apart.
|
|
59
|
+
*/
|
|
60
|
+
export declare function sanitizeLogText(text: string, maxLen: number): string;
|
package/dist/sanitize.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Characters that must be neutralized in ANY attacker-controlled text we embed
|
|
3
|
+
* into a prompt, independent of the wrapper's own delimiters: the C1 control
|
|
4
|
+
* block (U+0080-U+009F) - notably NEL (U+0085), a Unicode line break (UAX#14 BK
|
|
5
|
+
* class) that renders as a new line, i.e. prompt-line injection - plus the
|
|
6
|
+
* Unicode line/paragraph separators (U+2028/U+2029, likewise rendered as
|
|
7
|
+
* newlines) and the bidirectional override/isolate controls (U+202A-U+202E,
|
|
8
|
+
* U+2066-U+2069 -> trojan-source, where the visual order differs from the
|
|
9
|
+
* logical byte order). Also strips common zero-width format chars that make
|
|
10
|
+
* visually identical names/text compare differently. ASCII C0/DEL (incl. CR/LF)
|
|
11
|
+
* are stripped by each caller.
|
|
12
|
+
*/
|
|
13
|
+
export const PROMPT_UNSAFE_INVISIBLES = /[\u0080-\u009f\u200b-\u200d\u2028\u2029\u202a-\u202e\u2060\u2066-\u2069\ufeff]/g;
|
|
14
|
+
/**
|
|
15
|
+
* Truncate to at most `max` Unicode CODE POINTS (not UTF-16 code units). A cap
|
|
16
|
+
* applied with `.slice` counts code units, so one landing mid-surrogate-pair
|
|
17
|
+
* (e.g. an emoji \ud83c\udf89 = 2 units) leaves a lone surrogate that renders as `\ufffd`.
|
|
18
|
+
* `Array.from` iterates by code point, so slicing it never splits a pair.
|
|
19
|
+
*/
|
|
20
|
+
function truncateCodePoints(str, max) {
|
|
21
|
+
const cp = Array.from(str);
|
|
22
|
+
return cp.length > max ? cp.slice(0, max).join('') : str;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Neutralize a platform display name before embedding it in a `[name]` prompt
|
|
26
|
+
* tag: strip the bracket/newline delimiters, C0/DEL control chars, and the
|
|
27
|
+
* Unicode line/bidi controls above that would let a crafted nickname break out
|
|
28
|
+
* of the tag, inject extra lines, or smuggle terminal escape sequences, then
|
|
29
|
+
* cap the length. Shared by ChannelBase group attribution and adapters that
|
|
30
|
+
* self-prefix (e.g. QQ), so the rules stay identical everywhere.
|
|
31
|
+
*/
|
|
32
|
+
export function sanitizeSenderName(name) {
|
|
33
|
+
// A name made entirely of strippable chars collapses to all-spaces; trim()-ing
|
|
34
|
+
// it to '' lets the `|| 'unknown'` fallback fire so the [name] tag is never an
|
|
35
|
+
// anonymous `[]`. Both callers embed the result with no fallback of their own.
|
|
36
|
+
const cleaned = name
|
|
37
|
+
.replace(PROMPT_UNSAFE_INVISIBLES, ' ')
|
|
38
|
+
// eslint-disable-next-line no-control-regex
|
|
39
|
+
.replace(/[\u0000-\u001f\u007f]/g, ' ')
|
|
40
|
+
.replace(/[[\]\r\n]/g, ' ');
|
|
41
|
+
// Truncate on code-point boundaries so an emoji nick capped mid-pair can't
|
|
42
|
+
// leave a lone surrogate (renders as `�`).
|
|
43
|
+
return truncateCodePoints(cleaned, 64).trim() || 'unknown';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Neutralize attacker-controlled text embedded inside a `"..."` prompt wrapper
|
|
47
|
+
* (reply quotes, attachment filenames): strip C0/DEL control chars, the
|
|
48
|
+
* wrapper's own quote/bracket delimiters, and the Unicode line/bidi controls
|
|
49
|
+
* above, then cap the length. Shared so the reply-quote and filename paths
|
|
50
|
+
* can't drift apart. On truncation a single-char ellipsis is appended (kept
|
|
51
|
+
* within maxLen) so the agent can tell a quote/filename was cut rather than
|
|
52
|
+
* silently ending mid-token.
|
|
53
|
+
*/
|
|
54
|
+
export function sanitizeQuotedText(text, maxLen) {
|
|
55
|
+
const cleaned = text
|
|
56
|
+
.replace(PROMPT_UNSAFE_INVISIBLES, ' ')
|
|
57
|
+
// eslint-disable-next-line no-control-regex
|
|
58
|
+
.replace(/[\u0000-\u001f\u007f]/g, ' ')
|
|
59
|
+
.replace(/["[\]]/g, ' ');
|
|
60
|
+
// Count/slice by CODE POINT, not UTF-16 unit, so a cap landing mid-surrogate-
|
|
61
|
+
// pair can't leave a lone surrogate (`�`). On truncation keep maxLen-1 code
|
|
62
|
+
// points + the single-char ellipsis, so the result stays within maxLen.
|
|
63
|
+
const cp = Array.from(cleaned);
|
|
64
|
+
return cp.length > maxLen ? cp.slice(0, maxLen - 1).join('') + '…' : cleaned;
|
|
65
|
+
}
|
|
66
|
+
export function sanitizePromptText(text) {
|
|
67
|
+
return (text
|
|
68
|
+
.replace(PROMPT_UNSAFE_INVISIBLES, ' ')
|
|
69
|
+
.replace(/^([ \t]*)\[([^\]\r\n]{1,64})\](:?)/gm, '$1$2$3')
|
|
70
|
+
// Fold ASCII C0/DEL, including CR/LF/TAB, so attacker-controlled group
|
|
71
|
+
// text cannot create prompt lines outside the adapter's sender attribution.
|
|
72
|
+
// eslint-disable-next-line no-control-regex
|
|
73
|
+
.replace(/[\u0000-\u001f\u007f]/g, ' '));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Neutralize an attacker-influenced filesystem path before rendering it on
|
|
77
|
+
* its own line in a prompt (`... saved to: <path>`). Unlike
|
|
78
|
+
* sanitizeQuotedText, this PRESERVES `[`, `]`, `"`, and spaces: those are
|
|
79
|
+
* valid, common path characters (e.g. Next.js `app/[slug]/page.tsx`, a
|
|
80
|
+
* quoted segment, a space in a folder name), and a path rendered alone on a
|
|
81
|
+
* line cannot use them to break out of that line, so stripping them would
|
|
82
|
+
* only corrupt the path and make the agent's read-file tool miss a file that
|
|
83
|
+
* exists on disk. We strip ONLY what can break or reorder the line: C0/DEL
|
|
84
|
+
* controls (incl. CR/LF -> prompt-line injection) and the Unicode line/para
|
|
85
|
+
* separators + bidi overrides (trojan-source). Length is capped generously
|
|
86
|
+
* (1024) as defense-in-depth: well beyond any real path, but enough to stop a
|
|
87
|
+
* pathological attacker filename from ballooning the prompt unboundedly.
|
|
88
|
+
*/
|
|
89
|
+
export function sanitizePromptPath(path) {
|
|
90
|
+
const cleaned = path
|
|
91
|
+
.replace(PROMPT_UNSAFE_INVISIBLES, ' ')
|
|
92
|
+
// eslint-disable-next-line no-control-regex
|
|
93
|
+
.replace(/[\u0000-\u001f\u007f]/g, ' ');
|
|
94
|
+
// Cap by code point so a path ending in an emoji can't be split mid-pair.
|
|
95
|
+
return truncateCodePoints(cleaned, 1024);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Neutralize attacker-controlled text before it is written to a single-line
|
|
99
|
+
* stderr audit/diagnostic log. Caps to `maxLen` code points, renders ASCII
|
|
100
|
+
* newlines as a visible `\n` escape (so a multi-line payload stays one readable
|
|
101
|
+
* log line instead of collapsing to a space), then strips everything that could
|
|
102
|
+
* forge or corrupt a log line: PROMPT_UNSAFE_INVISIBLES (the C1 block incl. NEL
|
|
103
|
+
* U+0085, the Unicode line/paragraph separators U+2028/U+2029, and the bidi
|
|
104
|
+
* override/isolate controls — all of which render as a line break or reorder
|
|
105
|
+
* text) AND the C0/DEL controls (CR could overwrite the line, ESC could inject
|
|
106
|
+
* ANSI/OSC). Shared by every audit-log site so the strip set can't drift apart.
|
|
107
|
+
*/
|
|
108
|
+
export function sanitizeLogText(text, maxLen) {
|
|
109
|
+
return (truncateCodePoints(text, maxLen)
|
|
110
|
+
// Render real newlines visibly BEFORE the control strip, so the common
|
|
111
|
+
// ASCII-newline case shows as `\n` rather than collapsing to a space.
|
|
112
|
+
.replace(/\n/g, '\\n')
|
|
113
|
+
.replace(PROMPT_UNSAFE_INVISIBLES, ' ')
|
|
114
|
+
// eslint-disable-next-line no-control-regex
|
|
115
|
+
.replace(/[\u0000-\u001f\u007f]/g, ' '));
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=sanitize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,iFAAiF,CAAC;AAEpF;;;;;GAKG;AACH,SAAS,kBAAkB,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,EAAE,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,+EAA+E;IAC/E,+EAA+E;IAC/E,+EAA+E;IAC/E,MAAM,OAAO,GAAG,IAAI;SACjB,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC;QACvC,4CAA4C;SAC3C,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC;SACtC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAC9B,2EAA2E;IAC3E,2CAA2C;IAC3C,OAAO,kBAAkB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;AAC7D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,MAAc;IAC7D,MAAM,OAAO,GAAG,IAAI;SACjB,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC;QACvC,4CAA4C;SAC3C,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC;SACtC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC3B,8EAA8E;IAC9E,4EAA4E;IAC5E,wEAAwE;IACxE,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,CACL,IAAI;SACD,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC;SACtC,OAAO,CAAC,sCAAsC,EAAE,QAAQ,CAAC;QAC1D,uEAAuE;QACvE,4EAA4E;QAC5E,4CAA4C;SAC3C,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAC1C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,OAAO,GAAG,IAAI;SACjB,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC;QACvC,4CAA4C;SAC3C,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;IAC1C,0EAA0E;IAC1E,OAAO,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAc;IAC1D,OAAO,CACL,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC;QAC9B,uEAAuE;QACvE,sEAAsE;SACrE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC;QACvC,4CAA4C;SAC3C,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAC1C,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ChannelAgentBridge } from './ChannelAgentBridge.js';
|
|
2
2
|
import type { ChannelBase, ChannelBaseOptions } from './ChannelBase.js';
|
|
3
3
|
export type SenderPolicy = 'allowlist' | 'pairing' | 'open';
|
|
4
4
|
export type SessionScope = 'user' | 'thread' | 'single';
|
|
@@ -8,6 +8,7 @@ export type DispatchMode = 'collect' | 'steer' | 'followup';
|
|
|
8
8
|
export interface GroupConfig {
|
|
9
9
|
requireMention?: boolean;
|
|
10
10
|
dispatchMode?: DispatchMode;
|
|
11
|
+
groupHistoryLimit?: number;
|
|
11
12
|
}
|
|
12
13
|
export interface BlockStreamingChunkConfig {
|
|
13
14
|
/** Minimum characters before emitting a block. Default: 400. */
|
|
@@ -32,8 +33,9 @@ export interface ChannelConfig {
|
|
|
32
33
|
instructions?: string;
|
|
33
34
|
model?: string;
|
|
34
35
|
groupPolicy: GroupPolicy;
|
|
36
|
+
groupHistoryLimit?: number;
|
|
35
37
|
groups: Record<string, GroupConfig>;
|
|
36
|
-
/** Dispatch mode for concurrent messages. Default: '
|
|
38
|
+
/** Dispatch mode for concurrent messages. Default: 'steer' (resolved in ChannelBase.handleInbound). */
|
|
37
39
|
dispatchMode?: DispatchMode;
|
|
38
40
|
/** Enable block streaming — emit completed blocks as separate messages. */
|
|
39
41
|
blockStreaming?: 'on' | 'off';
|
|
@@ -74,12 +76,37 @@ export interface Envelope {
|
|
|
74
76
|
imageMimeType?: string;
|
|
75
77
|
/** Structured attachments (images, files, audio, video). */
|
|
76
78
|
attachments?: Attachment[];
|
|
79
|
+
/**
|
|
80
|
+
* Marks an envelope whose `text` ALREADY carries its `[sender]` attribution, so
|
|
81
|
+
* handleInbound must NOT re-prefix it. Set in two places: on a synthetic
|
|
82
|
+
* collect-mode re-entry (coalesced text already carries each message's prefix), AND
|
|
83
|
+
* by the QQ adapter on a REAL inbound it self-prefixes as `[name]: …`. QQ
|
|
84
|
+
* neutralizes that embedded name with sanitizeSenderName at the source (QQChannel),
|
|
85
|
+
* so the self-prefixed name reaching the prompt is already sanitized — setting this
|
|
86
|
+
* flag does not bypass sanitization.
|
|
87
|
+
*/
|
|
88
|
+
alreadyPrefixed?: true;
|
|
77
89
|
}
|
|
78
90
|
export interface SessionTarget {
|
|
79
91
|
channelName: string;
|
|
80
92
|
senderId: string;
|
|
81
93
|
chatId: string;
|
|
82
94
|
threadId?: string;
|
|
95
|
+
isGroup?: boolean;
|
|
96
|
+
}
|
|
97
|
+
export interface ChannelMemoryTarget {
|
|
98
|
+
channelName: string;
|
|
99
|
+
chatId: string;
|
|
100
|
+
threadId?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface ChannelMemoryWriteResult {
|
|
103
|
+
changed: boolean;
|
|
104
|
+
filePath?: string;
|
|
105
|
+
}
|
|
106
|
+
export interface ChannelMemoryCallbacks {
|
|
107
|
+
readChannelMemory(target: ChannelMemoryTarget): Promise<string>;
|
|
108
|
+
appendChannelMemory(target: ChannelMemoryTarget, text: string): Promise<ChannelMemoryWriteResult>;
|
|
109
|
+
clearChannelMemory(target: ChannelMemoryTarget): Promise<ChannelMemoryWriteResult>;
|
|
83
110
|
}
|
|
84
111
|
/**
|
|
85
112
|
* A channel plugin registers a channel type and provides a factory
|
|
@@ -97,5 +124,5 @@ export interface ChannelPlugin {
|
|
|
97
124
|
*/
|
|
98
125
|
requiredConfigFields?: string[];
|
|
99
126
|
/** Create a channel adapter instance. */
|
|
100
|
-
createChannel(name: string, config: ChannelConfig & Record<string, unknown>, bridge:
|
|
127
|
+
createChannel(name: string, config: ChannelConfig & Record<string, unknown>, bridge: ChannelAgentBridge, options?: ChannelBaseOptions): ChannelBase;
|
|
101
128
|
}
|