@bouncer-protocol/bouncer 0.3.0 → 0.3.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/dist/index.js CHANGED
@@ -113,12 +113,18 @@ function createBouncerChannel(logger) {
113
113
  import { EventEmitter } from "events";
114
114
  import WebSocket from "ws";
115
115
  var requestCounter = 0;
116
- var LobbyClient = class extends EventEmitter {
116
+ var LobbyClient = class _LobbyClient extends EventEmitter {
117
117
  ws = null;
118
118
  opts;
119
119
  reconnectAttempt = 0;
120
120
  reconnectTimer = null;
121
121
  closed = false;
122
+ lastHeartbeatAt = 0;
123
+ watchdogTimer = null;
124
+ pingTimer = null;
125
+ static HEARTBEAT_STALE_MS = 45e3;
126
+ static WATCHDOG_INTERVAL_MS = 15e3;
127
+ static CLIENT_PING_INTERVAL_MS = 25e3;
122
128
  constructor(opts) {
123
129
  super();
124
130
  this.opts = {
@@ -132,20 +138,26 @@ var LobbyClient = class extends EventEmitter {
132
138
  return this._connect();
133
139
  }
134
140
  _connect() {
141
+ this.stopTimers();
135
142
  return new Promise((resolve, reject) => {
136
143
  const url = `${this.opts.apiUrl}/v1/agents/${this.opts.agentId}/ws?token=${this.opts.token}`;
137
144
  const ws = new WebSocket(url);
138
145
  this.ws = ws;
139
146
  ws.on("open", () => {
140
147
  this.reconnectAttempt = 0;
148
+ this.lastHeartbeatAt = Date.now();
149
+ this.startWatchdog();
150
+ this.startClientPing();
141
151
  });
142
152
  ws.on("message", (raw) => {
143
153
  try {
144
154
  const data = JSON.parse(raw.toString());
145
155
  if (data.type === "connected") {
156
+ this.lastHeartbeatAt = Date.now();
146
157
  this.emit("connected", data);
147
158
  resolve();
148
159
  } else if (data.type === "heartbeat") {
160
+ this.lastHeartbeatAt = Date.now();
149
161
  this.emit("heartbeat", data);
150
162
  } else if (data.type === "error") {
151
163
  this.emit("error", new Error(data.error));
@@ -155,6 +167,7 @@ var LobbyClient = class extends EventEmitter {
155
167
  }
156
168
  });
157
169
  ws.on("close", () => {
170
+ this.stopTimers();
158
171
  if (!this.closed) {
159
172
  this.scheduleReconnect();
160
173
  }
@@ -166,6 +179,49 @@ var LobbyClient = class extends EventEmitter {
166
179
  });
167
180
  });
168
181
  }
182
+ startWatchdog() {
183
+ this.watchdogTimer = setInterval(() => {
184
+ if (this.closed) return;
185
+ const staleMs = Date.now() - this.lastHeartbeatAt;
186
+ if (staleMs > _LobbyClient.HEARTBEAT_STALE_MS) {
187
+ this.emit("stale", { staleMs });
188
+ this.forceReconnect();
189
+ }
190
+ }, _LobbyClient.WATCHDOG_INTERVAL_MS);
191
+ }
192
+ startClientPing() {
193
+ this.pingTimer = setInterval(() => {
194
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
195
+ try {
196
+ this.ws.ping();
197
+ } catch {
198
+ }
199
+ }
200
+ }, _LobbyClient.CLIENT_PING_INTERVAL_MS);
201
+ }
202
+ stopTimers() {
203
+ if (this.watchdogTimer) {
204
+ clearInterval(this.watchdogTimer);
205
+ this.watchdogTimer = null;
206
+ }
207
+ if (this.pingTimer) {
208
+ clearInterval(this.pingTimer);
209
+ this.pingTimer = null;
210
+ }
211
+ }
212
+ forceReconnect() {
213
+ this.stopTimers();
214
+ if (this.ws) {
215
+ try {
216
+ this.ws.terminate();
217
+ } catch {
218
+ }
219
+ this.ws = null;
220
+ }
221
+ if (!this.closed) {
222
+ this.scheduleReconnect();
223
+ }
224
+ }
169
225
  scheduleReconnect() {
170
226
  if (this.closed) return;
171
227
  const delay = Math.min(
@@ -187,7 +243,12 @@ var LobbyClient = class extends EventEmitter {
187
243
  this.send({ type: "decline_negotiation", negotiation_id: negotiationId, reason });
188
244
  }
189
245
  isConnected() {
190
- return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
246
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;
247
+ if (this.lastHeartbeatAt > 0) {
248
+ const staleMs = Date.now() - this.lastHeartbeatAt;
249
+ if (staleMs > _LobbyClient.HEARTBEAT_STALE_MS) return false;
250
+ }
251
+ return true;
191
252
  }
192
253
  send(data) {
193
254
  if (this.ws && this.ws.readyState === WebSocket.OPEN) {
@@ -199,15 +260,20 @@ var LobbyClient = class extends EventEmitter {
199
260
  request(msg, responseType, timeoutMs = 3e4) {
200
261
  return new Promise((resolve, reject) => {
201
262
  if (!this.isConnected()) {
202
- reject(new Error(`Lobby WS not connected (readyState: ${this.ws?.readyState ?? "null"}) \u2014 cannot send ${msg.type}`));
263
+ const staleMs = this.lastHeartbeatAt > 0 ? Date.now() - this.lastHeartbeatAt : -1;
264
+ reject(new Error(`Lobby WS not connected (readyState: ${this.ws?.readyState ?? "null"}, lastHeartbeat: ${staleMs}ms ago) \u2014 cannot send ${msg.type}`));
203
265
  return;
204
266
  }
205
267
  const requestId = `req_${++requestCounter}_${Date.now()}`;
268
+ console.log(`[lobby-request] Sending ${msg.type} with request_id=${requestId}, waiting for ${responseType}`);
206
269
  const timer = setTimeout(() => {
270
+ const staleMs = this.lastHeartbeatAt > 0 ? Date.now() - this.lastHeartbeatAt : -1;
271
+ console.log(`[lobby-request] TIMEOUT for ${requestId}: readyState=${this.ws?.readyState}, lastHeartbeat=${staleMs}ms ago, listenerCount(${responseType})=${this.listenerCount(responseType)}`);
207
272
  cleanup();
208
- reject(new Error(`WS request timed out waiting for ${responseType} (sent ${msg.type}, waited ${timeoutMs}ms)`));
273
+ reject(new Error(`WS request timed out waiting for ${responseType} (sent ${msg.type}, waited ${timeoutMs}ms, lastHeartbeat: ${staleMs}ms ago)`));
209
274
  }, timeoutMs);
210
275
  const handler = (data) => {
276
+ console.log(`[lobby-request] Got ${responseType} event: request_id=${data.request_id} (waiting for ${requestId})`);
211
277
  if (data.request_id === requestId) {
212
278
  cleanup();
213
279
  if (data.error) {
@@ -226,11 +292,14 @@ var LobbyClient = class extends EventEmitter {
226
292
  if (!sent) {
227
293
  cleanup();
228
294
  reject(new Error(`Failed to send ${msg.type} \u2014 WS connection dropped between check and send`));
295
+ } else {
296
+ console.log(`[lobby-request] Message sent successfully, readyState=${this.ws?.readyState}`);
229
297
  }
230
298
  });
231
299
  }
232
300
  close() {
233
301
  this.closed = true;
302
+ this.stopTimers();
234
303
  if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
235
304
  if (this.ws) {
236
305
  try {
@@ -410,6 +479,9 @@ async function startLobby(config, log) {
410
479
  lobbyClient.on("heartbeat", () => {
411
480
  log.debug("[bouncer] Lobby heartbeat");
412
481
  });
482
+ lobbyClient.on("stale", (data) => {
483
+ log.warn(`[bouncer] Lobby connection stale (${data.staleMs}ms since last heartbeat) \u2014 forcing reconnect`);
484
+ });
413
485
  try {
414
486
  await lobbyClient.connect();
415
487
  } catch (err) {
@@ -661,10 +733,20 @@ function createBrandTools(config, logger) {
661
733
  },
662
734
  async execute(params) {
663
735
  const lobby = getLobbyClient();
664
- if (!lobby) return { error: "Not connected to lobby" };
736
+ if (!lobby) {
737
+ logger.error("[bouncer] bouncer_offer: getLobbyClient() returned null \u2014 lobby not initialized");
738
+ return { error: "Not connected to lobby" };
739
+ }
740
+ const connected = lobby.isConnected();
741
+ logger.info(`[bouncer] bouncer_offer: lobby.isConnected() = ${connected}`);
742
+ if (!connected) {
743
+ logger.error("[bouncer] bouncer_offer: lobby exists but isConnected() is false \u2014 WS may be reconnecting");
744
+ return { error: "Lobby WS not connected \u2014 may be reconnecting. Try again in a few seconds." };
745
+ }
665
746
  const bouncerId = params.bouncer_id;
666
747
  try {
667
748
  logger.info(`[bouncer] Submitting offer to ${bouncerId}`);
749
+ const sendStart = Date.now();
668
750
  const offerResult = await lobby.request(
669
751
  {
670
752
  type: "submit_offer",
@@ -677,6 +759,7 @@ function createBrandTools(config, logger) {
677
759
  },
678
760
  "submit_offer_result"
679
761
  );
762
+ logger.info(`[bouncer] submit_offer response in ${Date.now() - sendStart}ms`);
680
763
  if (offerResult.error) {
681
764
  return { error: `Offer submission failed: ${offerResult.error}` };
682
765
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sdk-types.ts","../src/connector-parser.ts","../src/bouncer-channel.ts","../src/connector-lobby.ts","../src/connector-session.ts","../src/service.ts","../src/types.ts","../src/tools.ts","../index.ts"],"sourcesContent":["/**\n * Minimal type stubs for the OpenClaw Plugin SDK.\n *\n * When installed into an OpenClaw environment, replace these with:\n * import { definePluginEntry } from \"openclaw/plugin-sdk/core\";\n *\n * These stubs match the contract from openclaw/openclaw src/plugin-sdk/core.ts\n * and src/plugins/types.ts as of 2026-03.\n */\n\nexport interface PluginLogger {\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n debug(msg: string, ...args: unknown[]): void;\n}\n\nexport interface ReplyPayload {\n text?: string;\n body?: string;\n mediaUrl?: string;\n mediaUrls?: string[];\n [key: string]: unknown;\n}\n\nexport interface MsgContext {\n Body?: string;\n BodyForAgent?: string;\n RawBody?: string;\n CommandBody?: string;\n From?: string;\n To?: string;\n SessionKey?: string;\n AccountId?: string;\n OriginatingChannel?: string;\n OriginatingTo?: string;\n ChatType?: string;\n SenderName?: string;\n SenderId?: string;\n Provider?: string;\n Surface?: string;\n ConversationLabel?: string;\n Timestamp?: number;\n CommandAuthorized?: boolean;\n [key: string]: unknown;\n}\n\nexport type FinalizedMsgContext = Omit<MsgContext, \"CommandAuthorized\"> & {\n CommandAuthorized: boolean;\n};\n\nexport interface ReplyDispatcherWithTypingOptions {\n deliver: (payload: ReplyPayload, info: { kind: string }) => Promise<void>;\n onReplyStart?: () => Promise<void> | void;\n onIdle?: () => void;\n onCleanup?: () => void;\n [key: string]: unknown;\n}\n\nexport interface DispatchInboundResult {\n [key: string]: unknown;\n}\n\nexport interface PluginRuntime {\n channel: {\n reply: {\n finalizeInboundContext: <T extends Record<string, unknown>>(ctx: T) => T & FinalizedMsgContext;\n dispatchReplyWithBufferedBlockDispatcher: (params: {\n ctx: MsgContext | FinalizedMsgContext;\n cfg: OpenClawConfig;\n dispatcherOptions: ReplyDispatcherWithTypingOptions;\n replyOptions?: Record<string, unknown>;\n }) => Promise<DispatchInboundResult>;\n dispatchReplyFromConfig?: (...args: unknown[]) => Promise<unknown>;\n };\n debounce: {\n createInboundDebouncer: (...args: unknown[]) => unknown;\n resolveInboundDebounceMs: (...args: unknown[]) => number;\n };\n session: {\n recordInboundSession: (...args: unknown[]) => unknown;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n };\n config: {\n loadConfig: () => Promise<OpenClawConfig>;\n writeConfigFile?: (...args: unknown[]) => Promise<void>;\n };\n logging: { shouldLogVerbose(): boolean; getChildLogger(name: string): PluginLogger };\n state: { resolveStateDir(): string };\n}\n\nexport interface OpenClawConfig {\n channels?: Record<string, Record<string, unknown>>;\n plugins?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface OpenClawPluginServiceContext {\n config: OpenClawConfig;\n workspaceDir?: string;\n stateDir: string;\n logger: PluginLogger;\n}\n\nexport interface OpenClawPluginService {\n id: string;\n start: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;\n stop?: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;\n}\n\nexport interface OpenClawPluginToolContext {\n config?: OpenClawConfig;\n agentId?: string;\n sessionKey?: string;\n messageChannel?: string;\n [key: string]: unknown;\n}\n\nexport interface AgentTool {\n name: string;\n description: string;\n parameters?: Record<string, unknown>;\n execute: (params: Record<string, unknown>, ctx?: unknown) => Promise<unknown>;\n}\n\nexport type OpenClawPluginToolFactory = (ctx: OpenClawPluginToolContext) => AgentTool | AgentTool[] | null | undefined;\n\nexport interface OpenClawPluginApi {\n id: string;\n name: string;\n version?: string;\n description?: string;\n source: string;\n rootDir?: string;\n registrationMode: \"full\" | \"setup-only\" | \"setup-runtime\";\n config: OpenClawConfig;\n pluginConfig?: Record<string, unknown>;\n runtime: PluginRuntime;\n logger: PluginLogger;\n\n registerTool: (tool: AgentTool | OpenClawPluginToolFactory, opts?: { name?: string; names?: string[]; optional?: boolean }) => void;\n registerHook: (events: string | string[], handler: (...args: unknown[]) => void | Promise<void>, opts?: Record<string, unknown>) => void;\n registerHttpRoute: (params: Record<string, unknown>) => void;\n registerChannel: (registration: { plugin: ChannelPlugin } | ChannelPlugin) => void;\n registerGatewayMethod: (method: string, handler: (...args: unknown[]) => unknown) => void;\n registerService: (service: OpenClawPluginService) => void;\n registerCommand: (command: { name: string; description: string; handler: (...args: unknown[]) => void | Promise<void> }) => void;\n resolvePath: (input: string) => string;\n on: (hookName: string, handler: (...args: unknown[]) => void | Promise<void>, opts?: { priority?: number }) => void;\n}\n\nexport interface ChannelMeta {\n id: string;\n label: string;\n selectionLabel: string;\n docsPath?: string;\n blurb?: string;\n aliases?: string[];\n order?: number;\n}\n\nexport interface ChannelCapabilities {\n chatTypes: Array<\"direct\" | \"group\">;\n}\n\nexport interface ChannelConfigAdapter {\n listAccountIds: (cfg: OpenClawConfig) => string[];\n resolveAccount: (cfg: OpenClawConfig, accountId?: string) => Record<string, unknown>;\n}\n\nexport interface ChannelOutboundAdapter {\n deliveryMode: \"direct\" | \"queued\";\n sendText: (ctx: SendTextContext) => Promise<{ ok: boolean; error?: string }>;\n}\n\nexport interface SendTextContext {\n text: string;\n conversationId?: string;\n accountId?: string;\n replyTo?: string;\n [key: string]: unknown;\n}\n\nexport interface ChannelLifecycleAdapter {\n startAccount?: (accountId: string, config: Record<string, unknown>, logger: PluginLogger) => Promise<void>;\n stopAccount?: (accountId: string) => Promise<void>;\n}\n\nexport interface ChannelPlugin {\n id: string;\n meta: ChannelMeta;\n capabilities: ChannelCapabilities;\n config: ChannelConfigAdapter;\n outbound?: ChannelOutboundAdapter;\n lifecycle?: ChannelLifecycleAdapter;\n [key: string]: unknown;\n}\n\nexport interface DefinedPluginEntry {\n id: string;\n name: string;\n description: string;\n register: (api: OpenClawPluginApi) => void;\n}\n\nexport function definePluginEntry(opts: {\n id: string;\n name: string;\n description: string;\n register: (api: OpenClawPluginApi) => void;\n}): DefinedPluginEntry {\n return {\n id: opts.id,\n name: opts.name,\n description: opts.description,\n register: opts.register,\n };\n}\n\nexport function defineChannelPluginEntry<TPlugin extends ChannelPlugin>(opts: {\n id: string;\n name: string;\n description: string;\n plugin: TPlugin;\n setRuntime?: (runtime: PluginRuntime) => void;\n registerFull?: (api: OpenClawPluginApi) => void;\n}): DefinedPluginEntry {\n return definePluginEntry({\n id: opts.id,\n name: opts.name,\n description: opts.description,\n register(api) {\n api.registerChannel({ plugin: opts.plugin });\n if (opts.setRuntime) opts.setRuntime(api.runtime);\n if (api.registrationMode === \"full\" && opts.registerFull) {\n opts.registerFull(api);\n }\n },\n });\n}\n","export interface BounceMessage {\n type: \"message\" | \"accept\" | \"walk\" | \"propose_terms\" | \"counter_terms\" | \"research\";\n content: string;\n terms?: Record<string, any>;\n}\n\nconst SIMPLE_PREFIXES: Record<string, BounceMessage[\"type\"]> = {\n \"[ACCEPT]\": \"accept\",\n \"[WALK]\": \"walk\",\n \"[RESEARCH]\": \"research\",\n};\n\nconst TERMS_PREFIXES: Record<string, BounceMessage[\"type\"]> = {\n \"[TERMS]\": \"propose_terms\",\n \"[COUNTER]\": \"counter_terms\",\n};\n\nexport function parseResponse(text: string): BounceMessage {\n const trimmed = text.trim();\n\n for (const [prefix, type] of Object.entries(SIMPLE_PREFIXES)) {\n if (trimmed.startsWith(prefix)) {\n return { type, content: trimmed.slice(prefix.length).trim() };\n }\n }\n\n for (const [prefix, type] of Object.entries(TERMS_PREFIXES)) {\n if (trimmed.startsWith(prefix)) {\n const rest = trimmed.slice(prefix.length);\n const jsonEnd = rest.indexOf(\"}\");\n if (jsonEnd !== -1) {\n const jsonStr = rest.slice(0, jsonEnd + 1);\n try {\n const terms = JSON.parse(jsonStr);\n const content = rest.slice(jsonEnd + 1).trim();\n return { type, content, terms };\n } catch {\n return { type: \"message\", content: trimmed };\n }\n }\n return { type: \"message\", content: trimmed };\n }\n }\n\n return { type: \"message\", content: trimmed };\n}\n","import { parseResponse } from \"./connector-parser.js\";\nimport { NegotiationSession } from \"./connector-session.js\";\nimport type {\n ChannelPlugin,\n OpenClawConfig,\n PluginLogger,\n SendTextContext,\n} from \"./sdk-types.js\";\n\nconst activeSessions = new Map<string, NegotiationSession>();\n\nexport function getActiveSession(negotiationId: string): NegotiationSession | undefined {\n return activeSessions.get(negotiationId);\n}\n\nexport function setActiveSession(negotiationId: string, session: NegotiationSession): void {\n activeSessions.set(negotiationId, session);\n}\n\nexport function removeActiveSession(negotiationId: string): void {\n const session = activeSessions.get(negotiationId);\n if (session) {\n session.close();\n activeSessions.delete(negotiationId);\n }\n}\n\nexport function getActiveNegotiationId(): string | undefined {\n const entries = [...activeSessions.entries()];\n return entries.length > 0 ? entries[0]![0] : undefined;\n}\n\nexport function createBouncerChannel(logger: PluginLogger): ChannelPlugin {\n return {\n id: \"bouncer\",\n\n meta: {\n id: \"bouncer\",\n label: \"Bouncer Protocol\",\n selectionLabel: \"Bouncer Protocol (Agent Negotiation)\",\n docsPath: \"/channels/bouncer\",\n blurb: \"Real-time agent-to-agent negotiation via the Bouncer Protocol\",\n aliases: [\"bouncer-protocol\"],\n order: 90,\n },\n\n capabilities: {\n chatTypes: [\"direct\"],\n },\n\n config: {\n listAccountIds(cfg: OpenClawConfig): string[] {\n const bouncer = cfg.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncer?.agentId) return [];\n return [bouncer.agentId as string];\n },\n\n resolveAccount(cfg: OpenClawConfig, accountId?: string): Record<string, unknown> {\n const bouncer = cfg.channels?.bouncer as Record<string, unknown> | undefined;\n return bouncer ?? { accountId };\n },\n },\n\n outbound: {\n deliveryMode: \"direct\",\n\n async sendText(ctx: SendTextContext): Promise<{ ok: boolean; error?: string }> {\n const negId = ctx.conversationId ?? getActiveNegotiationId();\n if (!negId) {\n return { ok: false, error: \"No active negotiation session\" };\n }\n\n const session = activeSessions.get(negId);\n if (!session) {\n return { ok: false, error: `No session for negotiation ${negId}` };\n }\n\n const parsed = parseResponse(ctx.text);\n\n session.sendThinking();\n\n await new Promise((r) => setTimeout(r, 200));\n\n session.send(parsed);\n logger.info(`[bouncer] Sent ${parsed.type}: ${parsed.content.slice(0, 80)}...`);\n\n return { ok: true };\n },\n },\n };\n}\n","import { EventEmitter } from \"events\";\nimport WebSocket from \"ws\";\n\nlet requestCounter = 0;\n\nexport interface LobbyClientOpts {\n apiUrl: string;\n token: string;\n agentId: string;\n reconnectBaseMs?: number;\n reconnectMaxMs?: number;\n}\n\nexport class LobbyClient extends EventEmitter {\n private ws: WebSocket | null = null;\n private opts: Required<LobbyClientOpts>;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n\n constructor(opts: LobbyClientOpts) {\n super();\n this.opts = {\n reconnectBaseMs: 1000,\n reconnectMaxMs: 30_000,\n ...opts,\n };\n }\n\n connect(): Promise<void> {\n this.closed = false;\n return this._connect();\n }\n\n private _connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.opts.apiUrl}/v1/agents/${this.opts.agentId}/ws?token=${this.opts.token}`;\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.on(\"open\", () => {\n this.reconnectAttempt = 0;\n });\n\n ws.on(\"message\", (raw) => {\n try {\n const data = JSON.parse(raw.toString());\n if (data.type === \"connected\") {\n this.emit(\"connected\", data);\n resolve();\n } else if (data.type === \"heartbeat\") {\n this.emit(\"heartbeat\", data);\n } else if (data.type === \"error\") {\n this.emit(\"error\", new Error(data.error));\n }\n this.emit(data.type, data);\n } catch {}\n });\n\n ws.on(\"close\", () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n });\n\n ws.on(\"error\", (err) => {\n if (this.reconnectAttempt === 0 && ws.readyState === WebSocket.CONNECTING) {\n reject(err);\n }\n });\n });\n }\n\n private scheduleReconnect() {\n if (this.closed) return;\n const delay = Math.min(\n this.opts.reconnectBaseMs * Math.pow(2, this.reconnectAttempt),\n this.opts.reconnectMaxMs\n );\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n if (!this.closed) {\n this._connect().catch(() => {});\n }\n }, delay);\n }\n\n accept(negotiationId: string): void {\n this.send({ type: \"accept_negotiation\", negotiation_id: negotiationId });\n }\n\n decline(negotiationId: string, reason?: string): void {\n this.send({ type: \"decline_negotiation\", negotiation_id: negotiationId, reason });\n }\n\n isConnected(): boolean {\n return this.ws !== null && this.ws.readyState === WebSocket.OPEN;\n }\n\n send(data: any): boolean {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(data));\n return true;\n }\n return false;\n }\n\n request(msg: Record<string, unknown>, responseType: string, timeoutMs = 30_000): Promise<any> {\n return new Promise((resolve, reject) => {\n if (!this.isConnected()) {\n reject(new Error(`Lobby WS not connected (readyState: ${this.ws?.readyState ?? \"null\"}) — cannot send ${msg.type}`));\n return;\n }\n\n const requestId = `req_${++requestCounter}_${Date.now()}`;\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`WS request timed out waiting for ${responseType} (sent ${msg.type}, waited ${timeoutMs}ms)`));\n }, timeoutMs);\n\n const handler = (data: any) => {\n if (data.request_id === requestId) {\n cleanup();\n if (data.error) {\n reject(new Error(data.error));\n } else {\n resolve(data);\n }\n }\n };\n\n const cleanup = () => {\n clearTimeout(timer);\n this.removeListener(responseType, handler);\n };\n\n this.on(responseType, handler);\n const sent = this.send({ ...msg, request_id: requestId });\n if (!sent) {\n cleanup();\n reject(new Error(`Failed to send ${msg.type} — WS connection dropped between check and send`));\n }\n });\n }\n\n close(): void {\n this.closed = true;\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n if (this.ws) {\n try { this.ws.close(); } catch {}\n this.ws = null;\n }\n }\n}\n","import { EventEmitter } from \"events\";\nimport WebSocket from \"ws\";\n\nexport interface NegotiationSessionOpts {\n apiUrl: string;\n token: string;\n negotiationId: string;\n agentId: string;\n}\n\nexport class NegotiationSession extends EventEmitter {\n private ws: WebSocket | null = null;\n private opts: NegotiationSessionOpts;\n private seenMessageIds = new Set<string>();\n private myAgentId: string;\n\n constructor(opts: NegotiationSessionOpts) {\n super();\n this.opts = opts;\n this.myAgentId = opts.agentId;\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.opts.apiUrl}/v1/negotiations/${this.opts.negotiationId}/ws?token=${this.opts.token}`;\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.on(\"message\", (raw) => {\n try {\n const data = JSON.parse(raw.toString());\n\n if (data.type === \"connected\") {\n if (data.agent_id) this.myAgentId = data.agent_id;\n this.emit(\"connected\", data);\n resolve();\n } else if (data.type === \"negotiation_message\") {\n const msg = data.message ?? {\n id: data.id,\n from_agent_id: data.from_agent_id,\n type: data.message_type ?? data.type,\n content: data.content,\n terms: data.terms,\n is_catchup: data.is_catchup,\n created_at: data.created_at,\n };\n\n const msgId = msg.id;\n if (msgId && this.seenMessageIds.has(msgId)) return;\n if (msgId) this.seenMessageIds.add(msgId);\n\n if (msg.from_agent_id === this.myAgentId) return;\n\n this.emit(\"incoming_message\", msg);\n } else if (data.type === \"negotiation_started\") {\n this.emit(\"negotiation_started\", data);\n } else if (data.type === \"negotiation_ended\") {\n this.emit(\"ended\", data);\n this.close();\n } else if (data.type === \"message_ack\") {\n if (data.message?.id) this.seenMessageIds.add(data.message.id);\n this.emit(\"message_ack\", data);\n } else if (data.type === \"agent_thinking\") {\n this.emit(\"agent_thinking\", data);\n } else if (data.type === \"error\") {\n this.emit(\"error\", new Error(data.error));\n }\n } catch {}\n });\n\n ws.on(\"error\", (err) => {\n if (ws.readyState === WebSocket.CONNECTING) {\n reject(err);\n }\n });\n\n ws.on(\"close\", () => {\n this.emit(\"disconnected\");\n });\n });\n }\n\n send(msg: { type: string; content?: string; terms?: object }): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(msg));\n }\n }\n\n sendThinking(): void {\n this.send({ type: \"thinking\" });\n }\n\n close(): void {\n if (this.ws) {\n try { this.ws.close(); } catch {}\n this.ws = null;\n }\n }\n}\n","import { LobbyClient } from \"./connector-lobby.js\";\nimport { NegotiationSession } from \"./connector-session.js\";\nimport { parseResponse } from \"./connector-parser.js\";\nimport {\n setActiveSession,\n removeActiveSession,\n} from \"./bouncer-channel.js\";\nimport type { BouncerPluginConfig, NegotiationState } from \"./types.js\";\nimport type {\n OpenClawPluginService,\n OpenClawPluginServiceContext,\n PluginLogger,\n PluginRuntime,\n} from \"./sdk-types.js\";\n\nlet lobbyClient: LobbyClient | null = null;\n\nexport function getLobbyClient(): LobbyClient | null {\n return lobbyClient;\n}\nlet activeNegotiation: NegotiationState | null = null;\nlet pluginRuntime: PluginRuntime | null = null;\n\nfunction resolveAgentFromBindings(cfg: any, channel: string): string | null {\n const bindings = cfg?.bindings;\n if (!Array.isArray(bindings)) return null;\n for (const b of bindings) {\n if (b?.match?.channel === channel && b?.agentId) {\n return b.agentId;\n }\n }\n return null;\n}\n\nlet serviceStarted = false;\n\nexport function setRuntime(rt: PluginRuntime): void {\n pluginRuntime = rt;\n}\n\nexport async function ensureServiceStarted(log: PluginLogger): Promise<void> {\n if (serviceStarted || lobbyClient) return;\n if (!pluginRuntime) return;\n\n try {\n const cfg = await pluginRuntime.config.loadConfig();\n const bouncerCfg = cfg?.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncerCfg?.role) return;\n\n const config: BouncerPluginConfig = {\n role: bouncerCfg.role as \"bouncer\" | \"brand\",\n apiUrl: bouncerCfg.apiUrl as string,\n apiKey: bouncerCfg.apiKey as string,\n agentId: bouncerCfg.agentId as string,\n autoAccept: (bouncerCfg.autoAccept as boolean) ?? true,\n llmTimeoutMs: (bouncerCfg.llmTimeoutMs as number) ?? 25_000,\n };\n\n serviceStarted = true;\n log.info(`[bouncer] Self-starting service — role: ${config.role}, agent: ${config.agentId}`);\n\n await startLobby(config, log);\n } catch (err: any) {\n log.error(`[bouncer] Self-start failed: ${err.message}`);\n serviceStarted = false;\n }\n}\n\nexport function getActiveNegotiation(): NegotiationState | null {\n return activeNegotiation;\n}\n\nexport function createBouncerService(config: BouncerPluginConfig): OpenClawPluginService {\n return {\n id: \"bouncer-negotiation-service\",\n\n async start(ctx: OpenClawPluginServiceContext) {\n const log = ctx.logger;\n\n await startLobby(config, log);\n },\n\n async stop() {\n if (lobbyClient) {\n lobbyClient.close();\n lobbyClient = null;\n }\n if (activeNegotiation) {\n removeActiveSession(activeNegotiation.negotiationId);\n activeNegotiation = null;\n }\n },\n };\n}\n\nasync function startLobby(config: BouncerPluginConfig, log: PluginLogger): Promise<void> {\n const wsBase = config.apiUrl.replace(/^http/, \"ws\");\n\n lobbyClient = new LobbyClient({\n apiUrl: wsBase,\n token: config.apiKey,\n agentId: config.agentId,\n reconnectBaseMs: 1_000,\n reconnectMaxMs: 30_000,\n });\n\n lobbyClient.on(\"connected\", () => {\n log.info(`[bouncer] Lobby connected (${config.role} mode).`);\n });\n\n if (config.role === \"bouncer\") {\n lobbyClient.on(\"negotiation_requested\", (data: any) => {\n handleNegotiationRequested(data, config, wsBase, log);\n });\n }\n\n lobbyClient.on(\"heartbeat\", () => {\n log.debug(\"[bouncer] Lobby heartbeat\");\n });\n\n try {\n await lobbyClient.connect();\n } catch (err: any) {\n log.error(`[bouncer] Lobby connection failed: ${err.message}`);\n throw err;\n }\n}\n\nasync function handleNegotiationRequested(\n data: any,\n config: BouncerPluginConfig,\n wsBase: string,\n log: PluginLogger,\n): Promise<void> {\n const negId = data.negotiation_id;\n\n if (activeNegotiation) {\n log.info(`[bouncer] Declining ${negId} — already in negotiation ${activeNegotiation.negotiationId}`);\n lobbyClient?.decline(negId, \"busy — already in a negotiation\");\n return;\n }\n\n if (!config.autoAccept) {\n log.info(`[bouncer] Negotiation ${negId} requested but autoAccept is off. Declining.`);\n lobbyClient?.decline(negId, \"auto-accept disabled\");\n return;\n }\n\n log.info(`[bouncer] Accepting negotiation ${negId}`);\n lobbyClient?.accept(negId);\n\n activeNegotiation = {\n negotiationId: negId,\n status: \"pending\",\n otherAgentId: data.brand?.id,\n offerContext: data.offer\n ? { product: data.offer.product, terms: data.offer.terms, opening_message: data.offer.opening_message }\n : undefined,\n };\n\n await connectToNegotiationRoom(negId, config, wsBase, log);\n}\n\nexport async function connectToNegotiationRoom(\n negotiationId: string,\n config: BouncerPluginConfig,\n wsBase: string,\n log: PluginLogger,\n): Promise<void> {\n const session = new NegotiationSession({\n apiUrl: wsBase,\n token: config.apiKey,\n negotiationId,\n agentId: config.agentId,\n });\n\n session.on(\"connected\", () => {\n log.info(`[bouncer] Connected to negotiation room ${negotiationId}`);\n });\n\n session.on(\"negotiation_started\", (data: any) => {\n log.info(`[bouncer] Negotiation ${negotiationId} started`);\n if (activeNegotiation) {\n activeNegotiation.status = \"live\";\n if (data.queue_context) {\n (activeNegotiation as any).queueContext = data.queue_context;\n }\n if (data.relationship) {\n (activeNegotiation as any).relationship = data.relationship;\n }\n }\n });\n\n let dispatching = false;\n session.on(\"incoming_message\", (msg: any) => {\n if (dispatching) {\n log.debug(`[bouncer] Skipping message while dispatch in progress`);\n return;\n }\n log.info(`[bouncer] Message from ${msg.from_agent_id}: ${(msg.content ?? \"\").slice(0, 80)}...`);\n dispatching = true;\n dispatchToAgent(negotiationId, msg, config, session, log).finally(() => {\n dispatching = false;\n });\n });\n\n session.on(\"agent_thinking\", () => {\n log.debug(`[bouncer] Other agent thinking in ${negotiationId}`);\n });\n\n session.on(\"ended\", (data: any) => {\n log.info(`[bouncer] Negotiation ${negotiationId} ended: ${data?.status ?? \"unknown\"}`);\n removeActiveSession(negotiationId);\n activeNegotiation = null;\n });\n\n session.on(\"disconnected\", () => {\n log.warn(`[bouncer] Disconnected from negotiation ${negotiationId}`);\n });\n\n setActiveSession(negotiationId, session);\n\n try {\n await session.connect();\n } catch (err: any) {\n log.error(`[bouncer] Failed to connect to negotiation ${negotiationId}: ${err.message}`);\n removeActiveSession(negotiationId);\n activeNegotiation = null;\n }\n}\n\nasync function dispatchToAgent(\n negotiationId: string,\n msg: any,\n config: BouncerPluginConfig,\n session: NegotiationSession,\n log: PluginLogger,\n): Promise<void> {\n if (!pluginRuntime) {\n log.error(\"[bouncer] Runtime not set — cannot dispatch inbound message to agent\");\n return;\n }\n\n const rt = pluginRuntime;\n\n try {\n const currentCfg = await rt.config.loadConfig();\n\n const resolvedAgent = resolveAgentFromBindings(currentCfg, \"bouncer\");\n if (resolvedAgent) {\n log.info(`[bouncer] Routing negotiation ${negotiationId} to agent: ${resolvedAgent}`);\n }\n\n const msgCtx = rt.channel.reply.finalizeInboundContext({\n Body: msg.content ?? \"\",\n RawBody: msg.content ?? \"\",\n CommandBody: msg.content ?? \"\",\n From: `bouncer:${msg.from_agent_id}`,\n To: `bouncer:${config.agentId}`,\n SessionKey: `bouncer:${negotiationId}`,\n AccountId: config.agentId,\n OriginatingChannel: \"bouncer\",\n OriginatingTo: `bouncer:${msg.from_agent_id}`,\n ChatType: \"direct\",\n SenderName: msg.from_agent_id,\n SenderId: msg.from_agent_id,\n Provider: \"bouncer\",\n Surface: \"bouncer\",\n ConversationLabel: `Negotiation ${negotiationId}`,\n Timestamp: Date.now(),\n CommandAuthorized: true,\n ...(resolvedAgent ? { AgentId: resolvedAgent, TargetAgentId: resolvedAgent, ResolvedAgentId: resolvedAgent } : {}),\n });\n\n await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: msgCtx,\n cfg: currentCfg,\n dispatcherOptions: {\n deliver: async (payload) => {\n const text = payload?.text ?? payload?.body;\n if (!text) return;\n\n const parsed = parseResponse(text);\n session.sendThinking();\n await new Promise((r) => setTimeout(r, 200));\n session.send(parsed);\n log.info(`[bouncer] Agent replied (${parsed.type}): ${parsed.content.slice(0, 80)}...`);\n },\n onReplyStart: () => {\n session.sendThinking();\n },\n },\n });\n } catch (err: any) {\n log.error(`[bouncer] Dispatch failed for negotiation ${negotiationId}: ${err.message}`);\n }\n}\n","export interface BouncerPluginConfig {\n role: \"bouncer\" | \"brand\";\n apiUrl: string;\n apiKey: string;\n agentId: string;\n autoAccept?: boolean;\n llmTimeoutMs?: number;\n}\n\nexport interface NegotiationState {\n negotiationId: string;\n status: \"pending\" | \"live\" | \"ended\";\n otherAgentId?: string;\n offerContext?: {\n product: string;\n terms: string;\n opening_message: string;\n };\n}\n\nexport interface InboundNegotiationMessage {\n negotiationId: string;\n fromAgentId: string;\n type: string;\n content: string;\n terms?: Record<string, unknown>;\n timestamp: string;\n}\n\nexport function resolveConfig(pluginConfig: Record<string, unknown> | undefined): BouncerPluginConfig {\n if (!pluginConfig) throw new Error(\"Bouncer plugin config is required\");\n\n const role = pluginConfig.role as string;\n if (role !== \"bouncer\" && role !== \"brand\") {\n throw new Error(`Invalid role \"${role}\" — must be \"bouncer\" or \"brand\"`);\n }\n\n return {\n role,\n apiUrl: pluginConfig.apiUrl as string,\n apiKey: pluginConfig.apiKey as string,\n agentId: pluginConfig.agentId as string,\n autoAccept: (pluginConfig.autoAccept as boolean) ?? true,\n llmTimeoutMs: (pluginConfig.llmTimeoutMs as number) ?? 25_000,\n };\n}\n\nexport function wsUrl(apiUrl: string): string {\n return apiUrl.replace(/^http/, \"ws\");\n}\n","import type { AgentTool, PluginLogger } from \"./sdk-types.js\";\nimport type { BouncerPluginConfig } from \"./types.js\";\nimport { connectToNegotiationRoom, getLobbyClient } from \"./service.js\";\nimport { wsUrl } from \"./types.js\";\n\nexport function createBrandTools(config: BouncerPluginConfig, logger: PluginLogger): AgentTool[] {\n if (config.role !== \"brand\") return [];\n\n const bouncerBrowse: AgentTool = {\n name: \"bouncer_browse\",\n description:\n \"Browse available Bouncer agents in the directory. Returns a list of bouncers \" +\n \"with their name, listing, tags, and reputation score. Use this to find a \" +\n \"bouncer to target with an offer.\",\n parameters: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n description: \"Max results to return (default: 20)\",\n },\n },\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { error: \"Not connected to lobby\" };\n\n try {\n const result = await lobby.request(\n { type: \"browse_bouncers\", limit: params.limit ?? 20 },\n \"browse_bouncers_result\",\n );\n logger.info(`[bouncer] Browse returned ${result.bouncers?.length ?? 0} bouncers`);\n return result.bouncers;\n } catch (err: any) {\n return { error: `Browse failed: ${err.message}` };\n }\n },\n };\n\n const bouncerProfile: AgentTool = {\n name: \"bouncer_profile\",\n description:\n \"Get the full profile of a specific Bouncer agent, including their listing, \" +\n \"enrichment data, engagement rules, and verified credentials. Use this before \" +\n \"crafting a personalized offer.\",\n parameters: {\n type: \"object\",\n properties: {\n bouncer_id: {\n type: \"string\",\n description: \"The Bouncer agent's UUID\",\n },\n },\n required: [\"bouncer_id\"],\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { error: \"Not connected to lobby\" };\n\n try {\n const result = await lobby.request(\n { type: \"get_profile\", bouncer_id: params.bouncer_id },\n \"get_profile_result\",\n );\n if (result.error) return { error: result.error };\n return result.profile;\n } catch (err: any) {\n return { error: `Profile fetch failed: ${err.message}` };\n }\n },\n };\n\n const bouncerOffer: AgentTool = {\n name: \"bouncer_offer\",\n description:\n \"Submit an offer to a Bouncer agent and create a negotiation. This sends your \" +\n \"offer and automatically connects you to the negotiation room when the bouncer \" +\n \"accepts. Returns the offer_id and negotiation_id.\",\n parameters: {\n type: \"object\",\n properties: {\n bouncer_id: {\n type: \"string\",\n description: \"The target Bouncer's UUID\",\n },\n product: {\n type: \"string\",\n description: \"Product or service being offered\",\n },\n terms: {\n type: \"string\",\n description: \"Deal terms (e.g. '$20 credit + free delivery')\",\n },\n opening_message: {\n type: \"string\",\n description: \"Personalized opening message to the Bouncer\",\n },\n priority_bid: {\n type: \"number\",\n description: \"Priority bid in USDC (e.g. 2.0)\",\n },\n arena: {\n type: \"boolean\",\n description: \"Practice mode — no real USDC (default: false)\",\n },\n },\n required: [\"bouncer_id\", \"product\", \"terms\", \"opening_message\", \"priority_bid\"],\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { error: \"Not connected to lobby\" };\n\n const bouncerId = params.bouncer_id as string;\n\n try {\n logger.info(`[bouncer] Submitting offer to ${bouncerId}`);\n\n const offerResult = await lobby.request(\n {\n type: \"submit_offer\",\n bouncer_id: bouncerId,\n product: params.product,\n terms: params.terms,\n opening_message: params.opening_message,\n priority_bid: params.priority_bid,\n arena: params.arena ?? false,\n },\n \"submit_offer_result\",\n );\n\n if (offerResult.error) {\n return { error: `Offer submission failed: ${offerResult.error}` };\n }\n\n const offerId = offerResult.offer_id;\n logger.info(`[bouncer] Offer submitted: ${offerId}`);\n\n logger.info(`[bouncer] Creating negotiation for offer ${offerId}`);\n const negResult = await lobby.request(\n { type: \"create_negotiation\", offer_id: offerId, bouncer_id: bouncerId },\n \"create_negotiation_result\",\n );\n\n if (negResult.error) {\n return { error: `Negotiation creation failed: ${negResult.error}`, offer_id: offerId };\n }\n\n const negotiationId = negResult.negotiation_id;\n logger.info(`[bouncer] Negotiation created: ${negotiationId}`);\n\n logger.info(`[bouncer] Waiting for bouncer to accept (via WS)...`);\n const accepted = await waitForAcceptanceWS(negotiationId, 120_000);\n\n if (!accepted) {\n return { status: \"declined_or_timeout\", offer_id: offerId, negotiation_id: negotiationId };\n }\n\n logger.info(`[bouncer] Accepted! Connecting to negotiation room...`);\n await connectToNegotiationRoom(negotiationId, config, wsUrl(config.apiUrl), logger);\n\n return {\n status: \"connected\",\n offer_id: offerId,\n negotiation_id: negotiationId,\n message: \"Connected to negotiation room. Incoming messages will appear as chat messages.\",\n };\n } catch (err: any) {\n return { error: `Offer flow failed: ${err.message}` };\n }\n },\n };\n\n return [bouncerBrowse, bouncerProfile, bouncerOffer];\n}\n\nfunction waitForAcceptanceWS(negotiationId: string, timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n const lobby = getLobbyClient();\n if (!lobby) {\n resolve(false);\n return;\n }\n\n const timer = setTimeout(() => {\n cleanup();\n resolve(false);\n }, timeoutMs);\n\n const onAccepted = (data: any) => {\n if (data.negotiation_id === negotiationId) {\n cleanup();\n resolve(true);\n }\n };\n\n const onDeclined = (data: any) => {\n if (data.negotiation_id === negotiationId) {\n cleanup();\n resolve(false);\n }\n };\n\n const cleanup = () => {\n clearTimeout(timer);\n lobby.removeListener(\"negotiation_accepted\", onAccepted);\n lobby.removeListener(\"negotiation_declined\", onDeclined);\n };\n\n lobby.on(\"negotiation_accepted\", onAccepted);\n lobby.on(\"negotiation_declined\", onDeclined);\n });\n}\n","import { definePluginEntry } from \"./src/sdk-types.js\";\nimport { createBouncerChannel } from \"./src/bouncer-channel.js\";\nimport { createBouncerService, setRuntime, ensureServiceStarted } from \"./src/service.js\";\nimport { createBrandTools } from \"./src/tools.js\";\nimport { resolveConfig } from \"./src/types.js\";\nimport type { OpenClawPluginApi, PluginLogger } from \"./src/sdk-types.js\";\n\nlet pluginLogger: PluginLogger = {\n info: console.log,\n warn: console.warn,\n error: console.error,\n debug: () => {},\n};\n\nconst channel = createBouncerChannel(pluginLogger);\n\nexport default definePluginEntry({\n id: \"bouncer\",\n name: \"Bouncer Protocol\",\n description: \"Agent-to-agent negotiation channel via the Bouncer Protocol. \" +\n \"Handles WebSocket lifecycle, heartbeats, echo filtering, and protocol \" +\n \"message formatting so the LLM only deals with plain text.\",\n\n register(api: OpenClawPluginApi) {\n const logger = api.logger ?? pluginLogger;\n pluginLogger = logger;\n\n api.registerChannel({ plugin: channel });\n setRuntime(api.runtime);\n\n if (api.runtime.logging) {\n const child = api.runtime.logging.getChildLogger(\"bouncer\");\n if (child) pluginLogger = child;\n }\n\n const bouncerConfig = resolveChannelConfig(api);\n if (!bouncerConfig) {\n logger.warn(\"[bouncer] No bouncer channel config found — will self-start from runtime config.\");\n setTimeout(() => {\n ensureServiceStartedWithTools(api, pluginLogger).catch((err: any) => {\n pluginLogger.error(`[bouncer] Deferred start failed: ${err.message}`);\n });\n }, 2_000);\n return;\n }\n\n const config = resolveConfig(bouncerConfig);\n logger.info(`[bouncer] Registering plugin — role: ${config.role}, agent: ${config.agentId}`);\n\n api.registerService(createBouncerService(config));\n\n const tools = createBrandTools(config, logger);\n for (const tool of tools) {\n api.registerTool(tool, { name: tool.name });\n }\n\n logger.info(`[bouncer] Plugin registered. Role: ${config.role}`);\n if (config.role === \"bouncer\") {\n logger.info(\"[bouncer] Lobby service will start on gateway boot.\");\n } else {\n logger.info(\"[bouncer] Brand tools registered: bouncer_browse, bouncer_profile, bouncer_offer\");\n }\n },\n});\n\nasync function ensureServiceStartedWithTools(api: OpenClawPluginApi, log: PluginLogger): Promise<void> {\n try {\n const cfg = await api.runtime.config.loadConfig();\n const bouncerCfg = cfg?.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncerCfg?.role) {\n log.warn(\"[bouncer] Deferred start: no channels.bouncer.role found in runtime config.\");\n return;\n }\n\n const config = resolveConfig(bouncerCfg);\n log.info(`[bouncer] Deferred registration — role: ${config.role}, agent: ${config.agentId}`);\n\n api.registerService(createBouncerService(config));\n\n const tools = createBrandTools(config, log);\n for (const tool of tools) {\n api.registerTool(tool, { name: tool.name });\n }\n\n if (config.role === \"bouncer\") {\n log.info(\"[bouncer] Lobby service registered via deferred start.\");\n } else {\n log.info(\"[bouncer] Brand tools registered via deferred start: bouncer_browse, bouncer_profile, bouncer_offer\");\n }\n\n await ensureServiceStarted(log);\n } catch (err: any) {\n log.error(`[bouncer] Deferred start failed: ${err.message}`);\n }\n}\n\nfunction resolveChannelConfig(api: OpenClawPluginApi): Record<string, unknown> | null {\n const fromChannels = api.config?.channels?.bouncer as Record<string, unknown> | undefined;\n if (fromChannels && fromChannels.role) return fromChannels;\n\n if (api.pluginConfig && Object.keys(api.pluginConfig).length > 0) {\n return api.pluginConfig;\n }\n\n if (fromChannels && !fromChannels.role) {\n pluginLogger.warn(\n \"[bouncer] channels.bouncer exists but has no 'role' — check config. \" +\n \"Required: role, apiUrl, apiKey, agentId\"\n );\n }\n\n return null;\n}\n"],"mappings":"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","names":["EventEmitter","WebSocket","channel"]}
1
+ {"version":3,"sources":["../src/sdk-types.ts","../src/connector-parser.ts","../src/bouncer-channel.ts","../src/connector-lobby.ts","../src/connector-session.ts","../src/service.ts","../src/types.ts","../src/tools.ts","../index.ts"],"sourcesContent":["/**\n * Minimal type stubs for the OpenClaw Plugin SDK.\n *\n * When installed into an OpenClaw environment, replace these with:\n * import { definePluginEntry } from \"openclaw/plugin-sdk/core\";\n *\n * These stubs match the contract from openclaw/openclaw src/plugin-sdk/core.ts\n * and src/plugins/types.ts as of 2026-03.\n */\n\nexport interface PluginLogger {\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n debug(msg: string, ...args: unknown[]): void;\n}\n\nexport interface ReplyPayload {\n text?: string;\n body?: string;\n mediaUrl?: string;\n mediaUrls?: string[];\n [key: string]: unknown;\n}\n\nexport interface MsgContext {\n Body?: string;\n BodyForAgent?: string;\n RawBody?: string;\n CommandBody?: string;\n From?: string;\n To?: string;\n SessionKey?: string;\n AccountId?: string;\n OriginatingChannel?: string;\n OriginatingTo?: string;\n ChatType?: string;\n SenderName?: string;\n SenderId?: string;\n Provider?: string;\n Surface?: string;\n ConversationLabel?: string;\n Timestamp?: number;\n CommandAuthorized?: boolean;\n [key: string]: unknown;\n}\n\nexport type FinalizedMsgContext = Omit<MsgContext, \"CommandAuthorized\"> & {\n CommandAuthorized: boolean;\n};\n\nexport interface ReplyDispatcherWithTypingOptions {\n deliver: (payload: ReplyPayload, info: { kind: string }) => Promise<void>;\n onReplyStart?: () => Promise<void> | void;\n onIdle?: () => void;\n onCleanup?: () => void;\n [key: string]: unknown;\n}\n\nexport interface DispatchInboundResult {\n [key: string]: unknown;\n}\n\nexport interface PluginRuntime {\n channel: {\n reply: {\n finalizeInboundContext: <T extends Record<string, unknown>>(ctx: T) => T & FinalizedMsgContext;\n dispatchReplyWithBufferedBlockDispatcher: (params: {\n ctx: MsgContext | FinalizedMsgContext;\n cfg: OpenClawConfig;\n dispatcherOptions: ReplyDispatcherWithTypingOptions;\n replyOptions?: Record<string, unknown>;\n }) => Promise<DispatchInboundResult>;\n dispatchReplyFromConfig?: (...args: unknown[]) => Promise<unknown>;\n };\n debounce: {\n createInboundDebouncer: (...args: unknown[]) => unknown;\n resolveInboundDebounceMs: (...args: unknown[]) => number;\n };\n session: {\n recordInboundSession: (...args: unknown[]) => unknown;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n };\n config: {\n loadConfig: () => Promise<OpenClawConfig>;\n writeConfigFile?: (...args: unknown[]) => Promise<void>;\n };\n logging: { shouldLogVerbose(): boolean; getChildLogger(name: string): PluginLogger };\n state: { resolveStateDir(): string };\n}\n\nexport interface OpenClawConfig {\n channels?: Record<string, Record<string, unknown>>;\n plugins?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface OpenClawPluginServiceContext {\n config: OpenClawConfig;\n workspaceDir?: string;\n stateDir: string;\n logger: PluginLogger;\n}\n\nexport interface OpenClawPluginService {\n id: string;\n start: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;\n stop?: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;\n}\n\nexport interface OpenClawPluginToolContext {\n config?: OpenClawConfig;\n agentId?: string;\n sessionKey?: string;\n messageChannel?: string;\n [key: string]: unknown;\n}\n\nexport interface AgentTool {\n name: string;\n description: string;\n parameters?: Record<string, unknown>;\n execute: (params: Record<string, unknown>, ctx?: unknown) => Promise<unknown>;\n}\n\nexport type OpenClawPluginToolFactory = (ctx: OpenClawPluginToolContext) => AgentTool | AgentTool[] | null | undefined;\n\nexport interface OpenClawPluginApi {\n id: string;\n name: string;\n version?: string;\n description?: string;\n source: string;\n rootDir?: string;\n registrationMode: \"full\" | \"setup-only\" | \"setup-runtime\";\n config: OpenClawConfig;\n pluginConfig?: Record<string, unknown>;\n runtime: PluginRuntime;\n logger: PluginLogger;\n\n registerTool: (tool: AgentTool | OpenClawPluginToolFactory, opts?: { name?: string; names?: string[]; optional?: boolean }) => void;\n registerHook: (events: string | string[], handler: (...args: unknown[]) => void | Promise<void>, opts?: Record<string, unknown>) => void;\n registerHttpRoute: (params: Record<string, unknown>) => void;\n registerChannel: (registration: { plugin: ChannelPlugin } | ChannelPlugin) => void;\n registerGatewayMethod: (method: string, handler: (...args: unknown[]) => unknown) => void;\n registerService: (service: OpenClawPluginService) => void;\n registerCommand: (command: { name: string; description: string; handler: (...args: unknown[]) => void | Promise<void> }) => void;\n resolvePath: (input: string) => string;\n on: (hookName: string, handler: (...args: unknown[]) => void | Promise<void>, opts?: { priority?: number }) => void;\n}\n\nexport interface ChannelMeta {\n id: string;\n label: string;\n selectionLabel: string;\n docsPath?: string;\n blurb?: string;\n aliases?: string[];\n order?: number;\n}\n\nexport interface ChannelCapabilities {\n chatTypes: Array<\"direct\" | \"group\">;\n}\n\nexport interface ChannelConfigAdapter {\n listAccountIds: (cfg: OpenClawConfig) => string[];\n resolveAccount: (cfg: OpenClawConfig, accountId?: string) => Record<string, unknown>;\n}\n\nexport interface ChannelOutboundAdapter {\n deliveryMode: \"direct\" | \"queued\";\n sendText: (ctx: SendTextContext) => Promise<{ ok: boolean; error?: string }>;\n}\n\nexport interface SendTextContext {\n text: string;\n conversationId?: string;\n accountId?: string;\n replyTo?: string;\n [key: string]: unknown;\n}\n\nexport interface ChannelLifecycleAdapter {\n startAccount?: (accountId: string, config: Record<string, unknown>, logger: PluginLogger) => Promise<void>;\n stopAccount?: (accountId: string) => Promise<void>;\n}\n\nexport interface ChannelPlugin {\n id: string;\n meta: ChannelMeta;\n capabilities: ChannelCapabilities;\n config: ChannelConfigAdapter;\n outbound?: ChannelOutboundAdapter;\n lifecycle?: ChannelLifecycleAdapter;\n [key: string]: unknown;\n}\n\nexport interface DefinedPluginEntry {\n id: string;\n name: string;\n description: string;\n register: (api: OpenClawPluginApi) => void;\n}\n\nexport function definePluginEntry(opts: {\n id: string;\n name: string;\n description: string;\n register: (api: OpenClawPluginApi) => void;\n}): DefinedPluginEntry {\n return {\n id: opts.id,\n name: opts.name,\n description: opts.description,\n register: opts.register,\n };\n}\n\nexport function defineChannelPluginEntry<TPlugin extends ChannelPlugin>(opts: {\n id: string;\n name: string;\n description: string;\n plugin: TPlugin;\n setRuntime?: (runtime: PluginRuntime) => void;\n registerFull?: (api: OpenClawPluginApi) => void;\n}): DefinedPluginEntry {\n return definePluginEntry({\n id: opts.id,\n name: opts.name,\n description: opts.description,\n register(api) {\n api.registerChannel({ plugin: opts.plugin });\n if (opts.setRuntime) opts.setRuntime(api.runtime);\n if (api.registrationMode === \"full\" && opts.registerFull) {\n opts.registerFull(api);\n }\n },\n });\n}\n","export interface BounceMessage {\n type: \"message\" | \"accept\" | \"walk\" | \"propose_terms\" | \"counter_terms\" | \"research\";\n content: string;\n terms?: Record<string, any>;\n}\n\nconst SIMPLE_PREFIXES: Record<string, BounceMessage[\"type\"]> = {\n \"[ACCEPT]\": \"accept\",\n \"[WALK]\": \"walk\",\n \"[RESEARCH]\": \"research\",\n};\n\nconst TERMS_PREFIXES: Record<string, BounceMessage[\"type\"]> = {\n \"[TERMS]\": \"propose_terms\",\n \"[COUNTER]\": \"counter_terms\",\n};\n\nexport function parseResponse(text: string): BounceMessage {\n const trimmed = text.trim();\n\n for (const [prefix, type] of Object.entries(SIMPLE_PREFIXES)) {\n if (trimmed.startsWith(prefix)) {\n return { type, content: trimmed.slice(prefix.length).trim() };\n }\n }\n\n for (const [prefix, type] of Object.entries(TERMS_PREFIXES)) {\n if (trimmed.startsWith(prefix)) {\n const rest = trimmed.slice(prefix.length);\n const jsonEnd = rest.indexOf(\"}\");\n if (jsonEnd !== -1) {\n const jsonStr = rest.slice(0, jsonEnd + 1);\n try {\n const terms = JSON.parse(jsonStr);\n const content = rest.slice(jsonEnd + 1).trim();\n return { type, content, terms };\n } catch {\n return { type: \"message\", content: trimmed };\n }\n }\n return { type: \"message\", content: trimmed };\n }\n }\n\n return { type: \"message\", content: trimmed };\n}\n","import { parseResponse } from \"./connector-parser.js\";\nimport { NegotiationSession } from \"./connector-session.js\";\nimport type {\n ChannelPlugin,\n OpenClawConfig,\n PluginLogger,\n SendTextContext,\n} from \"./sdk-types.js\";\n\nconst activeSessions = new Map<string, NegotiationSession>();\n\nexport function getActiveSession(negotiationId: string): NegotiationSession | undefined {\n return activeSessions.get(negotiationId);\n}\n\nexport function setActiveSession(negotiationId: string, session: NegotiationSession): void {\n activeSessions.set(negotiationId, session);\n}\n\nexport function removeActiveSession(negotiationId: string): void {\n const session = activeSessions.get(negotiationId);\n if (session) {\n session.close();\n activeSessions.delete(negotiationId);\n }\n}\n\nexport function getActiveNegotiationId(): string | undefined {\n const entries = [...activeSessions.entries()];\n return entries.length > 0 ? entries[0]![0] : undefined;\n}\n\nexport function createBouncerChannel(logger: PluginLogger): ChannelPlugin {\n return {\n id: \"bouncer\",\n\n meta: {\n id: \"bouncer\",\n label: \"Bouncer Protocol\",\n selectionLabel: \"Bouncer Protocol (Agent Negotiation)\",\n docsPath: \"/channels/bouncer\",\n blurb: \"Real-time agent-to-agent negotiation via the Bouncer Protocol\",\n aliases: [\"bouncer-protocol\"],\n order: 90,\n },\n\n capabilities: {\n chatTypes: [\"direct\"],\n },\n\n config: {\n listAccountIds(cfg: OpenClawConfig): string[] {\n const bouncer = cfg.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncer?.agentId) return [];\n return [bouncer.agentId as string];\n },\n\n resolveAccount(cfg: OpenClawConfig, accountId?: string): Record<string, unknown> {\n const bouncer = cfg.channels?.bouncer as Record<string, unknown> | undefined;\n return bouncer ?? { accountId };\n },\n },\n\n outbound: {\n deliveryMode: \"direct\",\n\n async sendText(ctx: SendTextContext): Promise<{ ok: boolean; error?: string }> {\n const negId = ctx.conversationId ?? getActiveNegotiationId();\n if (!negId) {\n return { ok: false, error: \"No active negotiation session\" };\n }\n\n const session = activeSessions.get(negId);\n if (!session) {\n return { ok: false, error: `No session for negotiation ${negId}` };\n }\n\n const parsed = parseResponse(ctx.text);\n\n session.sendThinking();\n\n await new Promise((r) => setTimeout(r, 200));\n\n session.send(parsed);\n logger.info(`[bouncer] Sent ${parsed.type}: ${parsed.content.slice(0, 80)}...`);\n\n return { ok: true };\n },\n },\n };\n}\n","import { EventEmitter } from \"events\";\nimport WebSocket from \"ws\";\n\nlet requestCounter = 0;\n\nexport interface LobbyClientOpts {\n apiUrl: string;\n token: string;\n agentId: string;\n reconnectBaseMs?: number;\n reconnectMaxMs?: number;\n}\n\nexport class LobbyClient extends EventEmitter {\n private ws: WebSocket | null = null;\n private opts: Required<LobbyClientOpts>;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n private lastHeartbeatAt = 0;\n private watchdogTimer: ReturnType<typeof setInterval> | null = null;\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n\n private static readonly HEARTBEAT_STALE_MS = 45_000;\n private static readonly WATCHDOG_INTERVAL_MS = 15_000;\n private static readonly CLIENT_PING_INTERVAL_MS = 25_000;\n\n constructor(opts: LobbyClientOpts) {\n super();\n this.opts = {\n reconnectBaseMs: 1000,\n reconnectMaxMs: 30_000,\n ...opts,\n };\n }\n\n connect(): Promise<void> {\n this.closed = false;\n return this._connect();\n }\n\n private _connect(): Promise<void> {\n this.stopTimers();\n return new Promise((resolve, reject) => {\n const url = `${this.opts.apiUrl}/v1/agents/${this.opts.agentId}/ws?token=${this.opts.token}`;\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.on(\"open\", () => {\n this.reconnectAttempt = 0;\n this.lastHeartbeatAt = Date.now();\n this.startWatchdog();\n this.startClientPing();\n });\n\n ws.on(\"message\", (raw) => {\n try {\n const data = JSON.parse(raw.toString());\n if (data.type === \"connected\") {\n this.lastHeartbeatAt = Date.now();\n this.emit(\"connected\", data);\n resolve();\n } else if (data.type === \"heartbeat\") {\n this.lastHeartbeatAt = Date.now();\n this.emit(\"heartbeat\", data);\n } else if (data.type === \"error\") {\n this.emit(\"error\", new Error(data.error));\n }\n this.emit(data.type, data);\n } catch {}\n });\n\n ws.on(\"close\", () => {\n this.stopTimers();\n if (!this.closed) {\n this.scheduleReconnect();\n }\n });\n\n ws.on(\"error\", (err) => {\n if (this.reconnectAttempt === 0 && ws.readyState === WebSocket.CONNECTING) {\n reject(err);\n }\n });\n });\n }\n\n private startWatchdog() {\n this.watchdogTimer = setInterval(() => {\n if (this.closed) return;\n const staleMs = Date.now() - this.lastHeartbeatAt;\n if (staleMs > LobbyClient.HEARTBEAT_STALE_MS) {\n this.emit(\"stale\", { staleMs });\n this.forceReconnect();\n }\n }, LobbyClient.WATCHDOG_INTERVAL_MS);\n }\n\n private startClientPing() {\n this.pingTimer = setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.ping();\n } catch {}\n }\n }, LobbyClient.CLIENT_PING_INTERVAL_MS);\n }\n\n private stopTimers() {\n if (this.watchdogTimer) { clearInterval(this.watchdogTimer); this.watchdogTimer = null; }\n if (this.pingTimer) { clearInterval(this.pingTimer); this.pingTimer = null; }\n }\n\n private forceReconnect() {\n this.stopTimers();\n if (this.ws) {\n try { this.ws.terminate(); } catch {}\n this.ws = null;\n }\n if (!this.closed) {\n this.scheduleReconnect();\n }\n }\n\n private scheduleReconnect() {\n if (this.closed) return;\n const delay = Math.min(\n this.opts.reconnectBaseMs * Math.pow(2, this.reconnectAttempt),\n this.opts.reconnectMaxMs\n );\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n if (!this.closed) {\n this._connect().catch(() => {});\n }\n }, delay);\n }\n\n accept(negotiationId: string): void {\n this.send({ type: \"accept_negotiation\", negotiation_id: negotiationId });\n }\n\n decline(negotiationId: string, reason?: string): void {\n this.send({ type: \"decline_negotiation\", negotiation_id: negotiationId, reason });\n }\n\n isConnected(): boolean {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;\n if (this.lastHeartbeatAt > 0) {\n const staleMs = Date.now() - this.lastHeartbeatAt;\n if (staleMs > LobbyClient.HEARTBEAT_STALE_MS) return false;\n }\n return true;\n }\n\n send(data: any): boolean {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(data));\n return true;\n }\n return false;\n }\n\n request(msg: Record<string, unknown>, responseType: string, timeoutMs = 30_000): Promise<any> {\n return new Promise((resolve, reject) => {\n if (!this.isConnected()) {\n const staleMs = this.lastHeartbeatAt > 0 ? Date.now() - this.lastHeartbeatAt : -1;\n reject(new Error(`Lobby WS not connected (readyState: ${this.ws?.readyState ?? \"null\"}, lastHeartbeat: ${staleMs}ms ago) — cannot send ${msg.type}`));\n return;\n }\n\n const requestId = `req_${++requestCounter}_${Date.now()}`;\n console.log(`[lobby-request] Sending ${msg.type} with request_id=${requestId}, waiting for ${responseType}`);\n\n const timer = setTimeout(() => {\n const staleMs = this.lastHeartbeatAt > 0 ? Date.now() - this.lastHeartbeatAt : -1;\n console.log(`[lobby-request] TIMEOUT for ${requestId}: readyState=${this.ws?.readyState}, lastHeartbeat=${staleMs}ms ago, listenerCount(${responseType})=${this.listenerCount(responseType)}`);\n cleanup();\n reject(new Error(`WS request timed out waiting for ${responseType} (sent ${msg.type}, waited ${timeoutMs}ms, lastHeartbeat: ${staleMs}ms ago)`));\n }, timeoutMs);\n\n const handler = (data: any) => {\n console.log(`[lobby-request] Got ${responseType} event: request_id=${data.request_id} (waiting for ${requestId})`);\n if (data.request_id === requestId) {\n cleanup();\n if (data.error) {\n reject(new Error(data.error));\n } else {\n resolve(data);\n }\n }\n };\n\n const cleanup = () => {\n clearTimeout(timer);\n this.removeListener(responseType, handler);\n };\n\n this.on(responseType, handler);\n const sent = this.send({ ...msg, request_id: requestId });\n if (!sent) {\n cleanup();\n reject(new Error(`Failed to send ${msg.type} — WS connection dropped between check and send`));\n } else {\n console.log(`[lobby-request] Message sent successfully, readyState=${this.ws?.readyState}`);\n }\n });\n }\n\n close(): void {\n this.closed = true;\n this.stopTimers();\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n if (this.ws) {\n try { this.ws.close(); } catch {}\n this.ws = null;\n }\n }\n}\n","import { EventEmitter } from \"events\";\nimport WebSocket from \"ws\";\n\nexport interface NegotiationSessionOpts {\n apiUrl: string;\n token: string;\n negotiationId: string;\n agentId: string;\n}\n\nexport class NegotiationSession extends EventEmitter {\n private ws: WebSocket | null = null;\n private opts: NegotiationSessionOpts;\n private seenMessageIds = new Set<string>();\n private myAgentId: string;\n\n constructor(opts: NegotiationSessionOpts) {\n super();\n this.opts = opts;\n this.myAgentId = opts.agentId;\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.opts.apiUrl}/v1/negotiations/${this.opts.negotiationId}/ws?token=${this.opts.token}`;\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.on(\"message\", (raw) => {\n try {\n const data = JSON.parse(raw.toString());\n\n if (data.type === \"connected\") {\n if (data.agent_id) this.myAgentId = data.agent_id;\n this.emit(\"connected\", data);\n resolve();\n } else if (data.type === \"negotiation_message\") {\n const msg = data.message ?? {\n id: data.id,\n from_agent_id: data.from_agent_id,\n type: data.message_type ?? data.type,\n content: data.content,\n terms: data.terms,\n is_catchup: data.is_catchup,\n created_at: data.created_at,\n };\n\n const msgId = msg.id;\n if (msgId && this.seenMessageIds.has(msgId)) return;\n if (msgId) this.seenMessageIds.add(msgId);\n\n if (msg.from_agent_id === this.myAgentId) return;\n\n this.emit(\"incoming_message\", msg);\n } else if (data.type === \"negotiation_started\") {\n this.emit(\"negotiation_started\", data);\n } else if (data.type === \"negotiation_ended\") {\n this.emit(\"ended\", data);\n this.close();\n } else if (data.type === \"message_ack\") {\n if (data.message?.id) this.seenMessageIds.add(data.message.id);\n this.emit(\"message_ack\", data);\n } else if (data.type === \"agent_thinking\") {\n this.emit(\"agent_thinking\", data);\n } else if (data.type === \"error\") {\n this.emit(\"error\", new Error(data.error));\n }\n } catch {}\n });\n\n ws.on(\"error\", (err) => {\n if (ws.readyState === WebSocket.CONNECTING) {\n reject(err);\n }\n });\n\n ws.on(\"close\", () => {\n this.emit(\"disconnected\");\n });\n });\n }\n\n send(msg: { type: string; content?: string; terms?: object }): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(msg));\n }\n }\n\n sendThinking(): void {\n this.send({ type: \"thinking\" });\n }\n\n close(): void {\n if (this.ws) {\n try { this.ws.close(); } catch {}\n this.ws = null;\n }\n }\n}\n","import { LobbyClient } from \"./connector-lobby.js\";\nimport { NegotiationSession } from \"./connector-session.js\";\nimport { parseResponse } from \"./connector-parser.js\";\nimport {\n setActiveSession,\n removeActiveSession,\n} from \"./bouncer-channel.js\";\nimport type { BouncerPluginConfig, NegotiationState } from \"./types.js\";\nimport type {\n OpenClawPluginService,\n OpenClawPluginServiceContext,\n PluginLogger,\n PluginRuntime,\n} from \"./sdk-types.js\";\n\nlet lobbyClient: LobbyClient | null = null;\n\nexport function getLobbyClient(): LobbyClient | null {\n return lobbyClient;\n}\nlet activeNegotiation: NegotiationState | null = null;\nlet pluginRuntime: PluginRuntime | null = null;\n\nfunction resolveAgentFromBindings(cfg: any, channel: string): string | null {\n const bindings = cfg?.bindings;\n if (!Array.isArray(bindings)) return null;\n for (const b of bindings) {\n if (b?.match?.channel === channel && b?.agentId) {\n return b.agentId;\n }\n }\n return null;\n}\n\nlet serviceStarted = false;\n\nexport function setRuntime(rt: PluginRuntime): void {\n pluginRuntime = rt;\n}\n\nexport async function ensureServiceStarted(log: PluginLogger): Promise<void> {\n if (serviceStarted || lobbyClient) return;\n if (!pluginRuntime) return;\n\n try {\n const cfg = await pluginRuntime.config.loadConfig();\n const bouncerCfg = cfg?.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncerCfg?.role) return;\n\n const config: BouncerPluginConfig = {\n role: bouncerCfg.role as \"bouncer\" | \"brand\",\n apiUrl: bouncerCfg.apiUrl as string,\n apiKey: bouncerCfg.apiKey as string,\n agentId: bouncerCfg.agentId as string,\n autoAccept: (bouncerCfg.autoAccept as boolean) ?? true,\n llmTimeoutMs: (bouncerCfg.llmTimeoutMs as number) ?? 25_000,\n };\n\n serviceStarted = true;\n log.info(`[bouncer] Self-starting service — role: ${config.role}, agent: ${config.agentId}`);\n\n await startLobby(config, log);\n } catch (err: any) {\n log.error(`[bouncer] Self-start failed: ${err.message}`);\n serviceStarted = false;\n }\n}\n\nexport function getActiveNegotiation(): NegotiationState | null {\n return activeNegotiation;\n}\n\nexport function createBouncerService(config: BouncerPluginConfig): OpenClawPluginService {\n return {\n id: \"bouncer-negotiation-service\",\n\n async start(ctx: OpenClawPluginServiceContext) {\n const log = ctx.logger;\n\n await startLobby(config, log);\n },\n\n async stop() {\n if (lobbyClient) {\n lobbyClient.close();\n lobbyClient = null;\n }\n if (activeNegotiation) {\n removeActiveSession(activeNegotiation.negotiationId);\n activeNegotiation = null;\n }\n },\n };\n}\n\nasync function startLobby(config: BouncerPluginConfig, log: PluginLogger): Promise<void> {\n const wsBase = config.apiUrl.replace(/^http/, \"ws\");\n\n lobbyClient = new LobbyClient({\n apiUrl: wsBase,\n token: config.apiKey,\n agentId: config.agentId,\n reconnectBaseMs: 1_000,\n reconnectMaxMs: 30_000,\n });\n\n lobbyClient.on(\"connected\", () => {\n log.info(`[bouncer] Lobby connected (${config.role} mode).`);\n });\n\n if (config.role === \"bouncer\") {\n lobbyClient.on(\"negotiation_requested\", (data: any) => {\n handleNegotiationRequested(data, config, wsBase, log);\n });\n }\n\n lobbyClient.on(\"heartbeat\", () => {\n log.debug(\"[bouncer] Lobby heartbeat\");\n });\n\n lobbyClient.on(\"stale\", (data: any) => {\n log.warn(`[bouncer] Lobby connection stale (${data.staleMs}ms since last heartbeat) — forcing reconnect`);\n });\n\n try {\n await lobbyClient.connect();\n } catch (err: any) {\n log.error(`[bouncer] Lobby connection failed: ${err.message}`);\n throw err;\n }\n}\n\nasync function handleNegotiationRequested(\n data: any,\n config: BouncerPluginConfig,\n wsBase: string,\n log: PluginLogger,\n): Promise<void> {\n const negId = data.negotiation_id;\n\n if (activeNegotiation) {\n log.info(`[bouncer] Declining ${negId} — already in negotiation ${activeNegotiation.negotiationId}`);\n lobbyClient?.decline(negId, \"busy — already in a negotiation\");\n return;\n }\n\n if (!config.autoAccept) {\n log.info(`[bouncer] Negotiation ${negId} requested but autoAccept is off. Declining.`);\n lobbyClient?.decline(negId, \"auto-accept disabled\");\n return;\n }\n\n log.info(`[bouncer] Accepting negotiation ${negId}`);\n lobbyClient?.accept(negId);\n\n activeNegotiation = {\n negotiationId: negId,\n status: \"pending\",\n otherAgentId: data.brand?.id,\n offerContext: data.offer\n ? { product: data.offer.product, terms: data.offer.terms, opening_message: data.offer.opening_message }\n : undefined,\n };\n\n await connectToNegotiationRoom(negId, config, wsBase, log);\n}\n\nexport async function connectToNegotiationRoom(\n negotiationId: string,\n config: BouncerPluginConfig,\n wsBase: string,\n log: PluginLogger,\n): Promise<void> {\n const session = new NegotiationSession({\n apiUrl: wsBase,\n token: config.apiKey,\n negotiationId,\n agentId: config.agentId,\n });\n\n session.on(\"connected\", () => {\n log.info(`[bouncer] Connected to negotiation room ${negotiationId}`);\n });\n\n session.on(\"negotiation_started\", (data: any) => {\n log.info(`[bouncer] Negotiation ${negotiationId} started`);\n if (activeNegotiation) {\n activeNegotiation.status = \"live\";\n if (data.queue_context) {\n (activeNegotiation as any).queueContext = data.queue_context;\n }\n if (data.relationship) {\n (activeNegotiation as any).relationship = data.relationship;\n }\n }\n });\n\n let dispatching = false;\n session.on(\"incoming_message\", (msg: any) => {\n if (dispatching) {\n log.debug(`[bouncer] Skipping message while dispatch in progress`);\n return;\n }\n log.info(`[bouncer] Message from ${msg.from_agent_id}: ${(msg.content ?? \"\").slice(0, 80)}...`);\n dispatching = true;\n dispatchToAgent(negotiationId, msg, config, session, log).finally(() => {\n dispatching = false;\n });\n });\n\n session.on(\"agent_thinking\", () => {\n log.debug(`[bouncer] Other agent thinking in ${negotiationId}`);\n });\n\n session.on(\"ended\", (data: any) => {\n log.info(`[bouncer] Negotiation ${negotiationId} ended: ${data?.status ?? \"unknown\"}`);\n removeActiveSession(negotiationId);\n activeNegotiation = null;\n });\n\n session.on(\"disconnected\", () => {\n log.warn(`[bouncer] Disconnected from negotiation ${negotiationId}`);\n });\n\n setActiveSession(negotiationId, session);\n\n try {\n await session.connect();\n } catch (err: any) {\n log.error(`[bouncer] Failed to connect to negotiation ${negotiationId}: ${err.message}`);\n removeActiveSession(negotiationId);\n activeNegotiation = null;\n }\n}\n\nasync function dispatchToAgent(\n negotiationId: string,\n msg: any,\n config: BouncerPluginConfig,\n session: NegotiationSession,\n log: PluginLogger,\n): Promise<void> {\n if (!pluginRuntime) {\n log.error(\"[bouncer] Runtime not set — cannot dispatch inbound message to agent\");\n return;\n }\n\n const rt = pluginRuntime;\n\n try {\n const currentCfg = await rt.config.loadConfig();\n\n const resolvedAgent = resolveAgentFromBindings(currentCfg, \"bouncer\");\n if (resolvedAgent) {\n log.info(`[bouncer] Routing negotiation ${negotiationId} to agent: ${resolvedAgent}`);\n }\n\n const msgCtx = rt.channel.reply.finalizeInboundContext({\n Body: msg.content ?? \"\",\n RawBody: msg.content ?? \"\",\n CommandBody: msg.content ?? \"\",\n From: `bouncer:${msg.from_agent_id}`,\n To: `bouncer:${config.agentId}`,\n SessionKey: `bouncer:${negotiationId}`,\n AccountId: config.agentId,\n OriginatingChannel: \"bouncer\",\n OriginatingTo: `bouncer:${msg.from_agent_id}`,\n ChatType: \"direct\",\n SenderName: msg.from_agent_id,\n SenderId: msg.from_agent_id,\n Provider: \"bouncer\",\n Surface: \"bouncer\",\n ConversationLabel: `Negotiation ${negotiationId}`,\n Timestamp: Date.now(),\n CommandAuthorized: true,\n ...(resolvedAgent ? { AgentId: resolvedAgent, TargetAgentId: resolvedAgent, ResolvedAgentId: resolvedAgent } : {}),\n });\n\n await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: msgCtx,\n cfg: currentCfg,\n dispatcherOptions: {\n deliver: async (payload) => {\n const text = payload?.text ?? payload?.body;\n if (!text) return;\n\n const parsed = parseResponse(text);\n session.sendThinking();\n await new Promise((r) => setTimeout(r, 200));\n session.send(parsed);\n log.info(`[bouncer] Agent replied (${parsed.type}): ${parsed.content.slice(0, 80)}...`);\n },\n onReplyStart: () => {\n session.sendThinking();\n },\n },\n });\n } catch (err: any) {\n log.error(`[bouncer] Dispatch failed for negotiation ${negotiationId}: ${err.message}`);\n }\n}\n","export interface BouncerPluginConfig {\n role: \"bouncer\" | \"brand\";\n apiUrl: string;\n apiKey: string;\n agentId: string;\n autoAccept?: boolean;\n llmTimeoutMs?: number;\n}\n\nexport interface NegotiationState {\n negotiationId: string;\n status: \"pending\" | \"live\" | \"ended\";\n otherAgentId?: string;\n offerContext?: {\n product: string;\n terms: string;\n opening_message: string;\n };\n}\n\nexport interface InboundNegotiationMessage {\n negotiationId: string;\n fromAgentId: string;\n type: string;\n content: string;\n terms?: Record<string, unknown>;\n timestamp: string;\n}\n\nexport function resolveConfig(pluginConfig: Record<string, unknown> | undefined): BouncerPluginConfig {\n if (!pluginConfig) throw new Error(\"Bouncer plugin config is required\");\n\n const role = pluginConfig.role as string;\n if (role !== \"bouncer\" && role !== \"brand\") {\n throw new Error(`Invalid role \"${role}\" — must be \"bouncer\" or \"brand\"`);\n }\n\n return {\n role,\n apiUrl: pluginConfig.apiUrl as string,\n apiKey: pluginConfig.apiKey as string,\n agentId: pluginConfig.agentId as string,\n autoAccept: (pluginConfig.autoAccept as boolean) ?? true,\n llmTimeoutMs: (pluginConfig.llmTimeoutMs as number) ?? 25_000,\n };\n}\n\nexport function wsUrl(apiUrl: string): string {\n return apiUrl.replace(/^http/, \"ws\");\n}\n","import type { AgentTool, PluginLogger } from \"./sdk-types.js\";\nimport type { BouncerPluginConfig } from \"./types.js\";\nimport { connectToNegotiationRoom, getLobbyClient } from \"./service.js\";\nimport { wsUrl } from \"./types.js\";\n\nexport function createBrandTools(config: BouncerPluginConfig, logger: PluginLogger): AgentTool[] {\n if (config.role !== \"brand\") return [];\n\n const bouncerBrowse: AgentTool = {\n name: \"bouncer_browse\",\n description:\n \"Browse available Bouncer agents in the directory. Returns a list of bouncers \" +\n \"with their name, listing, tags, and reputation score. Use this to find a \" +\n \"bouncer to target with an offer.\",\n parameters: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n description: \"Max results to return (default: 20)\",\n },\n },\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { error: \"Not connected to lobby\" };\n\n try {\n const result = await lobby.request(\n { type: \"browse_bouncers\", limit: params.limit ?? 20 },\n \"browse_bouncers_result\",\n );\n logger.info(`[bouncer] Browse returned ${result.bouncers?.length ?? 0} bouncers`);\n return result.bouncers;\n } catch (err: any) {\n return { error: `Browse failed: ${err.message}` };\n }\n },\n };\n\n const bouncerProfile: AgentTool = {\n name: \"bouncer_profile\",\n description:\n \"Get the full profile of a specific Bouncer agent, including their listing, \" +\n \"enrichment data, engagement rules, and verified credentials. Use this before \" +\n \"crafting a personalized offer.\",\n parameters: {\n type: \"object\",\n properties: {\n bouncer_id: {\n type: \"string\",\n description: \"The Bouncer agent's UUID\",\n },\n },\n required: [\"bouncer_id\"],\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { error: \"Not connected to lobby\" };\n\n try {\n const result = await lobby.request(\n { type: \"get_profile\", bouncer_id: params.bouncer_id },\n \"get_profile_result\",\n );\n if (result.error) return { error: result.error };\n return result.profile;\n } catch (err: any) {\n return { error: `Profile fetch failed: ${err.message}` };\n }\n },\n };\n\n const bouncerOffer: AgentTool = {\n name: \"bouncer_offer\",\n description:\n \"Submit an offer to a Bouncer agent and create a negotiation. This sends your \" +\n \"offer and automatically connects you to the negotiation room when the bouncer \" +\n \"accepts. Returns the offer_id and negotiation_id.\",\n parameters: {\n type: \"object\",\n properties: {\n bouncer_id: {\n type: \"string\",\n description: \"The target Bouncer's UUID\",\n },\n product: {\n type: \"string\",\n description: \"Product or service being offered\",\n },\n terms: {\n type: \"string\",\n description: \"Deal terms (e.g. '$20 credit + free delivery')\",\n },\n opening_message: {\n type: \"string\",\n description: \"Personalized opening message to the Bouncer\",\n },\n priority_bid: {\n type: \"number\",\n description: \"Priority bid in USDC (e.g. 2.0)\",\n },\n arena: {\n type: \"boolean\",\n description: \"Practice mode — no real USDC (default: false)\",\n },\n },\n required: [\"bouncer_id\", \"product\", \"terms\", \"opening_message\", \"priority_bid\"],\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) {\n logger.error(\"[bouncer] bouncer_offer: getLobbyClient() returned null — lobby not initialized\");\n return { error: \"Not connected to lobby\" };\n }\n\n const connected = lobby.isConnected();\n logger.info(`[bouncer] bouncer_offer: lobby.isConnected() = ${connected}`);\n if (!connected) {\n logger.error(\"[bouncer] bouncer_offer: lobby exists but isConnected() is false — WS may be reconnecting\");\n return { error: \"Lobby WS not connected — may be reconnecting. Try again in a few seconds.\" };\n }\n\n const bouncerId = params.bouncer_id as string;\n\n try {\n logger.info(`[bouncer] Submitting offer to ${bouncerId}`);\n const sendStart = Date.now();\n\n const offerResult = await lobby.request(\n {\n type: \"submit_offer\",\n bouncer_id: bouncerId,\n product: params.product,\n terms: params.terms,\n opening_message: params.opening_message,\n priority_bid: params.priority_bid,\n arena: params.arena ?? false,\n },\n \"submit_offer_result\",\n );\n\n logger.info(`[bouncer] submit_offer response in ${Date.now() - sendStart}ms`);\n\n if (offerResult.error) {\n return { error: `Offer submission failed: ${offerResult.error}` };\n }\n\n const offerId = offerResult.offer_id;\n logger.info(`[bouncer] Offer submitted: ${offerId}`);\n\n logger.info(`[bouncer] Creating negotiation for offer ${offerId}`);\n const negResult = await lobby.request(\n { type: \"create_negotiation\", offer_id: offerId, bouncer_id: bouncerId },\n \"create_negotiation_result\",\n );\n\n if (negResult.error) {\n return { error: `Negotiation creation failed: ${negResult.error}`, offer_id: offerId };\n }\n\n const negotiationId = negResult.negotiation_id;\n logger.info(`[bouncer] Negotiation created: ${negotiationId}`);\n\n logger.info(`[bouncer] Waiting for bouncer to accept (via WS)...`);\n const accepted = await waitForAcceptanceWS(negotiationId, 120_000);\n\n if (!accepted) {\n return { status: \"declined_or_timeout\", offer_id: offerId, negotiation_id: negotiationId };\n }\n\n logger.info(`[bouncer] Accepted! Connecting to negotiation room...`);\n await connectToNegotiationRoom(negotiationId, config, wsUrl(config.apiUrl), logger);\n\n return {\n status: \"connected\",\n offer_id: offerId,\n negotiation_id: negotiationId,\n message: \"Connected to negotiation room. Incoming messages will appear as chat messages.\",\n };\n } catch (err: any) {\n return { error: `Offer flow failed: ${err.message}` };\n }\n },\n };\n\n return [bouncerBrowse, bouncerProfile, bouncerOffer];\n}\n\nfunction waitForAcceptanceWS(negotiationId: string, timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n const lobby = getLobbyClient();\n if (!lobby) {\n resolve(false);\n return;\n }\n\n const timer = setTimeout(() => {\n cleanup();\n resolve(false);\n }, timeoutMs);\n\n const onAccepted = (data: any) => {\n if (data.negotiation_id === negotiationId) {\n cleanup();\n resolve(true);\n }\n };\n\n const onDeclined = (data: any) => {\n if (data.negotiation_id === negotiationId) {\n cleanup();\n resolve(false);\n }\n };\n\n const cleanup = () => {\n clearTimeout(timer);\n lobby.removeListener(\"negotiation_accepted\", onAccepted);\n lobby.removeListener(\"negotiation_declined\", onDeclined);\n };\n\n lobby.on(\"negotiation_accepted\", onAccepted);\n lobby.on(\"negotiation_declined\", onDeclined);\n });\n}\n","import { definePluginEntry } from \"./src/sdk-types.js\";\nimport { createBouncerChannel } from \"./src/bouncer-channel.js\";\nimport { createBouncerService, setRuntime, ensureServiceStarted } from \"./src/service.js\";\nimport { createBrandTools } from \"./src/tools.js\";\nimport { resolveConfig } from \"./src/types.js\";\nimport type { OpenClawPluginApi, PluginLogger } from \"./src/sdk-types.js\";\n\nlet pluginLogger: PluginLogger = {\n info: console.log,\n warn: console.warn,\n error: console.error,\n debug: () => {},\n};\n\nconst channel = createBouncerChannel(pluginLogger);\n\nexport default definePluginEntry({\n id: \"bouncer\",\n name: \"Bouncer Protocol\",\n description: \"Agent-to-agent negotiation channel via the Bouncer Protocol. \" +\n \"Handles WebSocket lifecycle, heartbeats, echo filtering, and protocol \" +\n \"message formatting so the LLM only deals with plain text.\",\n\n register(api: OpenClawPluginApi) {\n const logger = api.logger ?? pluginLogger;\n pluginLogger = logger;\n\n api.registerChannel({ plugin: channel });\n setRuntime(api.runtime);\n\n if (api.runtime.logging) {\n const child = api.runtime.logging.getChildLogger(\"bouncer\");\n if (child) pluginLogger = child;\n }\n\n const bouncerConfig = resolveChannelConfig(api);\n if (!bouncerConfig) {\n logger.warn(\"[bouncer] No bouncer channel config found — will self-start from runtime config.\");\n setTimeout(() => {\n ensureServiceStartedWithTools(api, pluginLogger).catch((err: any) => {\n pluginLogger.error(`[bouncer] Deferred start failed: ${err.message}`);\n });\n }, 2_000);\n return;\n }\n\n const config = resolveConfig(bouncerConfig);\n logger.info(`[bouncer] Registering plugin — role: ${config.role}, agent: ${config.agentId}`);\n\n api.registerService(createBouncerService(config));\n\n const tools = createBrandTools(config, logger);\n for (const tool of tools) {\n api.registerTool(tool, { name: tool.name });\n }\n\n logger.info(`[bouncer] Plugin registered. Role: ${config.role}`);\n if (config.role === \"bouncer\") {\n logger.info(\"[bouncer] Lobby service will start on gateway boot.\");\n } else {\n logger.info(\"[bouncer] Brand tools registered: bouncer_browse, bouncer_profile, bouncer_offer\");\n }\n },\n});\n\nasync function ensureServiceStartedWithTools(api: OpenClawPluginApi, log: PluginLogger): Promise<void> {\n try {\n const cfg = await api.runtime.config.loadConfig();\n const bouncerCfg = cfg?.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncerCfg?.role) {\n log.warn(\"[bouncer] Deferred start: no channels.bouncer.role found in runtime config.\");\n return;\n }\n\n const config = resolveConfig(bouncerCfg);\n log.info(`[bouncer] Deferred registration — role: ${config.role}, agent: ${config.agentId}`);\n\n api.registerService(createBouncerService(config));\n\n const tools = createBrandTools(config, log);\n for (const tool of tools) {\n api.registerTool(tool, { name: tool.name });\n }\n\n if (config.role === \"bouncer\") {\n log.info(\"[bouncer] Lobby service registered via deferred start.\");\n } else {\n log.info(\"[bouncer] Brand tools registered via deferred start: bouncer_browse, bouncer_profile, bouncer_offer\");\n }\n\n await ensureServiceStarted(log);\n } catch (err: any) {\n log.error(`[bouncer] Deferred start failed: ${err.message}`);\n }\n}\n\nfunction resolveChannelConfig(api: OpenClawPluginApi): Record<string, unknown> | null {\n const fromChannels = api.config?.channels?.bouncer as Record<string, unknown> | undefined;\n if (fromChannels && fromChannels.role) return fromChannels;\n\n if (api.pluginConfig && Object.keys(api.pluginConfig).length > 0) {\n return api.pluginConfig;\n }\n\n if (fromChannels && !fromChannels.role) {\n pluginLogger.warn(\n \"[bouncer] channels.bouncer exists but has no 'role' — check config. \" +\n \"Required: role, apiUrl, apiKey, agentId\"\n );\n }\n\n return null;\n}\n"],"mappings":"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","names":["EventEmitter","WebSocket","channel"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bouncer-protocol/bouncer",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for the Bouncer Protocol — bridges agent negotiations over WebSocket",
6
6
  "main": "./dist/index.js",