Merge pull request 'fix(routing): resolveAgentRoute uses binding.accountId, not agent_id' (#11) from fix/routing-use-binding-accountid into main

This commit was merged in pull request #11.
This commit is contained in:
h z
2026-05-31 19:33:13 +00:00

View File

@@ -51,6 +51,30 @@ type FabricMessage = {
xType?: string;
};
// Walk cfg.bindings for the entry that ties `agentId` to a fabric account.
// Returns the binding's match.accountId (the slot label routing keys on);
// returns undefined when the agent has no explicit fabric binding so the
// caller can fall back to agentId without changing pre-existing semantics
// for agents whose binding accountId == agent_id anyway.
function findFabricBindingAccountId(cfg: unknown, agentId: string): string | undefined {
const bindings = (cfg as { bindings?: Array<{
agentId?: string;
match?: { channel?: string; accountId?: string };
}> })?.bindings;
if (!Array.isArray(bindings)) return undefined;
for (const b of bindings) {
if (
b?.agentId === agentId &&
b?.match?.channel === 'fabric' &&
typeof b?.match?.accountId === 'string' &&
b.match.accountId.length > 0
) {
return b.match.accountId;
}
}
return undefined;
}
export class FabricInbound {
private sockets: Socket[] = [];
private seen = new Set<string>();
@@ -541,10 +565,22 @@ export class FabricInbound {
// (commands-handlers `isDirectMessage` checks ChatType==='direct')
// misclassifies the turn.
const { peerKind, chatType } = fabricPeerRoutingForXType(m.xType);
// resolveAgentRoute needs the *binding* accountId (the channel-side
// slot name) — not the openclaw agentId. For most agents the binding
// is `{agentId: X, match: {channel: fabric, accountId: X}}` so the
// two coincide; but for shared-placeholder cases (e.g. the recruitment
// `interviewee` slot bound to multiple agents over its lifetime) the
// binding accountId is the slot label ("interviewee", "Neon", …) not
// the agent_id. Passing agentId there returned bindings=0 and silently
// fell back to `main`, hijacking sub-discussion turns. Look up the
// agent's fabric binding accountId here; fall back to agentId when no
// explicit binding exists (preserves prior behavior for agents with
// no fabric binding declared).
const bindingAccountId = findFabricBindingAccountId(this.cfg, agentId) ?? agentId;
const route = core.channel.routing.resolveAgentRoute({
cfg: this.cfg,
channel: 'fabric',
accountId: agentId,
accountId: bindingAccountId,
peer: { kind: peerKind, id: channelId },
});
const storePath = core.channel.session.resolveStorePath(cfg.session?.store, {