feat(fabric): dynamic-subscription via fabric-register openclaw tool
The plugin manifest declared `fabric-register` as a tool name but
tools.ts never registered it — recruitment fell through to the
standalone `/root/.openclaw/bin/fabric-register` binary, which writes
~/.openclaw/fabric-identity.json correctly but exits without notifying
the running plugin. That left fabric inbound's subscription as a
connect-time snapshot: every new agent required a gateway restart
between `new-agent` and the interview's sub-discussion or the message
had no socket to dispatch on.
Wire the full path:
- `FabricInbound.addAccount(entry)` — login, upsert identity, open socket(s),
track per-agent so removeAccount can teardown cleanly. Idempotent: a
second call replaces the previous socket (used post-onboard when the
agent rotates off the shared `interviewee` placeholder onto its own
apikey).
- `FabricInbound.removeAccount(agentId)` — disconnect sockets, clear
timers + per-agent caches.
- `__fabric.addAccount` / `removeAccount` — cross-plugin bridge so the
`fabric-register` tool can reach the live FabricInbound instance from
its tool handler context.
- `fabric-register` openclaw tool — validates apiKey, calls
`__fabric.addAccount`, returns `{ok, fabricUserId, displayName}`.
Accepts `agentId` arg so recruitment can bind on behalf of a
freshly-created agent before that agent has a session of its own.
Removes the "restart the gateway" advice from the ctxGuild
"agent not registered" error message — operators should now call the
tool path instead.
After this lands + the ClawSkills register-agent script flip (separate
commit), `recruitment.new-agent` -> interviewer sub-discussion runs
without a gateway restart in between.
This commit is contained in:
20
index.ts
20
index.ts
@@ -96,13 +96,29 @@ export default defineChannelPluginEntry({
|
||||
// fall back to "assume DM" — fail closed on unknown.
|
||||
{
|
||||
const _G = globalThis as Record<string, unknown>;
|
||||
_G['__fabric'] = { getChannelType };
|
||||
_G['__fabric'] = {
|
||||
getChannelType,
|
||||
// Dynamic-subscription bridges: tools (notably `fabric-register`)
|
||||
// call these to add/remove an account's inbound socket without
|
||||
// a gateway restart. Both delegate to the live FabricInbound
|
||||
// instance via the module-level `inbound` closure variable; the
|
||||
// closures stay valid across gateway_start / gateway_stop
|
||||
// because we re-assign the variable, not the property.
|
||||
addAccount: async (entry: { agentId: string; fabricApiKey: string }) => {
|
||||
if (!inbound) throw new Error('fabric inbound not ready yet (gateway not started?)');
|
||||
await inbound.addAccount(entry);
|
||||
},
|
||||
removeAccount: (agentId: string) => {
|
||||
if (!inbound) return;
|
||||
inbound.removeAccount(agentId);
|
||||
},
|
||||
};
|
||||
// Flush channel-meta cache when the gateway shuts down so
|
||||
// recently-recorded xType entries don't get lost.
|
||||
api.on('gateway_stop', () => {
|
||||
try { flushChannelMeta(); } catch { /* ignore */ }
|
||||
});
|
||||
api.logger.info('fabric: __fabric cross-plugin API installed (getChannelType)');
|
||||
api.logger.info('fabric: __fabric cross-plugin API installed (getChannelType + addAccount + removeAccount)');
|
||||
}
|
||||
|
||||
api.on('gateway_start', () => {
|
||||
|
||||
Reference in New Issue
Block a user