@xmoxmo/bncr 0.6.8 → 0.6.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmoxmo/bncr",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/channel.ts CHANGED
@@ -201,6 +201,7 @@ import {
201
201
  createBncrOutboxDiagnosticsHelpers,
202
202
  createBncrRuntimeAckObservabilityBuilder,
203
203
  } from './plugin/runtime-diagnostics-snapshot.ts';
204
+ import { buildRouteSceneKey } from './plugin/scene-registry.ts';
204
205
  import { BNCR_SETUP_SURFACE } from './plugin/setup.ts';
205
206
  import type { BncrHistoryShardRow } from './plugin/sqlite-state.ts';
206
207
  import { createBncrStateTransientRuntimeGroup } from './plugin/state-transient-runtime-group.ts';
@@ -309,6 +310,12 @@ class BncrBridgeRuntime {
309
310
  getSceneRegistry(): Map<string, BncrSceneRecord> {
310
311
  return this.sceneRegistry;
311
312
  }
313
+ resolveOutboundAgentId(route: BncrRoute): string {
314
+ return (
315
+ asString(this.sceneRegistry.get(buildRouteSceneKey(route))?.agentId).trim() ||
316
+ this.defaultPublicAgentId()
317
+ );
318
+ }
312
319
  private conversationHistories: BncrConversationHistoryMap = new Map();
313
320
  private outboundReplayCache: BncrOutboundReplayCache = new Map();
314
321
  private routeAliases = new Map<
@@ -27,12 +27,11 @@ type BncrOutboundSessionRoute = ChannelOutboundSessionRoute & BncrChannelRouteRe
27
27
  type ResolveBncrOutboundSessionRouteParams = {
28
28
  cfg: BncrChannelConfigRoot;
29
29
  channel: string;
30
- agentId: string;
31
30
  accountId?: string;
32
31
  target: string;
33
32
  resolvedTarget?: { to?: string } | null;
34
33
  threadId?: string | number | null;
35
- canonicalAgentId: string;
34
+ resolveAgentId: (route: BncrRoute) => string;
36
35
  resolveRouteBySession?: (raw: string, accountId: string) => BncrRoute | null;
37
36
  };
38
37
 
@@ -76,15 +75,14 @@ export function resolveBncrOutboundSessionRoute(params: ResolveBncrOutboundSessi
76
75
 
77
76
  if (!route) return null;
78
77
 
79
- const canonicalAgentId =
80
- asString(params.canonicalAgentId).trim() || asString(params.agentId).trim() || 'main';
78
+ const agentId = asString(params.resolveAgentId(route)).trim() || 'public';
81
79
  const peerId = routeScopeToHex(route);
82
- const sessionKey = buildCanonicalBncrSessionKey(route, canonicalAgentId);
80
+ const sessionKey = buildCanonicalBncrSessionKey(route, agentId);
83
81
  const displayTo = formatDisplayScope(route);
84
82
 
85
83
  const built = buildOpenClawChannelOutboundSessionRoute({
86
84
  cfg: params.cfg,
87
- agentId: canonicalAgentId,
85
+ agentId,
88
86
  channel: params.channel,
89
87
  accountId: params.accountId,
90
88
  peer: {
@@ -34,6 +34,7 @@ export type BncrChannelPluginBridge = {
34
34
  channelId: string;
35
35
  peer: { kind: 'direct'; id: string };
36
36
  }) => string;
37
+ resolveOutboundAgentId: (route: BncrRoute) => string;
37
38
  resolveRouteBySession: (raw: string, accountId: string) => BncrRoute | null;
38
39
  getChannelSummary: (defaultAccountId: string) => Record<string, unknown>;
39
40
  getAccountRuntimeSnapshot: (accountId: string) => BncrStatusRuntimeSnapshot;
@@ -90,14 +91,7 @@ export function createBncrChannelPluginBridgeGroup(runtime: {
90
91
  const getMessagingBridge = () => {
91
92
  const bridge = runtime.getBridge();
92
93
  return {
93
- canonicalAgentId: undefined,
94
- ensureCanonicalAgentId: (params: { cfg: BncrChannelConfigRoot; accountId: string }) =>
95
- bridge.ensureCanonicalAgentId({
96
- cfg: params.cfg,
97
- accountId: params.accountId,
98
- channelId: runtime.channelId,
99
- peer: { kind: 'direct', id: params.accountId },
100
- }),
94
+ resolveOutboundAgentId: (route: BncrRoute) => bridge.resolveOutboundAgentId(route),
101
95
  resolveRouteBySession: (raw: string, accountId: string) =>
102
96
  bridge.resolveRouteBySession(raw, accountId),
103
97
  };
@@ -3,13 +3,13 @@ import { Type } from 'typebox';
3
3
  import { listAccountIds, normalizeAccountId, resolveAccount } from '../core/accounts.ts';
4
4
  import { BncrConfigSchema } from '../core/config-schema.ts';
5
5
  import { resolveBncrChannelPolicy } from '../core/policy.ts';
6
+ import type { BncrRoute } from '../core/types.ts';
6
7
  import type { ReplyPayloadInput } from '../messaging/outbound/reply-enqueue.ts';
7
8
  import type { OutboundReplyTargetPolicy } from '../messaging/outbound/reply-target-policy.ts';
8
9
  import type { OpenClawChannelToolSend, openClawJsonResult } from '../openclaw/sdk-helpers.ts';
9
10
  import { readOpenClawStringParam } from '../openclaw/sdk-helpers.ts';
10
11
  import type { BncrBridgeCallBridge } from './bridge-call.ts';
11
12
  import type {
12
- BncrChannelConfigRoot,
13
13
  BncrChannelSendContext,
14
14
  BncrMessageToolSchemaContribution,
15
15
  BncrSceneRecord,
@@ -81,8 +81,7 @@ export function createBncrChannelPluginSurfaceGroup(runtime: {
81
81
  };
82
82
  getOutboundBridge: () => BncrOutboundBridge;
83
83
  getMessagingBridge: () => {
84
- canonicalAgentId: undefined;
85
- ensureCanonicalAgentId: (params: { cfg: BncrChannelConfigRoot; accountId: string }) => string;
84
+ resolveOutboundAgentId: (route: BncrRoute) => string;
86
85
  resolveRouteBySession: (raw: string, accountId: string) => BncrVerifiedTarget['route'] | null;
87
86
  };
88
87
  getStatusBridge: () => {
@@ -15,8 +15,7 @@ function formatBncrHumanDisplay(route: BncrRoute): string {
15
15
  }
16
16
 
17
17
  type BncrMessagingRuntimeBridge = {
18
- canonicalAgentId?: string;
19
- ensureCanonicalAgentId: (params: { cfg: BncrChannelConfigRoot; accountId: string }) => string;
18
+ resolveOutboundAgentId: (route: BncrRoute) => string;
20
19
  resolveRouteBySession: (raw: string, accountId: string) => BncrRoute | null;
21
20
  };
22
21
 
@@ -44,6 +43,7 @@ type BncrMessagingSessionTargetArgs = {
44
43
  };
45
44
 
46
45
  type BncrMessagingOutboundSessionRouteArgs = {
46
+ /** Host-reported owner. BNCR resolves ownership from its persisted scene registry instead. */
47
47
  agentId: string;
48
48
  target: string;
49
49
  resolvedTarget?: { to?: string } | null;
@@ -99,21 +99,9 @@ function resolveMessagingAccountId(accountId: unknown) {
99
99
  return normalizeAccountId(asSanitizedString(accountId || BNCR_DEFAULT_ACCOUNT_ID));
100
100
  }
101
101
 
102
- function resolveMessagingCanonicalAgentId(
103
- runtimeBridge: BncrMessagingRuntimeBridge,
104
- cfg: BncrChannelConfigRoot,
105
- accountId: string,
106
- ) {
107
- return runtimeBridge.canonicalAgentId || runtimeBridge.ensureCanonicalAgentId({ cfg, accountId });
108
- }
109
-
110
- export function createBncrMessagingExplicitTargetParser(
111
- getBridge: () => BncrMessagingRuntimeBridge,
112
- ) {
102
+ export function createBncrMessagingExplicitTargetParser() {
113
103
  return ({ raw }: BncrMessagingExplicitTargetArgs) => {
114
- const runtimeBridge = getBridge();
115
- const canonicalAgentId = runtimeBridge.canonicalAgentId || 'main';
116
- const parsed = parseExplicitTarget(asSanitizedString(raw).trim(), { canonicalAgentId });
104
+ const parsed = parseExplicitTarget(asSanitizedString(raw).trim());
117
105
  if (!parsed) return null;
118
106
  const chatType: ChatType = parsed.route?.groupId ? 'group' : 'direct';
119
107
  return {
@@ -125,16 +113,12 @@ export function createBncrMessagingExplicitTargetParser(
125
113
  };
126
114
  }
127
115
 
128
- export function createBncrMessagingSessionTargetResolver(
129
- getBridge: () => BncrMessagingRuntimeBridge,
130
- ) {
116
+ export function createBncrMessagingSessionTargetResolver() {
131
117
  return ({ id }: BncrMessagingSessionTargetArgs) => {
132
118
  const raw = asSanitizedString(id).trim();
133
119
  if (!raw) return undefined;
134
- const runtimeBridge = getBridge();
135
- const canonicalAgentId = runtimeBridge.canonicalAgentId || 'main';
136
120
 
137
- const parsed = parseExplicitTarget(raw, { canonicalAgentId });
121
+ const parsed = parseExplicitTarget(raw);
138
122
  if (!parsed) {
139
123
  return raw || undefined;
140
124
  }
@@ -146,17 +130,10 @@ export function createBncrMessagingOutboundSessionRouteResolver(
146
130
  getBridge: () => BncrMessagingRuntimeBridge,
147
131
  ) {
148
132
  return (params: BncrMessagingOutboundSessionRouteArgs) => {
149
- const accountId = resolveMessagingAccountId(params?.accountId);
150
133
  const runtimeBridge = getBridge();
151
- const canonicalAgentId = resolveMessagingCanonicalAgentId(
152
- runtimeBridge,
153
- params?.cfg,
154
- accountId,
155
- );
156
134
  return resolveBncrOutboundSessionRoute({
157
135
  channel: 'bncr',
158
136
  cfg: params.cfg,
159
- agentId: params.agentId,
160
137
  accountId: params.accountId ?? undefined,
161
138
  target: params.target,
162
139
  resolvedTarget: params.resolvedTarget,
@@ -164,7 +141,7 @@ export function createBncrMessagingOutboundSessionRouteResolver(
164
141
  params.threadId === null || params.threadId === undefined
165
142
  ? undefined
166
143
  : asSanitizedString(params.threadId),
167
- canonicalAgentId,
144
+ resolveAgentId: (route) => runtimeBridge.resolveOutboundAgentId(route),
168
145
  resolveRouteBySession: (raw: string, acc: string) =>
169
146
  runtimeBridge.resolveRouteBySession(raw, acc),
170
147
  });
@@ -175,9 +152,9 @@ export function createBncrMessagingSurface(getBridge: () => BncrMessagingRuntime
175
152
  return {
176
153
  // 接收任意标签输入;不在 normalize 阶段做格式门槛,统一下沉到发送前验证。
177
154
  normalizeTarget: normalizeBncrMessagingTarget,
178
- parseExplicitTarget: createBncrMessagingExplicitTargetParser(getBridge),
155
+ parseExplicitTarget: createBncrMessagingExplicitTargetParser(),
179
156
  formatTargetDisplay: formatBncrMessagingTargetDisplay,
180
- resolveSessionTarget: createBncrMessagingSessionTargetResolver(getBridge),
157
+ resolveSessionTarget: createBncrMessagingSessionTargetResolver(),
181
158
  resolveOutboundSessionRoute: createBncrMessagingOutboundSessionRouteResolver(getBridge),
182
159
  targetResolver: createBncrMessagingTargetResolver(getBridge),
183
160
  };
@@ -1,3 +1,5 @@
1
+ import type { BncrRoute } from '../core/types.ts';
2
+ import { asString } from '../core/value-sanitize.ts';
1
3
  import type {
2
4
  BncrGroupReplyMode,
3
5
  BncrSceneKind,
@@ -30,10 +32,19 @@ function defaultGroupReplyMode(kind: BncrSceneKind): BncrGroupReplyMode | undefi
30
32
  return kind === 'group' ? 'admin' : undefined;
31
33
  }
32
34
 
35
+ export function buildRouteSceneKey(route: BncrRoute): string {
36
+ const platform = asString(route.platform).trim();
37
+ const groupId = asString(route.groupId).trim() || '0';
38
+ const userId = asString(route.userId).trim() || '0';
39
+ return groupId !== '0' ? `${platform}:${groupId}` : `${platform}:${userId}`;
40
+ }
41
+
33
42
  export function buildSceneKey(parsed: ParsedInbound): string {
34
- return parsed.peer.kind === 'group'
35
- ? `${parsed.platform}:${parsed.groupId}`
36
- : `${parsed.platform}:${parsed.userId}`;
43
+ return buildRouteSceneKey({
44
+ platform: parsed.platform,
45
+ groupId: parsed.groupId || '0',
46
+ userId: parsed.userId || '0',
47
+ });
37
48
  }
38
49
 
39
50
  function buildSceneRecord(args: {