@xmoxmo/bncr 0.6.1 → 0.6.2
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/package.json +1 -1
- package/scripts/check-pack.mjs +1 -1
- package/scripts/selfcheck.mjs +1 -1
- package/src/channel.ts +16 -4
- package/src/messaging/inbound/context-facts.ts +88 -58
- package/src/messaging/inbound/{group-history.ts → conversation-history.ts} +92 -25
- package/src/messaging/inbound/dispatch.ts +73 -48
- package/src/messaging/inbound/native-command.ts +1 -1
- package/src/messaging/inbound/outbound-replay-cache.ts +82 -6
- package/src/messaging/inbound/scene-admin.ts +24 -9
- package/src/messaging/inbound/turn-context.ts +101 -37
- package/src/plugin/bridge-outbox-facade.ts +9 -0
- package/src/plugin/channel-components.ts +5 -5
- package/src/plugin/channel-runtime-builders-delivery.ts +2 -2
- package/src/plugin/channel-runtime-types.ts +9 -7
- package/src/plugin/inbound-acceptance.ts +9 -24
- package/src/plugin/inbound-handlers.ts +4 -4
- package/src/plugin/inbound-surface-handlers-group.ts +4 -2
- package/src/plugin/scene-registry.ts +4 -4
- package/src/plugin/state-store.ts +38 -34
- package/src/plugin/state-transient-runtime-group.ts +3 -3
|
@@ -4,8 +4,8 @@ import { emitBncrLogLine } from '../core/logging.ts';
|
|
|
4
4
|
import { formatDisplayScope, normalizeStoredSessionKey, parseRouteLike } from '../core/targets.ts';
|
|
5
5
|
import type { BncrRoute } from '../core/types.ts';
|
|
6
6
|
import type { BncrInboundParamsInput } from '../messaging/inbound/contracts.ts';
|
|
7
|
+
import type { BncrConversationHistoryMap } from '../messaging/inbound/conversation-history.ts';
|
|
7
8
|
import { dispatchBncrInbound } from '../messaging/inbound/dispatch.ts';
|
|
8
|
-
import type { BncrGroupHistoryMap } from '../messaging/inbound/group-history.ts';
|
|
9
9
|
import type { BncrOutboundReplayCache } from '../messaging/inbound/outbound-replay-cache.ts';
|
|
10
10
|
import { parseBncrInboundParams } from '../messaging/inbound/parse.ts';
|
|
11
11
|
import { OUTBOUND_FLUSH_REASON, OUTBOUND_FLUSH_TRIGGER } from '../messaging/outbound/reasons.ts';
|
|
@@ -211,7 +211,7 @@ export function createBncrInboundHandlersComponent(runtime: {
|
|
|
211
211
|
defaultAdminAgentId: Parameters<typeof createBncrInboundHandlers>[0]['defaultAdminAgentId'];
|
|
212
212
|
defaultPublicAgentId: Parameters<typeof createBncrInboundHandlers>[0]['defaultPublicAgentId'];
|
|
213
213
|
sceneRegistry: Parameters<typeof createBncrInboundHandlers>[0]['sceneRegistry'];
|
|
214
|
-
|
|
214
|
+
conversationHistories: BncrConversationHistoryMap;
|
|
215
215
|
outboundReplayCache: BncrOutboundReplayCache;
|
|
216
216
|
prepareInboundAcceptance: Parameters<
|
|
217
217
|
typeof createBncrInboundHandlers
|
|
@@ -257,7 +257,7 @@ export function createBncrInboundHandlersComponent(runtime: {
|
|
|
257
257
|
defaultAdminAgentId: runtime.defaultAdminAgentId,
|
|
258
258
|
defaultPublicAgentId: runtime.defaultPublicAgentId,
|
|
259
259
|
sceneRegistry: runtime.sceneRegistry,
|
|
260
|
-
|
|
260
|
+
conversationHistories: runtime.conversationHistories,
|
|
261
261
|
outboundReplayCache: runtime.outboundReplayCache,
|
|
262
262
|
prepareInboundAcceptance: runtime.prepareInboundAcceptance,
|
|
263
263
|
formatDisplayScope,
|
|
@@ -277,7 +277,7 @@ export function createBncrInboundHandlersComponent(runtime: {
|
|
|
277
277
|
shouldDispatch,
|
|
278
278
|
shouldAccumulate,
|
|
279
279
|
sceneRegistry,
|
|
280
|
-
|
|
280
|
+
conversationHistories,
|
|
281
281
|
outboundReplayCache,
|
|
282
282
|
defaultAdminAgentId,
|
|
283
283
|
defaultPublicAgentId,
|
|
@@ -293,7 +293,7 @@ export function createBncrInboundHandlersComponent(runtime: {
|
|
|
293
293
|
shouldDispatch,
|
|
294
294
|
shouldAccumulate,
|
|
295
295
|
sceneRegistry,
|
|
296
|
-
|
|
296
|
+
conversationHistories,
|
|
297
297
|
outboundReplayCache,
|
|
298
298
|
defaultAdminAgentId,
|
|
299
299
|
defaultPublicAgentId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { GatewayRequestHandlerOptions } from 'openclaw/plugin-sdk/core';
|
|
2
2
|
import type { BncrRoute, OutboxEntry } from '../core/types.ts';
|
|
3
|
-
import type {
|
|
3
|
+
import type { BncrConversationHistoryMap } from '../messaging/inbound/conversation-history.ts';
|
|
4
4
|
import type { BncrOutboundReplayCache } from '../messaging/inbound/outbound-replay-cache.ts';
|
|
5
5
|
import type { parseBncrInboundParams } from '../messaging/inbound/parse.ts';
|
|
6
6
|
import type { ReplyPayloadInput } from '../messaging/outbound/reply-enqueue.ts';
|
|
@@ -107,7 +107,7 @@ export function buildBncrInboundSurfaceRuntime(deps: {
|
|
|
107
107
|
}) => string;
|
|
108
108
|
defaultPublicAgentId: () => string;
|
|
109
109
|
sceneRegistry: Map<string, BncrSceneRecord>;
|
|
110
|
-
|
|
110
|
+
conversationHistories: BncrConversationHistoryMap;
|
|
111
111
|
outboundReplayCache: BncrOutboundReplayCache;
|
|
112
112
|
prepareInboundAcceptance: (args: {
|
|
113
113
|
parsed: ReturnType<typeof parseBncrInboundParams>;
|
|
@@ -73,29 +73,30 @@ export type BncrSceneRecord = {
|
|
|
73
73
|
lastSeenAt: number;
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
export type
|
|
76
|
+
export type BncrPersistedConversationHistoryEntry = {
|
|
77
77
|
sender: string;
|
|
78
78
|
senderId?: string;
|
|
79
|
+
role?: 'user' | 'assistant' | 'system';
|
|
79
80
|
body: string;
|
|
80
81
|
timestamp?: number;
|
|
81
82
|
messageId?: string;
|
|
82
|
-
media?:
|
|
83
|
+
media?: BncrPersistedConversationHistoryMediaEntry[];
|
|
83
84
|
};
|
|
84
85
|
|
|
85
|
-
export type
|
|
86
|
+
export type BncrPersistedConversationHistoryMediaEntry = {
|
|
86
87
|
path?: string;
|
|
87
88
|
contentType?: string;
|
|
88
89
|
kind?: 'image' | 'video' | 'audio' | 'document' | 'unknown';
|
|
89
90
|
messageId?: string;
|
|
90
91
|
};
|
|
91
92
|
|
|
92
|
-
export type
|
|
93
|
+
export type BncrPersistedConversationHistoryBucket = {
|
|
93
94
|
key: string;
|
|
94
|
-
entries:
|
|
95
|
+
entries: BncrPersistedConversationHistoryEntry[];
|
|
95
96
|
};
|
|
96
97
|
|
|
97
98
|
export type BncrPersistedOutboundReplayEntry = BncrOutboundReplayEntry;
|
|
98
|
-
export type BncrPersistedOutboundReplayMediaEntry =
|
|
99
|
+
export type BncrPersistedOutboundReplayMediaEntry = BncrPersistedConversationHistoryMediaEntry;
|
|
99
100
|
export type BncrPersistedOutboundReplayBucket = {
|
|
100
101
|
key: string;
|
|
101
102
|
entries: BncrPersistedOutboundReplayEntry[];
|
|
@@ -186,7 +187,8 @@ export type PersistedState = {
|
|
|
186
187
|
deadLetter: OutboxEntry[];
|
|
187
188
|
sessionRoutes: BncrPersistedSessionRoute[];
|
|
188
189
|
sceneRegistry?: BncrSceneRecord[];
|
|
189
|
-
|
|
190
|
+
conversationHistories?: BncrPersistedConversationHistoryBucket[];
|
|
191
|
+
groupHistories?: BncrPersistedConversationHistoryBucket[];
|
|
190
192
|
outboundReplayCache?: BncrPersistedOutboundReplayBucket[];
|
|
191
193
|
lastSessionByAccount?: BncrPersistedLastSession[];
|
|
192
194
|
lastActivityByAccount?: BncrPersistedAccountTimestamp[];
|
|
@@ -66,30 +66,12 @@ function shouldDispatchForScene(args: {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function shouldAccumulateForScene(args: {
|
|
69
|
-
|
|
69
|
+
shouldDispatch: boolean;
|
|
70
70
|
admission: ReturnType<typeof decideSceneAdmission>;
|
|
71
|
-
cfg: BncrChannelConfigRoot;
|
|
72
71
|
}) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const isBncrNativeCommand =
|
|
78
|
-
parseBncrNativeCommand(parsed.extracted.text, {
|
|
79
|
-
allowBareWhoami: parsed.isAdmin !== true,
|
|
80
|
-
}) !== null;
|
|
81
|
-
const isAdminOpenClawNativeCommand =
|
|
82
|
-
parsed.isAdmin === true &&
|
|
83
|
-
!isBncrNativeCommand &&
|
|
84
|
-
hasControlCommand(parsed.extracted.text, cfg as Parameters<typeof hasControlCommand>[1]);
|
|
85
|
-
if (isAdminOpenClawNativeCommand) return true;
|
|
86
|
-
|
|
87
|
-
const mode = admission.scene.groupReplyMode || 'admin';
|
|
88
|
-
// admin and all: no accumulation needed - messages are either dispatched directly or discarded
|
|
89
|
-
if (mode === 'admin') return false;
|
|
90
|
-
if (mode === 'all') return false;
|
|
91
|
-
// mention and hybrid: non-trigger messages accumulate for future context
|
|
92
|
-
return true;
|
|
72
|
+
if (args.shouldDispatch) return true;
|
|
73
|
+
const mode = args.admission.scene.groupReplyMode || 'admin';
|
|
74
|
+
return mode === 'mention' || mode === 'hybrid';
|
|
93
75
|
}
|
|
94
76
|
|
|
95
77
|
export async function prepareBncrInboundAcceptance(args: {
|
|
@@ -206,6 +188,9 @@ export async function prepareBncrInboundAcceptance(args: {
|
|
|
206
188
|
resolveAgentRoute: args.resolveAgentRoute,
|
|
207
189
|
});
|
|
208
190
|
|
|
191
|
+
const shouldDispatch = shouldDispatchForScene({ parsed, admission, cfg });
|
|
192
|
+
const shouldAccumulate = shouldAccumulateForScene({ shouldDispatch, admission });
|
|
193
|
+
|
|
209
194
|
return {
|
|
210
195
|
ok: true as const,
|
|
211
196
|
accountId,
|
|
@@ -213,8 +198,8 @@ export async function prepareBncrInboundAcceptance(args: {
|
|
|
213
198
|
inboundText,
|
|
214
199
|
hasMedia: Boolean(mediaBase64 || mediaPathFromTransfer),
|
|
215
200
|
resolvedAgentId: admission.agentId,
|
|
216
|
-
shouldDispatch
|
|
217
|
-
shouldAccumulate
|
|
201
|
+
shouldDispatch,
|
|
202
|
+
shouldAccumulate,
|
|
218
203
|
dispatchBy: resolveDispatchBy({ parsed, admission, cfg }),
|
|
219
204
|
};
|
|
220
205
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { GatewayRequestHandlerOptions } from 'openclaw/plugin-sdk/core';
|
|
2
2
|
import { buildCanonicalBncrSessionKey } from '../core/targets.ts';
|
|
3
3
|
import type { BncrConnection, BncrRoute } from '../core/types.ts';
|
|
4
|
-
import type {
|
|
4
|
+
import type { BncrConversationHistoryMap } from '../messaging/inbound/conversation-history.ts';
|
|
5
5
|
import type { BncrOutboundReplayCache } from '../messaging/inbound/outbound-replay-cache.ts';
|
|
6
6
|
import type { parseBncrInboundParams } from '../messaging/inbound/parse.ts';
|
|
7
7
|
import type { ReplyPayloadInput } from '../messaging/outbound/reply-enqueue.ts';
|
|
@@ -134,7 +134,7 @@ export type BncrInboundHandlersRuntime = {
|
|
|
134
134
|
}) => string;
|
|
135
135
|
defaultPublicAgentId: () => string;
|
|
136
136
|
sceneRegistry: Map<string, BncrSceneRecord>;
|
|
137
|
-
|
|
137
|
+
conversationHistories: BncrConversationHistoryMap;
|
|
138
138
|
outboundReplayCache: BncrOutboundReplayCache;
|
|
139
139
|
prepareInboundAcceptance: (args: {
|
|
140
140
|
parsed: ParsedInboundParams;
|
|
@@ -165,7 +165,7 @@ export type BncrInboundHandlersRuntime = {
|
|
|
165
165
|
shouldDispatch: boolean;
|
|
166
166
|
shouldAccumulate: boolean;
|
|
167
167
|
sceneRegistry: Map<string, BncrSceneRecord>;
|
|
168
|
-
|
|
168
|
+
conversationHistories: BncrConversationHistoryMap;
|
|
169
169
|
outboundReplayCache: BncrOutboundReplayCache;
|
|
170
170
|
defaultAdminAgentId: string;
|
|
171
171
|
defaultPublicAgentId: string;
|
|
@@ -335,7 +335,7 @@ export function createBncrInboundHandlers(runtime: Omit<BncrInboundHandlersRunti
|
|
|
335
335
|
shouldDispatch,
|
|
336
336
|
shouldAccumulate,
|
|
337
337
|
sceneRegistry: runtime.sceneRegistry,
|
|
338
|
-
|
|
338
|
+
conversationHistories: runtime.conversationHistories,
|
|
339
339
|
outboundReplayCache: runtime.outboundReplayCache,
|
|
340
340
|
defaultAdminAgentId,
|
|
341
341
|
defaultPublicAgentId: runtime.defaultPublicAgentId(),
|
|
@@ -86,7 +86,9 @@ export function createBncrInboundSurfaceHandlersGroup(runtime: {
|
|
|
86
86
|
typeof createBncrInboundHandlersComponent
|
|
87
87
|
>[0]['defaultPublicAgentId'];
|
|
88
88
|
sceneRegistry: Parameters<typeof createBncrInboundHandlersComponent>[0]['sceneRegistry'];
|
|
89
|
-
|
|
89
|
+
conversationHistories: Parameters<
|
|
90
|
+
typeof createBncrInboundHandlersComponent
|
|
91
|
+
>[0]['conversationHistories'];
|
|
90
92
|
outboundReplayCache: BncrOutboundReplayCache;
|
|
91
93
|
prepareInboundAcceptance: Parameters<
|
|
92
94
|
typeof createBncrInboundHandlersComponent
|
|
@@ -153,7 +155,7 @@ export function createBncrInboundSurfaceHandlersGroup(runtime: {
|
|
|
153
155
|
defaultAdminAgentId: runtime.defaultAdminAgentId,
|
|
154
156
|
defaultPublicAgentId: runtime.defaultPublicAgentId,
|
|
155
157
|
sceneRegistry: runtime.sceneRegistry,
|
|
156
|
-
|
|
158
|
+
conversationHistories: runtime.conversationHistories,
|
|
157
159
|
outboundReplayCache: runtime.outboundReplayCache,
|
|
158
160
|
prepareInboundAcceptance: runtime.prepareInboundAcceptance,
|
|
159
161
|
logInboundSummary: runtime.logInboundSummary,
|
|
@@ -56,8 +56,8 @@ function buildSceneRecord(args: {
|
|
|
56
56
|
...(kind === 'group' && parsed.groupName ? { groupName: parsed.groupName } : {}),
|
|
57
57
|
...(agentId ? { agentId } : {}),
|
|
58
58
|
...(kind === 'group' ? { groupReplyMode: defaultGroupReplyMode(kind) } : {}),
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
historyLimit: 50,
|
|
60
|
+
historyForce: true,
|
|
61
61
|
lastSeenAt,
|
|
62
62
|
};
|
|
63
63
|
}
|
|
@@ -90,8 +90,8 @@ export function decideSceneAdmission(args: {
|
|
|
90
90
|
...(kind === 'group' && !existing.groupReplyMode
|
|
91
91
|
? { groupReplyMode: defaultGroupReplyMode(kind) }
|
|
92
92
|
: {}),
|
|
93
|
-
...(
|
|
94
|
-
...(
|
|
93
|
+
...(existing.historyLimit === undefined ? { historyLimit: 50 } : {}),
|
|
94
|
+
...(existing.historyForce === undefined ? { historyForce: true } : {}),
|
|
95
95
|
lastSeenAt: now,
|
|
96
96
|
} satisfies BncrSceneRecord;
|
|
97
97
|
|
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
import type {
|
|
15
15
|
BncrGroupReplyMode,
|
|
16
16
|
BncrPersistedAccountTimestamp,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
BncrPersistedConversationHistoryBucket,
|
|
18
|
+
BncrPersistedConversationHistoryEntry,
|
|
19
|
+
BncrPersistedConversationHistoryMediaEntry,
|
|
20
20
|
BncrPersistedLastSession,
|
|
21
21
|
BncrPersistedOutboundReplayBucket,
|
|
22
22
|
BncrPersistedOutboundReplayEntry,
|
|
@@ -26,13 +26,14 @@ import type {
|
|
|
26
26
|
} from './channel-runtime-types.ts';
|
|
27
27
|
|
|
28
28
|
const GROUP_REPLY_MODES = new Set<BncrGroupReplyMode>(['admin', 'mention', 'hybrid', 'all']);
|
|
29
|
-
const
|
|
29
|
+
const DEFAULT_PERSISTED_CONVERSATION_HISTORY_LIMIT = 50;
|
|
30
30
|
|
|
31
31
|
type BncrPersistedStateStoreInput = {
|
|
32
32
|
outbox?: unknown;
|
|
33
33
|
deadLetter?: unknown;
|
|
34
34
|
sessionRoutes?: unknown;
|
|
35
35
|
sceneRegistry?: unknown;
|
|
36
|
+
conversationHistories?: unknown;
|
|
36
37
|
groupHistories?: unknown;
|
|
37
38
|
outboundReplayCache?: unknown;
|
|
38
39
|
// Legacy persisted key from before the outboundReplayCache rename.
|
|
@@ -48,8 +49,8 @@ type PersistedAccountTimestampInput = Partial<BncrPersistedAccountTimestamp>;
|
|
|
48
49
|
type PersistedLastSessionInput = Partial<BncrPersistedLastSession>;
|
|
49
50
|
type PersistedSessionRouteInput = Partial<BncrPersistedSessionRoute>;
|
|
50
51
|
type PersistedSceneRecordInput = Partial<BncrSceneRecord>;
|
|
51
|
-
type
|
|
52
|
-
type
|
|
52
|
+
type PersistedConversationHistoryBucketInput = Partial<BncrPersistedConversationHistoryBucket>;
|
|
53
|
+
type PersistedConversationHistoryEntryInput = Partial<BncrPersistedConversationHistoryEntry>;
|
|
53
54
|
type PersistedOutboundReplayBucketInput = Partial<BncrPersistedOutboundReplayBucket>;
|
|
54
55
|
type PersistedOutboundReplayEntryInput = Partial<BncrOutboundReplayEntry>;
|
|
55
56
|
|
|
@@ -75,7 +76,7 @@ export function createBncrStateStore(runtime: {
|
|
|
75
76
|
maxSessionRouteEntries: number;
|
|
76
77
|
maxAccountActivityEntries: number;
|
|
77
78
|
sceneRegistry: Map<string, BncrSceneRecord>;
|
|
78
|
-
|
|
79
|
+
conversationHistories: Map<string, BncrPersistedConversationHistoryEntry[]>;
|
|
79
80
|
outboundReplayCache?: Map<string, BncrPersistedOutboundReplayEntry[]>;
|
|
80
81
|
outbox: Map<string, OutboxEntry>;
|
|
81
82
|
getDeadLetter: () => OutboxEntry[];
|
|
@@ -92,16 +93,16 @@ export function createBncrStateStore(runtime: {
|
|
|
92
93
|
const outboundReplayCache =
|
|
93
94
|
runtime.outboundReplayCache ?? new Map<string, BncrPersistedOutboundReplayEntry[]>();
|
|
94
95
|
|
|
95
|
-
function
|
|
96
|
+
function resolvePersistedConversationHistoryLimit(key: string): number {
|
|
96
97
|
const scene = runtime.sceneRegistry.get(key);
|
|
97
|
-
const sceneLimit = scene?.
|
|
98
|
+
const sceneLimit = scene?.historyLimit;
|
|
98
99
|
if (typeof sceneLimit === 'number' && Number.isFinite(sceneLimit) && sceneLimit >= 0) {
|
|
99
100
|
return Math.max(
|
|
100
|
-
|
|
101
|
+
DEFAULT_PERSISTED_CONVERSATION_HISTORY_LIMIT,
|
|
101
102
|
Math.ceil(Math.floor(sceneLimit) * 1.2),
|
|
102
103
|
);
|
|
103
104
|
}
|
|
104
|
-
return
|
|
105
|
+
return DEFAULT_PERSISTED_CONVERSATION_HISTORY_LIMIT;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
function loadPersistedSceneRegistry(persisted: unknown): void {
|
|
@@ -165,19 +166,19 @@ export function createBncrStateStore(runtime: {
|
|
|
165
166
|
|
|
166
167
|
function loadPersistedHistoryBuckets(
|
|
167
168
|
persisted: unknown,
|
|
168
|
-
target: Map<string,
|
|
169
|
+
target: Map<string, BncrPersistedConversationHistoryEntry[]>,
|
|
169
170
|
resolveLimit: (key: string) => number,
|
|
170
171
|
): void {
|
|
171
172
|
target.clear();
|
|
172
173
|
const buckets = Array.isArray(persisted)
|
|
173
|
-
? (persisted as
|
|
174
|
+
? (persisted as PersistedConversationHistoryBucketInput[])
|
|
174
175
|
: [];
|
|
175
176
|
for (const bucket of buckets) {
|
|
176
177
|
const key = runtime.asString(bucket?.key || '').trim();
|
|
177
178
|
if (!key) continue;
|
|
178
|
-
const entries:
|
|
179
|
+
const entries: BncrPersistedConversationHistoryEntry[] = [];
|
|
179
180
|
const rawEntries = Array.isArray(bucket?.entries)
|
|
180
|
-
? (bucket.entries as
|
|
181
|
+
? (bucket.entries as PersistedConversationHistoryEntryInput[])
|
|
181
182
|
: [];
|
|
182
183
|
for (const entry of rawEntries) {
|
|
183
184
|
const sender = runtime.asString(entry?.sender || '').trim();
|
|
@@ -186,9 +187,9 @@ export function createBncrStateStore(runtime: {
|
|
|
186
187
|
const timestamp = runtime.finiteNumberOr(entry?.timestamp, 0);
|
|
187
188
|
const messageId = runtime.asString(entry?.messageId || '').trim();
|
|
188
189
|
|
|
189
|
-
const media:
|
|
190
|
+
const media: BncrPersistedConversationHistoryMediaEntry[] = [];
|
|
190
191
|
const rawMedia = Array.isArray(entry?.media)
|
|
191
|
-
? (entry.media as Partial<
|
|
192
|
+
? (entry.media as Partial<BncrPersistedConversationHistoryMediaEntry>[])
|
|
192
193
|
: [];
|
|
193
194
|
for (const item of rawMedia) {
|
|
194
195
|
const path = runtime.asString(item?.path || '').trim();
|
|
@@ -196,20 +197,23 @@ export function createBncrStateStore(runtime: {
|
|
|
196
197
|
const contentType = runtime.asString(item?.contentType || '').trim();
|
|
197
198
|
const kind = runtime.asString(item?.kind || '').trim();
|
|
198
199
|
const mediaMessageId = runtime.asString(item?.messageId || '').trim();
|
|
199
|
-
const normalizedMedia:
|
|
200
|
+
const normalizedMedia: BncrPersistedConversationHistoryMediaEntry = {
|
|
200
201
|
path,
|
|
201
202
|
...(contentType ? { contentType } : {}),
|
|
202
|
-
...(kind ? { kind: kind as
|
|
203
|
+
...(kind ? { kind: kind as BncrPersistedConversationHistoryMediaEntry['kind'] } : {}),
|
|
203
204
|
...(mediaMessageId ? { messageId: mediaMessageId } : {}),
|
|
204
205
|
};
|
|
205
206
|
media.push(normalizedMedia);
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
const normalizedEntry:
|
|
209
|
+
const normalizedEntry: BncrPersistedConversationHistoryEntry = {
|
|
209
210
|
sender,
|
|
210
211
|
...(runtime.asString(entry?.senderId || '').trim()
|
|
211
212
|
? { senderId: runtime.asString(entry?.senderId || '').trim() }
|
|
212
213
|
: {}),
|
|
214
|
+
...(entry?.role === 'user' || entry?.role === 'assistant' || entry?.role === 'system'
|
|
215
|
+
? { role: entry.role }
|
|
216
|
+
: {}),
|
|
213
217
|
body,
|
|
214
218
|
...(timestamp > 0 ? { timestamp } : {}),
|
|
215
219
|
...(messageId ? { messageId } : {}),
|
|
@@ -224,9 +228,9 @@ export function createBncrStateStore(runtime: {
|
|
|
224
228
|
}
|
|
225
229
|
}
|
|
226
230
|
|
|
227
|
-
function
|
|
228
|
-
loadPersistedHistoryBuckets(persisted, runtime.
|
|
229
|
-
|
|
231
|
+
function loadPersistedConversationHistories(persisted: unknown): void {
|
|
232
|
+
loadPersistedHistoryBuckets(persisted, runtime.conversationHistories, (key) =>
|
|
233
|
+
resolvePersistedConversationHistoryLimit(key),
|
|
230
234
|
);
|
|
231
235
|
}
|
|
232
236
|
|
|
@@ -261,9 +265,9 @@ export function createBncrStateStore(runtime: {
|
|
|
261
265
|
groupId: entry?.route?.groupId,
|
|
262
266
|
userId: entry?.route?.userId,
|
|
263
267
|
});
|
|
264
|
-
const media:
|
|
268
|
+
const media: BncrPersistedConversationHistoryMediaEntry[] = [];
|
|
265
269
|
const rawMedia = Array.isArray(entry?.media)
|
|
266
|
-
? (entry.media as Partial<
|
|
270
|
+
? (entry.media as Partial<BncrPersistedConversationHistoryMediaEntry>[])
|
|
267
271
|
: [];
|
|
268
272
|
for (const item of rawMedia) {
|
|
269
273
|
const path = runtime.asString(item?.path || '').trim();
|
|
@@ -274,7 +278,7 @@ export function createBncrStateStore(runtime: {
|
|
|
274
278
|
media.push({
|
|
275
279
|
path,
|
|
276
280
|
...(contentType ? { contentType } : {}),
|
|
277
|
-
...(kind ? { kind: kind as
|
|
281
|
+
...(kind ? { kind: kind as BncrPersistedConversationHistoryMediaEntry['kind'] } : {}),
|
|
278
282
|
...(mediaMessageId ? { messageId: mediaMessageId } : {}),
|
|
279
283
|
});
|
|
280
284
|
}
|
|
@@ -305,7 +309,7 @@ export function createBncrStateStore(runtime: {
|
|
|
305
309
|
}
|
|
306
310
|
|
|
307
311
|
function dumpPersistedHistoryBuckets(
|
|
308
|
-
source: Map<string,
|
|
312
|
+
source: Map<string, BncrPersistedConversationHistoryEntry[]>,
|
|
309
313
|
resolveLimit: (key: string) => number,
|
|
310
314
|
) {
|
|
311
315
|
return Array.from(source.entries()).map(([key, entries]) => ({
|
|
@@ -314,9 +318,9 @@ export function createBncrStateStore(runtime: {
|
|
|
314
318
|
}));
|
|
315
319
|
}
|
|
316
320
|
|
|
317
|
-
function
|
|
318
|
-
return dumpPersistedHistoryBuckets(runtime.
|
|
319
|
-
|
|
321
|
+
function dumpPersistedConversationHistories() {
|
|
322
|
+
return dumpPersistedHistoryBuckets(runtime.conversationHistories, (key) =>
|
|
323
|
+
resolvePersistedConversationHistoryLimit(key),
|
|
320
324
|
);
|
|
321
325
|
}
|
|
322
326
|
|
|
@@ -474,7 +478,7 @@ export function createBncrStateStore(runtime: {
|
|
|
474
478
|
|
|
475
479
|
loadPersistedSessionRoutes(data.sessionRoutes);
|
|
476
480
|
loadPersistedSceneRegistry(data.sceneRegistry);
|
|
477
|
-
|
|
481
|
+
loadPersistedConversationHistories(data.conversationHistories ?? data.groupHistories);
|
|
478
482
|
loadPersistedOutboundReplayCache(data.outboundReplayCache ?? data.messageCache);
|
|
479
483
|
loadPersistedLastSessionMap(data.lastSessionByAccount);
|
|
480
484
|
loadPersistedAccountTimestampMap(runtime.lastActivityByAccount, data.lastActivityByAccount);
|
|
@@ -494,7 +498,7 @@ export function createBncrStateStore(runtime: {
|
|
|
494
498
|
deadLetter: runtime.getDeadLetter().slice(-runtime.maxDeadLetterEntries),
|
|
495
499
|
sessionRoutes: dumpPersistedSessionRoutes(),
|
|
496
500
|
sceneRegistry: dumpPersistedSceneRegistry(),
|
|
497
|
-
|
|
501
|
+
conversationHistories: dumpPersistedConversationHistories(),
|
|
498
502
|
outboundReplayCache: dumpPersistedOutboundReplayCache(),
|
|
499
503
|
lastSessionByAccount: dumpPersistedLastSessionMap(),
|
|
500
504
|
lastActivityByAccount: dumpPersistedAccountTimestampMap(runtime.lastActivityByAccount),
|
|
@@ -515,8 +519,8 @@ export function createBncrStateStore(runtime: {
|
|
|
515
519
|
dumpPersistedSessionRoutes,
|
|
516
520
|
loadPersistedSceneRegistry,
|
|
517
521
|
dumpPersistedSceneRegistry,
|
|
518
|
-
|
|
519
|
-
|
|
522
|
+
loadPersistedConversationHistories,
|
|
523
|
+
dumpPersistedConversationHistories,
|
|
520
524
|
loadPersistedOutboundReplayCache,
|
|
521
525
|
dumpPersistedOutboundReplayCache,
|
|
522
526
|
backfillAccountActivityFromSessionRoutes,
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
OutboxEntry,
|
|
8
8
|
} from '../core/types.ts';
|
|
9
9
|
import type {
|
|
10
|
-
|
|
10
|
+
BncrPersistedConversationHistoryEntry,
|
|
11
11
|
BncrPersistedOutboundReplayEntry,
|
|
12
12
|
BncrSceneRecord,
|
|
13
13
|
} from './channel-runtime-types.ts';
|
|
@@ -37,7 +37,7 @@ export function createBncrStateTransientRuntimeGroup(runtime: {
|
|
|
37
37
|
maxSessionRouteEntries: number;
|
|
38
38
|
maxAccountActivityEntries: number;
|
|
39
39
|
sceneRegistry: Map<string, BncrSceneRecord>;
|
|
40
|
-
|
|
40
|
+
conversationHistories: Map<string, BncrPersistedConversationHistoryEntry[]>;
|
|
41
41
|
outboundReplayCache?: Map<string, BncrPersistedOutboundReplayEntry[]>;
|
|
42
42
|
outbox: Map<string, OutboxEntry>;
|
|
43
43
|
getDeadLetter: () => OutboxEntry[];
|
|
@@ -78,7 +78,7 @@ export function createBncrStateTransientRuntimeGroup(runtime: {
|
|
|
78
78
|
maxSessionRouteEntries: runtime.maxSessionRouteEntries,
|
|
79
79
|
maxAccountActivityEntries: runtime.maxAccountActivityEntries,
|
|
80
80
|
sceneRegistry: runtime.sceneRegistry,
|
|
81
|
-
|
|
81
|
+
conversationHistories: runtime.conversationHistories,
|
|
82
82
|
outboundReplayCache:
|
|
83
83
|
runtime.outboundReplayCache ?? new Map<string, BncrPersistedOutboundReplayEntry[]>(),
|
|
84
84
|
outbox: runtime.outbox,
|