@qwen-code/channel-base 0.19.3-nightly.20260701.a974594d7 → 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 +11 -0
- package/dist/ChannelAgentBridge.d.ts +1 -0
- package/dist/ChannelBase.d.ts +53 -1
- package/dist/ChannelBase.js +749 -24
- 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/SenderGate.d.ts +1 -0
- package/dist/SenderGate.js +13 -0
- package/dist/SenderGate.js.map +1 -1
- package/dist/SessionRouter.js +20 -6
- 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 +5 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/sanitize.js +2 -0
- package/dist/sanitize.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,6 +67,15 @@ For a complete working example, see [`@qwen-code/channel-plugin-example`](../plu
|
|
|
67
67
|
|
|
68
68
|
Migration note for existing TypeScript plugins: if your adapter constructor or factory explicitly types `bridge` as `AcpBridge`, change that annotation to `ChannelAgentBridge` and keep using only the methods exposed by that contract. JavaScript plugins are unaffected at runtime, and standalone `qwen channel start` still passes the current `AcpBridge` implementation.
|
|
69
69
|
|
|
70
|
+
## Runtime modes
|
|
71
|
+
|
|
72
|
+
Channel adapters can run in two host modes:
|
|
73
|
+
|
|
74
|
+
- `qwen channel start [name]` is the standalone service. It uses `AcpBridge` over a `qwen-code --acp` child process and remains the default channel command.
|
|
75
|
+
- `qwen serve --channel <name>` and `qwen serve --channel all` are experimental daemon-managed modes. `qwen serve` starts one out-of-process channel worker, the worker connects back to the daemon through the SDK, and adapters receive a `DaemonChannelBridge`-backed `ChannelAgentBridge` facade.
|
|
76
|
+
|
|
77
|
+
In daemon-managed mode, one daemon is bound to one workspace. Every selected channel's `cwd` must resolve to that same workspace. The optional `shellCommand` method is exposed to adapters only when the daemon advertises the `session_shell_command` capability.
|
|
78
|
+
|
|
70
79
|
## Architecture
|
|
71
80
|
|
|
72
81
|
```
|
|
@@ -160,6 +169,8 @@ constructor(name: string, config: ChannelConfig, bridge: ChannelAgentBridge, opt
|
|
|
160
169
|
|
|
161
170
|
`ChannelAgentBridge` is the adapter-facing contract. Channel adapters, channel plugins, `ChannelBase`, and `SessionRouter` should depend on this type instead of a concrete bridge implementation.
|
|
162
171
|
|
|
172
|
+
`shellCommand` is optional. Adapters should check for it before enabling `!cmd`-style features because daemon-managed hosts expose it only when the connected daemon supports shell execution.
|
|
173
|
+
|
|
163
174
|
```typescript
|
|
164
175
|
interface ChannelAgentBridge {
|
|
165
176
|
readonly availableCommands: AvailableCommand[];
|
|
@@ -29,6 +29,7 @@ interface ChannelAgentBridgeEventMap {
|
|
|
29
29
|
}
|
|
30
30
|
export interface ChannelAgentBridge {
|
|
31
31
|
readonly availableCommands: AvailableCommand[];
|
|
32
|
+
getAvailableCommands?(sessionId: string): AvailableCommand[];
|
|
32
33
|
on<K extends keyof ChannelAgentBridgeEventMap>(eventName: K, listener: (...args: ChannelAgentBridgeEventMap[K]) => void): unknown;
|
|
33
34
|
off<K extends keyof ChannelAgentBridgeEventMap>(eventName: K, listener: (...args: ChannelAgentBridgeEventMap[K]) => void): unknown;
|
|
34
35
|
newSession(cwd: string): Promise<string>;
|
package/dist/ChannelBase.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { ChannelConfig, Envelope } from './types.js';
|
|
1
|
+
import type { ChannelConfig, ChannelMemoryCallbacks, Envelope, SessionTarget } from './types.js';
|
|
2
2
|
import { GroupGate } from './GroupGate.js';
|
|
3
3
|
import { SenderGate } from './SenderGate.js';
|
|
4
4
|
import { SessionRouter } from './SessionRouter.js';
|
|
5
5
|
import type { ChannelAgentBridge, ToolCallEvent } from './ChannelAgentBridge.js';
|
|
6
|
+
import type { ChannelLoop, ChannelLoopInput } from './ChannelLoopStore.js';
|
|
6
7
|
/**
|
|
7
8
|
* Max time /clear waits for a cancelled in-flight turn to wind down before
|
|
8
9
|
* purging anyway. A wedged ACP child (stuck tool call, not reading stdin, or
|
|
@@ -15,11 +16,26 @@ export declare const CLEAR_CANCEL_TIMEOUT_MS = 3000;
|
|
|
15
16
|
export interface ChannelBaseOptions {
|
|
16
17
|
router?: SessionRouter;
|
|
17
18
|
proxy?: string;
|
|
19
|
+
channelMemory?: ChannelMemoryCallbacks;
|
|
18
20
|
/**
|
|
19
21
|
* Set when a channel owns a supplied router and should consume bridge
|
|
20
22
|
* events directly.
|
|
21
23
|
*/
|
|
22
24
|
registerBridgeEvents?: boolean;
|
|
25
|
+
groupHistoryPath?: string;
|
|
26
|
+
loopController?: ChannelLoopController;
|
|
27
|
+
}
|
|
28
|
+
export interface ChannelLoopController {
|
|
29
|
+
create(input: ChannelLoopInput): Promise<ChannelLoop>;
|
|
30
|
+
createForTarget?(input: ChannelLoopInput, maxEnabledLoops: number): Promise<ChannelLoop | undefined>;
|
|
31
|
+
listForTarget(channelName: string, target: SessionTarget): Promise<ChannelLoop[]>;
|
|
32
|
+
disable(id: string): Promise<boolean>;
|
|
33
|
+
validateCron(cron: string): void;
|
|
34
|
+
nextFireTime?(job: ChannelLoop): Date;
|
|
35
|
+
}
|
|
36
|
+
export interface ChannelLoopPromptOptions {
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
shouldContinue?: () => Promise<boolean>;
|
|
23
39
|
}
|
|
24
40
|
/** Handler for a slash command. Return true if handled, false to forward to agent. */
|
|
25
41
|
type CommandHandler = (envelope: Envelope, args: string) => Promise<boolean>;
|
|
@@ -32,6 +48,9 @@ export declare abstract class ChannelBase {
|
|
|
32
48
|
protected name: string;
|
|
33
49
|
/** Resolved proxy URL, available to subclasses for adapter-specific clients. */
|
|
34
50
|
protected proxy?: string;
|
|
51
|
+
private readonly channelMemory?;
|
|
52
|
+
private groupHistory;
|
|
53
|
+
private readonly loopController?;
|
|
35
54
|
private instructedSessions;
|
|
36
55
|
private commands;
|
|
37
56
|
/** Per-session promise chain to serialize prompt + send (followup mode). */
|
|
@@ -53,8 +72,14 @@ export declare abstract class ChannelBase {
|
|
|
53
72
|
abstract connect(): Promise<void>;
|
|
54
73
|
abstract sendMessage(chatId: string, text: string): Promise<void>;
|
|
55
74
|
abstract disconnect(): void;
|
|
75
|
+
supportsProactiveSend(): boolean;
|
|
76
|
+
protected supportsProactiveTarget(target: SessionTarget): boolean;
|
|
77
|
+
protected pushProactive(target: SessionTarget, text: string): Promise<void>;
|
|
56
78
|
/** Replace the bridge instance (used after crash recovery restart). */
|
|
57
79
|
setBridge(bridge: ChannelAgentBridge): void;
|
|
80
|
+
runLoopPrompt(job: ChannelLoop, options?: ChannelLoopPromptOptions): Promise<string | undefined>;
|
|
81
|
+
private runLoopBridgePrompt;
|
|
82
|
+
private cancelTimedOutLoopPrompt;
|
|
58
83
|
onToolCall(_chatId: string, _event: ToolCallEvent): void;
|
|
59
84
|
onSessionDied(sessionId: string): void;
|
|
60
85
|
private attachBridgeEvents;
|
|
@@ -91,9 +116,29 @@ export declare abstract class ChannelBase {
|
|
|
91
116
|
protected registerCancelCommand(name?: string): void;
|
|
92
117
|
/** Register shared slash commands. Called from constructor. */
|
|
93
118
|
private registerSharedCommands;
|
|
119
|
+
private handleLoopCommand;
|
|
120
|
+
private handleLoopAdd;
|
|
121
|
+
private handleLoopList;
|
|
122
|
+
private handleLoopInspect;
|
|
123
|
+
private formatLoopListLine;
|
|
124
|
+
private lastLoopStatus;
|
|
125
|
+
private formatNextFireTime;
|
|
126
|
+
private handleLoopCancel;
|
|
127
|
+
private loopTargetFromEnvelope;
|
|
128
|
+
private isStoredLoopTargetAuthorized;
|
|
94
129
|
/** Check if a message text matches a registered local command. */
|
|
95
130
|
protected isLocalCommand(text: string): boolean;
|
|
96
131
|
private findActiveSessionId;
|
|
132
|
+
private channelMemoryTarget;
|
|
133
|
+
private invalidateSessionContext;
|
|
134
|
+
private dropQueuedTurnIfStale;
|
|
135
|
+
private isAuthorizedForChannelMemory;
|
|
136
|
+
private isSenderAuthorizedForChannelMemory;
|
|
137
|
+
private ensureChannelMemoryAuthorized;
|
|
138
|
+
private getChannelMemory;
|
|
139
|
+
private channelMemoryErrorMessage;
|
|
140
|
+
private channelMemoryUserErrorMessage;
|
|
141
|
+
private logChannelMemoryError;
|
|
97
142
|
/**
|
|
98
143
|
* Whether the resolved session is SHARED across senders. `single` collapses
|
|
99
144
|
* the whole channel to one `__single__` session for EVERY sender — group OR
|
|
@@ -103,6 +148,7 @@ export declare abstract class ChannelBase {
|
|
|
103
148
|
* and the host-shell (`!`) gate.
|
|
104
149
|
*/
|
|
105
150
|
private isSharedSession;
|
|
151
|
+
private isSharedSessionTarget;
|
|
106
152
|
/**
|
|
107
153
|
* Whether `envelope.senderId` may act on the resolved session's destructive or
|
|
108
154
|
* workspace-leaking commands (/clear, /who). A SHARED session with a non-empty
|
|
@@ -172,6 +218,12 @@ export declare abstract class ChannelBase {
|
|
|
172
218
|
* isRecognizedCommand's no-await contract.
|
|
173
219
|
*/
|
|
174
220
|
private getAgentCommandsForSession;
|
|
221
|
+
private groupHistoryKey;
|
|
222
|
+
private groupHistoryLimit;
|
|
223
|
+
private recordPendingGroupHistory;
|
|
224
|
+
private drainPendingGroupHistory;
|
|
225
|
+
private clearPendingGroupHistory;
|
|
226
|
+
private prependGroupHistoryContext;
|
|
175
227
|
handleInbound(envelope: Envelope): Promise<void>;
|
|
176
228
|
protected onPairingRequired(chatId: string, code: string | null): Promise<void>;
|
|
177
229
|
}
|