@qwen-code/channel-base 0.19.10 → 0.19.11-nightly.20260717.f8e6e8931
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 +2 -2
- package/dist/ChannelBase.d.ts +4 -0
- package/dist/ChannelBase.js +234 -54
- package/dist/ChannelBase.js.map +1 -1
- package/dist/DaemonChannelBridge.js +14 -0
- package/dist/DaemonChannelBridge.js.map +1 -1
- package/dist/channel-memory-intent.d.ts +11 -0
- package/dist/channel-memory-intent.js +53 -1
- package/dist/channel-memory-intent.js.map +1 -1
- package/dist/types.d.ts +52 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,9 +72,9 @@ Migration note for existing TypeScript plugins: if your adapter constructor or f
|
|
|
72
72
|
Channel adapters can run in two host modes:
|
|
73
73
|
|
|
74
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
|
|
75
|
+
- `qwen serve --channel <name>` and `qwen serve --channel all` are experimental daemon-managed modes. Named channels are grouped by owning workspace and `qwen serve` starts one out-of-process worker per owning runtime. Each worker connects back to the daemon through the SDK, and adapters receive a `DaemonChannelBridge`-backed `ChannelAgentBridge` facade. `--channel all` stays primary-only.
|
|
76
76
|
|
|
77
|
-
In daemon-managed mode,
|
|
77
|
+
In daemon-managed mode, every named channel's `cwd` must resolve to exactly one registered, trusted workspace. Its worker receives that runtime's cwd and environment overlay; an ambiguous or untrusted selection fails instead of using primary. The optional `shellCommand` method is exposed to adapters only when the daemon advertises the `session_shell_command` capability.
|
|
78
78
|
|
|
79
79
|
## Architecture
|
|
80
80
|
|
package/dist/ChannelBase.d.ts
CHANGED
|
@@ -111,6 +111,7 @@ export declare abstract class ChannelBase {
|
|
|
111
111
|
private lifecycleBase;
|
|
112
112
|
supportsProactiveSend(): boolean;
|
|
113
113
|
protected supportsProactiveTarget(target: SessionTarget): boolean;
|
|
114
|
+
protected supportsProactiveWebhookTarget(target: SessionTarget): boolean;
|
|
114
115
|
protected pushProactive(target: SessionTarget, text: string): Promise<void>;
|
|
115
116
|
private prependUnattendedSessionContext;
|
|
116
117
|
private drainCollectBufferForCurrentPrompt;
|
|
@@ -212,6 +213,9 @@ export declare abstract class ChannelBase {
|
|
|
212
213
|
private invalidateSessionContext;
|
|
213
214
|
private dropQueuedTurnIfStale;
|
|
214
215
|
private getChannelMemory;
|
|
216
|
+
private entriesForChannelMemoryIds;
|
|
217
|
+
private renderChannelMemoryCandidate;
|
|
218
|
+
private renderChannelMemoryCandidates;
|
|
215
219
|
private handleChannelMemoryIntent;
|
|
216
220
|
private shouldClassifyChannelMemoryIntent;
|
|
217
221
|
private clearPendingKey;
|
package/dist/ChannelBase.js
CHANGED
|
@@ -26,8 +26,10 @@ const GROUP_HISTORY_ENTRY_TEXT_LIMIT = 1000;
|
|
|
26
26
|
const GROUP_HISTORY_ENTRY_METADATA_LIMIT = 256;
|
|
27
27
|
const LOOP_CANCEL_GRACE_MS = 5000;
|
|
28
28
|
const CHANNEL_MEMORY_PROMPT_CODE_POINT_LIMIT = 12_000;
|
|
29
|
+
const CHANNEL_MEMORY_PAGE_SIZE = 20;
|
|
30
|
+
const CHANNEL_MEMORY_PREVIEW_CODE_POINT_LIMIT = 160;
|
|
29
31
|
const CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE = 0.7;
|
|
30
|
-
const CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(
|
|
32
|
+
const CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(?:记住|记得|记一下|记忆|忘掉|忘记|清空|清除|删除|删掉|改成|更新|刚才那条|保存|(?:只|仅)(?:看|列出)[\p{Script=Han}\s]{0,12}(?:偏好|习惯)|\b(?:remember|memory|forget|delete|remove|update|change)\b)/iu;
|
|
31
33
|
/** Sentinel message for the loop-prompt timeout rejection; matched by identity below. */
|
|
32
34
|
const LOOP_TIMED_OUT_MESSAGE = 'loop timed out';
|
|
33
35
|
const DEBUG_PAYLOAD_ENV = 'QWEN_CHANNEL_DEBUG_PAYLOAD';
|
|
@@ -370,6 +372,9 @@ export class ChannelBase {
|
|
|
370
372
|
supportsProactiveTarget(target) {
|
|
371
373
|
return target.threadId === undefined;
|
|
372
374
|
}
|
|
375
|
+
supportsProactiveWebhookTarget(target) {
|
|
376
|
+
return this.supportsProactiveTarget(target);
|
|
377
|
+
}
|
|
373
378
|
async pushProactive(target, text) {
|
|
374
379
|
if (target.threadId) {
|
|
375
380
|
throw new Error('Channel does not support proactive loop messages for threaded targets.');
|
|
@@ -675,7 +680,7 @@ export class ChannelBase {
|
|
|
675
680
|
throw new Error(`Unknown webhook source "${task.source}".`);
|
|
676
681
|
}
|
|
677
682
|
const target = resolveChannelWebhookTarget(this.name, this.config.webhooks, task.source, task.targetRef);
|
|
678
|
-
if (!this.
|
|
683
|
+
if (!this.supportsProactiveWebhookTarget(target)) {
|
|
679
684
|
throw new Error('Channel does not support proactive webhook messages for this chat target.');
|
|
680
685
|
}
|
|
681
686
|
return target;
|
|
@@ -1407,30 +1412,6 @@ export class ChannelBase {
|
|
|
1407
1412
|
this.registerCommand('approve', (envelope, args) => this.handlePermissionResponseCommand(envelope, args, 'approve'));
|
|
1408
1413
|
this.registerCommand('approve-always', (envelope, args) => this.handlePermissionResponseCommand(envelope, args, 'approve-always'));
|
|
1409
1414
|
this.registerCommand('deny', (envelope, args) => this.handlePermissionResponseCommand(envelope, args, 'deny'));
|
|
1410
|
-
this.registerCommand('remember-channel', async (envelope, args) => {
|
|
1411
|
-
const text = args.trim();
|
|
1412
|
-
if (text === '') {
|
|
1413
|
-
await this.sendMessage(envelope.chatId, 'Usage: /remember-channel <text>');
|
|
1414
|
-
return true;
|
|
1415
|
-
}
|
|
1416
|
-
await this.handleChannelMemoryIntent(envelope, {
|
|
1417
|
-
kind: 'remember',
|
|
1418
|
-
text,
|
|
1419
|
-
});
|
|
1420
|
-
return true;
|
|
1421
|
-
});
|
|
1422
|
-
this.registerCommand('channel-memory', async (envelope) => {
|
|
1423
|
-
await this.handleChannelMemoryIntent(envelope, { kind: 'list' });
|
|
1424
|
-
return true;
|
|
1425
|
-
});
|
|
1426
|
-
this.registerCommand('forget-channel', async (envelope, args) => {
|
|
1427
|
-
if (args.toLowerCase() !== 'confirm') {
|
|
1428
|
-
await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Re-send with "confirm" (e.g. /forget-channel confirm) to proceed.');
|
|
1429
|
-
return true;
|
|
1430
|
-
}
|
|
1431
|
-
await this.handleChannelMemoryIntent(envelope, { kind: 'clear_confirm' }, { skipPendingClear: true });
|
|
1432
|
-
return true;
|
|
1433
|
-
});
|
|
1434
1415
|
// Read-only: report the current (possibly group-shared) session and workspace.
|
|
1435
1416
|
// For a shared session, gate it to authorized senders like /clear — /who
|
|
1436
1417
|
// leaks the workspace basename, so non-members shouldn't see it either.
|
|
@@ -1938,7 +1919,64 @@ export class ChannelBase {
|
|
|
1938
1919
|
}
|
|
1939
1920
|
return this.channelMemory;
|
|
1940
1921
|
}
|
|
1941
|
-
|
|
1922
|
+
entriesForChannelMemoryIds(entries, ids) {
|
|
1923
|
+
const selected = new Set(ids);
|
|
1924
|
+
return entries.filter((entry) => selected.has(entry.id));
|
|
1925
|
+
}
|
|
1926
|
+
renderChannelMemoryCandidate(entry) {
|
|
1927
|
+
const preview = truncateCodePoints(sanitizePromptText(entry.text)
|
|
1928
|
+
.replace(/[\r\n]+/gu, ' ')
|
|
1929
|
+
.trim(), CHANNEL_MEMORY_PREVIEW_CODE_POINT_LIMIT);
|
|
1930
|
+
return `${entry.id} ${preview}`;
|
|
1931
|
+
}
|
|
1932
|
+
renderChannelMemoryCandidates(entries) {
|
|
1933
|
+
return entries.map((entry) => this.renderChannelMemoryCandidate(entry));
|
|
1934
|
+
}
|
|
1935
|
+
async handleChannelMemoryIntent(envelope, intent) {
|
|
1936
|
+
if (intent.kind === 'no_match') {
|
|
1937
|
+
await this.sendMessage(envelope.chatId, 'No matching channel memory entry.');
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
if (intent.kind === 'ambiguous') {
|
|
1941
|
+
const channelMemory = await this.getChannelMemory(envelope);
|
|
1942
|
+
if (!channelMemory)
|
|
1943
|
+
return;
|
|
1944
|
+
let entries;
|
|
1945
|
+
try {
|
|
1946
|
+
entries = await channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
1947
|
+
}
|
|
1948
|
+
catch (error) {
|
|
1949
|
+
this.logChannelMemoryError('read', envelope, this.channelMemoryErrorMessage(error));
|
|
1950
|
+
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
|
|
1954
|
+
await this.sendMessage(envelope.chatId, [
|
|
1955
|
+
'Multiple channel memory entries match:',
|
|
1956
|
+
...this.renderChannelMemoryCandidates(selected),
|
|
1957
|
+
].join('\n'));
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
if (intent.kind === 'list_matches') {
|
|
1961
|
+
const channelMemory = await this.getChannelMemory(envelope);
|
|
1962
|
+
if (!channelMemory)
|
|
1963
|
+
return;
|
|
1964
|
+
let entries;
|
|
1965
|
+
try {
|
|
1966
|
+
entries = await channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
1967
|
+
}
|
|
1968
|
+
catch (error) {
|
|
1969
|
+
this.logChannelMemoryError('read', envelope, this.channelMemoryErrorMessage(error));
|
|
1970
|
+
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
|
|
1974
|
+
await this.sendMessage(envelope.chatId, [
|
|
1975
|
+
'Channel memory (page 1/1):',
|
|
1976
|
+
...this.renderChannelMemoryCandidates(selected),
|
|
1977
|
+
].join('\n'));
|
|
1978
|
+
return;
|
|
1979
|
+
}
|
|
1942
1980
|
if (intent.kind === 'clear_request') {
|
|
1943
1981
|
this.setPendingClear(this.clearPendingKey(envelope));
|
|
1944
1982
|
await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Say "确认清空记忆" or "confirm clear memory" to proceed.');
|
|
@@ -1949,8 +1987,9 @@ export class ChannelBase {
|
|
|
1949
1987
|
return;
|
|
1950
1988
|
}
|
|
1951
1989
|
if (intent.kind === 'remember') {
|
|
1990
|
+
let result;
|
|
1952
1991
|
try {
|
|
1953
|
-
await channelMemory.
|
|
1992
|
+
result = await channelMemory.addChannelMemoryEntries(this.channelMemoryTarget(envelope), [intent.text], envelope.senderId);
|
|
1954
1993
|
}
|
|
1955
1994
|
catch (error) {
|
|
1956
1995
|
const message = this.channelMemoryErrorMessage(error);
|
|
@@ -1958,14 +1997,27 @@ export class ChannelBase {
|
|
|
1958
1997
|
await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
1959
1998
|
return;
|
|
1960
1999
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
2000
|
+
if (result.changed) {
|
|
2001
|
+
this.invalidateSessionContext(envelope);
|
|
2002
|
+
}
|
|
2003
|
+
if (result.added.length > 0) {
|
|
2004
|
+
const ids = result.added.map((entry) => entry.id);
|
|
2005
|
+
await this.sendMessage(envelope.chatId, ids.length === 1
|
|
2006
|
+
? `Channel memory ${ids[0]} saved.`
|
|
2007
|
+
: `Channel memory saved: ${ids.join(', ')}.`);
|
|
2008
|
+
}
|
|
2009
|
+
else if (result.duplicateIds.length > 0) {
|
|
2010
|
+
await this.sendMessage(envelope.chatId, `Channel memory already contains ${result.duplicateIds.join(', ')}.`);
|
|
2011
|
+
}
|
|
2012
|
+
else {
|
|
2013
|
+
await this.sendMessage(envelope.chatId, 'Channel memory updated.');
|
|
2014
|
+
}
|
|
1963
2015
|
return;
|
|
1964
2016
|
}
|
|
1965
|
-
if (intent.kind === 'list') {
|
|
1966
|
-
let
|
|
2017
|
+
if (intent.kind === 'list' || intent.kind === 'inspect') {
|
|
2018
|
+
let entries;
|
|
1967
2019
|
try {
|
|
1968
|
-
|
|
2020
|
+
entries = await channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
1969
2021
|
}
|
|
1970
2022
|
catch (error) {
|
|
1971
2023
|
const message = this.channelMemoryErrorMessage(error);
|
|
@@ -1973,19 +2025,77 @@ export class ChannelBase {
|
|
|
1973
2025
|
await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
1974
2026
|
return;
|
|
1975
2027
|
}
|
|
1976
|
-
|
|
2028
|
+
if (intent.kind === 'inspect') {
|
|
2029
|
+
const entry = entries.find((candidate) => candidate.id === intent.id);
|
|
2030
|
+
await this.sendMessage(envelope.chatId, entry
|
|
2031
|
+
? `Channel memory ${entry.id}:\n${sanitizePromptText(entry.text).trim()}`
|
|
2032
|
+
: `No channel memory entry ${intent.id}.`);
|
|
2033
|
+
return;
|
|
2034
|
+
}
|
|
2035
|
+
const totalPages = Math.max(1, Math.ceil(entries.length / CHANNEL_MEMORY_PAGE_SIZE));
|
|
2036
|
+
if (intent.page > totalPages) {
|
|
2037
|
+
await this.sendMessage(envelope.chatId, `Channel memory page ${intent.page} does not exist.`);
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
if (entries.length === 0) {
|
|
2041
|
+
await this.sendMessage(envelope.chatId, 'No channel memory saved.');
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
const pageStart = (intent.page - 1) * CHANNEL_MEMORY_PAGE_SIZE;
|
|
2045
|
+
const lines = entries
|
|
2046
|
+
.slice(pageStart, pageStart + CHANNEL_MEMORY_PAGE_SIZE)
|
|
2047
|
+
.map((entry) => this.renderChannelMemoryCandidate(entry));
|
|
2048
|
+
await this.sendMessage(envelope.chatId, [`Channel memory (page ${intent.page}/${totalPages}):`, ...lines].join('\n'));
|
|
1977
2049
|
return;
|
|
1978
2050
|
}
|
|
1979
|
-
if (intent.kind === '
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2051
|
+
if (intent.kind === 'update' ||
|
|
2052
|
+
intent.kind === 'remove' ||
|
|
2053
|
+
intent.kind === 'natural_update' ||
|
|
2054
|
+
intent.kind === 'natural_remove') {
|
|
2055
|
+
let changed;
|
|
2056
|
+
const isUpdate = intent.kind === 'update' || intent.kind === 'natural_update';
|
|
2057
|
+
const id = intent.id;
|
|
2058
|
+
try {
|
|
2059
|
+
if (isUpdate) {
|
|
2060
|
+
({ changed } = await channelMemory.updateChannelMemoryEntry(this.channelMemoryTarget(envelope), intent.kind === 'natural_update'
|
|
2061
|
+
? {
|
|
2062
|
+
id: intent.id,
|
|
2063
|
+
text: intent.text,
|
|
2064
|
+
expectedText: intent.expectedText,
|
|
2065
|
+
}
|
|
2066
|
+
: { id: intent.id, text: intent.text }));
|
|
2067
|
+
}
|
|
2068
|
+
else {
|
|
2069
|
+
({ changed } = await channelMemory.removeChannelMemoryEntries(this.channelMemoryTarget(envelope), intent.kind === 'natural_remove'
|
|
2070
|
+
? {
|
|
2071
|
+
ids: [intent.id],
|
|
2072
|
+
expectedTextById: { [intent.id]: intent.expectedText },
|
|
2073
|
+
}
|
|
2074
|
+
: { ids: [intent.id] }));
|
|
1987
2075
|
}
|
|
1988
2076
|
}
|
|
2077
|
+
catch (error) {
|
|
2078
|
+
const message = this.channelMemoryErrorMessage(error);
|
|
2079
|
+
this.logChannelMemoryError(isUpdate ? 'update' : 'remove', envelope, message);
|
|
2080
|
+
await this.sendMessage(envelope.chatId, `Failed to ${isUpdate ? 'update' : 'remove'} channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
if (!changed) {
|
|
2084
|
+
await this.sendMessage(envelope.chatId, `No channel memory entry ${id}.`);
|
|
2085
|
+
return;
|
|
2086
|
+
}
|
|
2087
|
+
this.invalidateSessionContext(envelope);
|
|
2088
|
+
await this.sendMessage(envelope.chatId, `Channel memory ${id} ${isUpdate ? 'updated' : 'removed'}.`);
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
if (intent.kind === 'clear_confirm') {
|
|
2092
|
+
const pendingKey = this.clearPendingKey(envelope);
|
|
2093
|
+
const expiresAt = this.pendingClears.get(pendingKey);
|
|
2094
|
+
this.pendingClears.delete(pendingKey);
|
|
2095
|
+
if (expiresAt === undefined || expiresAt < Date.now()) {
|
|
2096
|
+
await this.sendMessage(envelope.chatId, 'No pending clear request. Say "清空记忆" first.');
|
|
2097
|
+
return;
|
|
2098
|
+
}
|
|
1989
2099
|
let result;
|
|
1990
2100
|
try {
|
|
1991
2101
|
result = await channelMemory.clearChannelMemory(this.channelMemoryTarget(envelope));
|
|
@@ -1996,7 +2106,9 @@ export class ChannelBase {
|
|
|
1996
2106
|
await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
|
|
1997
2107
|
return;
|
|
1998
2108
|
}
|
|
1999
|
-
|
|
2109
|
+
if (result.changed) {
|
|
2110
|
+
this.invalidateSessionContext(envelope);
|
|
2111
|
+
}
|
|
2000
2112
|
await this.sendMessage(envelope.chatId, result.changed ? 'Channel memory cleared.' : 'No channel memory saved.');
|
|
2001
2113
|
return;
|
|
2002
2114
|
}
|
|
@@ -2022,32 +2134,100 @@ export class ChannelBase {
|
|
|
2022
2134
|
}
|
|
2023
2135
|
this.pendingClears.set(key, now + 60_000);
|
|
2024
2136
|
}
|
|
2025
|
-
async classifyChannelMemoryIntent(
|
|
2026
|
-
if (!this.memoryIntentClassifier) {
|
|
2137
|
+
async classifyChannelMemoryIntent(envelope) {
|
|
2138
|
+
if (!this.memoryIntentClassifier || !this.channelMemory) {
|
|
2139
|
+
return null;
|
|
2140
|
+
}
|
|
2141
|
+
let entries;
|
|
2142
|
+
try {
|
|
2143
|
+
entries = await this.channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
|
|
2144
|
+
}
|
|
2145
|
+
catch (error) {
|
|
2146
|
+
this.logChannelMemoryError('read', envelope, this.channelMemoryErrorMessage(error));
|
|
2027
2147
|
return null;
|
|
2028
2148
|
}
|
|
2029
2149
|
let classified;
|
|
2030
2150
|
try {
|
|
2031
2151
|
classified =
|
|
2032
|
-
await this.memoryIntentClassifier.classifyChannelMemoryIntent(text);
|
|
2152
|
+
await this.memoryIntentClassifier.classifyChannelMemoryIntent(envelope.text, entries);
|
|
2033
2153
|
}
|
|
2034
2154
|
catch (error) {
|
|
2035
2155
|
process.stderr.write(`[${this.name}] channel memory intent classifier failed: ${sanitizeLogText(this.channelMemoryErrorMessage(error), 200)}\n`);
|
|
2036
2156
|
return null;
|
|
2037
2157
|
}
|
|
2038
|
-
|
|
2158
|
+
const confidence = classified && typeof classified === 'object'
|
|
2159
|
+
? classified.confidence
|
|
2160
|
+
: undefined;
|
|
2161
|
+
if (typeof confidence !== 'number' ||
|
|
2162
|
+
!Number.isFinite(confidence) ||
|
|
2163
|
+
confidence < 0 ||
|
|
2164
|
+
confidence > 1 ||
|
|
2165
|
+
confidence < CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE) {
|
|
2039
2166
|
return null;
|
|
2040
2167
|
}
|
|
2041
|
-
|
|
2042
|
-
|
|
2168
|
+
const result = classified;
|
|
2169
|
+
const targetIds = result.targetIds;
|
|
2170
|
+
const entryById = new Map(entries.map((entry) => [entry.id, entry]));
|
|
2171
|
+
const resolvedEntries = targetIds === undefined
|
|
2172
|
+
? undefined
|
|
2173
|
+
: Array.isArray(targetIds) &&
|
|
2174
|
+
targetIds.every((id) => typeof id === 'string' && entryById.has(id)) &&
|
|
2175
|
+
new Set(targetIds).size === targetIds.length
|
|
2176
|
+
? this.entriesForChannelMemoryIds(entries, targetIds)
|
|
2177
|
+
: null;
|
|
2178
|
+
if (result.intent === 'remember') {
|
|
2179
|
+
const memory = typeof result.memory === 'string' ? result.memory.trim() : '';
|
|
2043
2180
|
return memory ? { kind: 'remember', text: memory } : null;
|
|
2044
2181
|
}
|
|
2045
|
-
if (
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2182
|
+
if (result.intent === 'list') {
|
|
2183
|
+
if (resolvedEntries === undefined)
|
|
2184
|
+
return { kind: 'list', page: 1 };
|
|
2185
|
+
if (resolvedEntries === null)
|
|
2186
|
+
return null;
|
|
2187
|
+
return resolvedEntries.length === 0
|
|
2188
|
+
? { kind: 'no_match' }
|
|
2189
|
+
: {
|
|
2190
|
+
kind: 'list_matches',
|
|
2191
|
+
ids: resolvedEntries.map((entry) => entry.id),
|
|
2192
|
+
};
|
|
2193
|
+
}
|
|
2194
|
+
if (result.intent === 'clear_all') {
|
|
2049
2195
|
return { kind: 'clear_request' };
|
|
2050
2196
|
}
|
|
2197
|
+
if (result.intent !== 'inspect' &&
|
|
2198
|
+
result.intent !== 'update' &&
|
|
2199
|
+
result.intent !== 'remove') {
|
|
2200
|
+
return null;
|
|
2201
|
+
}
|
|
2202
|
+
if (resolvedEntries === null || resolvedEntries === undefined)
|
|
2203
|
+
return null;
|
|
2204
|
+
if (resolvedEntries.length === 0)
|
|
2205
|
+
return { kind: 'no_match' };
|
|
2206
|
+
if (resolvedEntries.length > 1) {
|
|
2207
|
+
return {
|
|
2208
|
+
kind: 'ambiguous',
|
|
2209
|
+
ids: resolvedEntries.map((entry) => entry.id),
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
const entry = resolvedEntries[0];
|
|
2213
|
+
if (result.intent === 'inspect')
|
|
2214
|
+
return { kind: 'inspect', id: entry.id };
|
|
2215
|
+
if (result.intent === 'remove') {
|
|
2216
|
+
return {
|
|
2217
|
+
kind: 'natural_remove',
|
|
2218
|
+
id: entry.id,
|
|
2219
|
+
expectedText: entry.text,
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
const text = typeof result.memory === 'string' ? result.memory.trim() : '';
|
|
2223
|
+
if (text) {
|
|
2224
|
+
return {
|
|
2225
|
+
kind: 'natural_update',
|
|
2226
|
+
id: entry.id,
|
|
2227
|
+
text,
|
|
2228
|
+
expectedText: entry.text,
|
|
2229
|
+
};
|
|
2230
|
+
}
|
|
2051
2231
|
return null;
|
|
2052
2232
|
}
|
|
2053
2233
|
channelMemoryErrorMessage(error) {
|
|
@@ -2420,7 +2600,7 @@ export class ChannelBase {
|
|
|
2420
2600
|
let memoryIntent = parseChannelMemoryIntent(envelope.text);
|
|
2421
2601
|
if (!memoryIntent &&
|
|
2422
2602
|
this.shouldClassifyChannelMemoryIntent(envelope.text)) {
|
|
2423
|
-
memoryIntent = await this.classifyChannelMemoryIntent(envelope
|
|
2603
|
+
memoryIntent = await this.classifyChannelMemoryIntent(envelope);
|
|
2424
2604
|
}
|
|
2425
2605
|
if (memoryIntent) {
|
|
2426
2606
|
await this.handleChannelMemoryIntent(envelope, memoryIntent);
|