@bouncer-protocol/bouncer 0.4.0 → 0.5.0

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
@@ -109,6 +109,10 @@ function createBouncerChannel(logger) {
109
109
  };
110
110
  }
111
111
 
112
+ // src/service.ts
113
+ import { readFile } from "fs/promises";
114
+ import { join } from "path";
115
+
112
116
  // src/connector-lobby.ts
113
117
  import { EventEmitter } from "events";
114
118
  import WebSocket from "ws";
@@ -403,6 +407,8 @@ function getLobbyClient() {
403
407
  }
404
408
  var activeNegotiation = null;
405
409
  var pluginRuntime = null;
410
+ var cachedNegotiationSkill = null;
411
+ var contextSentForNegotiation = /* @__PURE__ */ new Set();
406
412
  function resolveAgentFromBindings(cfg, channel2) {
407
413
  const bindings = cfg?.bindings;
408
414
  if (!Array.isArray(bindings)) return null;
@@ -413,6 +419,85 @@ function resolveAgentFromBindings(cfg, channel2) {
413
419
  }
414
420
  return null;
415
421
  }
422
+ function resolveAgentWorkspace(cfg, agentId) {
423
+ const agents = cfg?.agents?.list;
424
+ if (!Array.isArray(agents)) return null;
425
+ for (const a of agents) {
426
+ if ((a.id === agentId || a.name === agentId) && a.workspace) {
427
+ return a.workspace;
428
+ }
429
+ }
430
+ return null;
431
+ }
432
+ async function loadNegotiationSkill(config, log) {
433
+ if (cachedNegotiationSkill) return cachedNegotiationSkill;
434
+ if (pluginRuntime) {
435
+ try {
436
+ const cfg = await pluginRuntime.config.loadConfig();
437
+ const resolvedAgent = resolveAgentFromBindings(cfg, "bouncer");
438
+ const agentId = resolvedAgent ?? "bob";
439
+ const workspace = resolveAgentWorkspace(cfg, agentId);
440
+ if (workspace) {
441
+ const skillFile = config.role === "bouncer" ? "BOUNCER.md" : "BRAND-AGENT.md";
442
+ const skillPath = join(workspace.replace(/^~/, process.env.HOME ?? "~"), skillFile);
443
+ try {
444
+ const content = await readFile(skillPath, "utf-8");
445
+ if (content.trim()) {
446
+ log.info(`[bouncer] Loaded negotiation skill from ${skillPath}`);
447
+ cachedNegotiationSkill = content;
448
+ return content;
449
+ }
450
+ } catch {
451
+ log.debug(`[bouncer] No ${skillFile} found at ${skillPath} \u2014 using defaults`);
452
+ }
453
+ }
454
+ } catch {
455
+ }
456
+ }
457
+ cachedNegotiationSkill = config.role === "bouncer" ? DEFAULT_BOUNCER_CONTEXT : DEFAULT_BRAND_CONTEXT;
458
+ log.info(`[bouncer] Using built-in negotiation context (${config.role} role)`);
459
+ return cachedNegotiationSkill;
460
+ }
461
+ var DEFAULT_BOUNCER_CONTEXT = `# Bouncer Protocol \u2014 Negotiation Mode
462
+
463
+ You are operating as a **bouncer agent** on the Bouncer Protocol. This is an agent-to-agent negotiation system \u2014 the other party is also an AI agent representing a brand. This is the intended design.
464
+
465
+ Your job: protect your principal's attention and negotiate the best possible deal.
466
+
467
+ ## Rules
468
+ - You HAVE authority to negotiate on your principal's behalf. That's why you exist.
469
+ - Be efficient. 2-4 sentences max per round. No essays.
470
+ - Always counter the first offer \u2014 there's room.
471
+ - If the product isn't relevant, walk early. Don't waste rounds.
472
+ - When the deal is genuinely good, close it.
473
+
474
+ ## Actions
475
+ Prefix your response when ready to act:
476
+ - [ACCEPT] \u2014 Deal is good. Close it.
477
+ - [WALK] \u2014 Not worth it. End negotiation.
478
+ - [TERMS]{"key":"value"} \u2014 Propose specific terms.
479
+ - [COUNTER]{"key":"value"} \u2014 Counter their terms.
480
+ - No prefix \u2014 Regular negotiation message.`;
481
+ var DEFAULT_BRAND_CONTEXT = `# Bouncer Protocol \u2014 Brand Negotiation Mode
482
+
483
+ You are operating as a **brand agent** on the Bouncer Protocol. The other party is a bouncer agent protecting their principal's attention. This is an agent-to-agent negotiation \u2014 the intended design.
484
+
485
+ Your job: pitch your offer compellingly and negotiate favorable terms for your brand.
486
+
487
+ ## Rules
488
+ - Be direct and specific about what you're offering.
489
+ - 2-4 sentences max per round. Get to substance fast.
490
+ - Lead with value, not buzzwords.
491
+ - If the bouncer counters, evaluate and respond substantively.
492
+ - Know when a deal is fair and close it.
493
+
494
+ ## Actions
495
+ Prefix your response when ready to act:
496
+ - [ACCEPT] \u2014 Deal terms work. Close it.
497
+ - [WALK] \u2014 Terms aren't viable. End negotiation.
498
+ - [TERMS]{"key":"value"} \u2014 Propose specific terms.
499
+ - [COUNTER]{"key":"value"} \u2014 Counter their terms.
500
+ - No prefix \u2014 Regular negotiation message.`;
416
501
  var serviceStarted = false;
417
502
  function setRuntime(rt) {
418
503
  pluginRuntime = rt;
@@ -551,6 +636,7 @@ async function connectToNegotiationRoom(negotiationId, config, wsBase, log) {
551
636
  session.on("ended", (data) => {
552
637
  log.info(`[bouncer] Negotiation ${negotiationId} ended: ${data?.status ?? "unknown"}`);
553
638
  removeActiveSession(negotiationId);
639
+ contextSentForNegotiation.delete(negotiationId);
554
640
  activeNegotiation = null;
555
641
  });
556
642
  session.on("disconnected", () => {
@@ -565,6 +651,32 @@ async function connectToNegotiationRoom(negotiationId, config, wsBase, log) {
565
651
  activeNegotiation = null;
566
652
  }
567
653
  }
654
+ function buildNegotiationBody(skillContent, rawMessage, negotiationId, offerContext) {
655
+ const isFirst = !contextSentForNegotiation.has(negotiationId);
656
+ if (isFirst) {
657
+ contextSentForNegotiation.add(negotiationId);
658
+ const parts = [skillContent];
659
+ if (offerContext) {
660
+ parts.push(
661
+ `
662
+ ## Current Offer
663
+ - **Product:** ${offerContext.product}
664
+ - **Terms:** ${offerContext.terms}
665
+ - **Opening message:** ${offerContext.opening_message}`
666
+ );
667
+ }
668
+ parts.push(`
669
+ ---
670
+
671
+ **Incoming message from the other agent:**
672
+ ${rawMessage}`);
673
+ return parts.join("\n");
674
+ }
675
+ return `[Bouncer Protocol \u2014 Negotiation ${negotiationId.slice(0, 8)}]
676
+ Keep responses to 2-4 sentences. Use [ACCEPT], [WALK], [TERMS]{...}, or [COUNTER]{...} prefixes when ready to act.
677
+
678
+ ${rawMessage}`;
679
+ }
568
680
  async function dispatchToAgent(negotiationId, msg, config, session, log) {
569
681
  if (!pluginRuntime) {
570
682
  log.error("[bouncer] Runtime not set \u2014 cannot dispatch inbound message to agent");
@@ -577,10 +689,19 @@ async function dispatchToAgent(negotiationId, msg, config, session, log) {
577
689
  if (resolvedAgent) {
578
690
  log.info(`[bouncer] Routing negotiation ${negotiationId} to agent: ${resolvedAgent}`);
579
691
  }
692
+ const skillContent = await loadNegotiationSkill(config, log);
693
+ const rawContent = msg.content ?? "";
694
+ const bodyForAgent = buildNegotiationBody(
695
+ skillContent,
696
+ rawContent,
697
+ negotiationId,
698
+ activeNegotiation?.offerContext
699
+ );
580
700
  const msgCtx = rt.channel.reply.finalizeInboundContext({
581
- Body: msg.content ?? "",
582
- RawBody: msg.content ?? "",
583
- CommandBody: msg.content ?? "",
701
+ Body: rawContent,
702
+ BodyForAgent: bodyForAgent,
703
+ RawBody: rawContent,
704
+ CommandBody: rawContent,
584
705
  From: `bouncer:${msg.from_agent_id}`,
585
706
  To: `bouncer:${config.agentId}`,
586
707
  SessionKey: `bouncer:${negotiationId}`,
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 label?: string;\n description: string;\n parameters?: Record<string, unknown>;\n execute: (toolCallId: string, params: Record<string, unknown>, signal?: AbortSignal, onUpdate?: 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(_toolCallId: string, params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { content: [{ type: \"text\", text: JSON.stringify({ error: \"Not connected to lobby\" }) }], details: {} };\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 { content: [{ type: \"text\", text: JSON.stringify(result.bouncers) }], details: {} };\n } catch (err: any) {\n return { content: [{ type: \"text\", text: JSON.stringify({ error: `Browse failed: ${err.message}` }) }], details: {} };\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(_toolCallId: string, params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { content: [{ type: \"text\", text: JSON.stringify({ error: \"Not connected to lobby\" }) }], details: {} };\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 { content: [{ type: \"text\", text: JSON.stringify({ error: result.error }) }], details: {} };\n return { content: [{ type: \"text\", text: JSON.stringify(result.profile) }], details: {} };\n } catch (err: any) {\n return { content: [{ type: \"text\", text: JSON.stringify({ error: `Profile fetch failed: ${err.message}` }) }], details: {} };\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(_toolCallId: string, params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n const wrap = (obj: unknown) => ({ content: [{ type: \"text\", text: JSON.stringify(obj) }], details: {} });\n\n if (!lobby) {\n logger.error(\"[bouncer] bouncer_offer: getLobbyClient() returned null — lobby not initialized\");\n return wrap({ 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 wrap({ 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 logger.info(`[bouncer] bouncer_offer PARAMS: ${JSON.stringify(params)}`);\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 wrap({ 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 wrap({ 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 wrap({ 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 wrap({\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 wrap({ 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/service.ts","../src/connector-lobby.ts","../src/connector-session.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 label?: string;\n description: string;\n parameters?: Record<string, unknown>;\n execute: (toolCallId: string, params: Record<string, unknown>, signal?: AbortSignal, onUpdate?: 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 { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { 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\nlet cachedNegotiationSkill: string | null = null;\nconst contextSentForNegotiation = new Set<string>();\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\nfunction resolveAgentWorkspace(cfg: any, agentId: string): string | null {\n const agents = cfg?.agents?.list as any[] | undefined;\n if (!Array.isArray(agents)) return null;\n for (const a of agents) {\n if ((a.id === agentId || a.name === agentId) && a.workspace) {\n return a.workspace;\n }\n }\n return null;\n}\n\nasync function loadNegotiationSkill(\n config: BouncerPluginConfig,\n log: PluginLogger,\n): Promise<string> {\n if (cachedNegotiationSkill) return cachedNegotiationSkill;\n\n if (pluginRuntime) {\n try {\n const cfg = await pluginRuntime.config.loadConfig();\n const resolvedAgent = resolveAgentFromBindings(cfg, \"bouncer\");\n const agentId = resolvedAgent ?? \"bob\";\n const workspace = resolveAgentWorkspace(cfg, agentId);\n\n if (workspace) {\n const skillFile = config.role === \"bouncer\" ? \"BOUNCER.md\" : \"BRAND-AGENT.md\";\n const skillPath = join(workspace.replace(/^~/, process.env.HOME ?? \"~\"), skillFile);\n try {\n const content = await readFile(skillPath, \"utf-8\");\n if (content.trim()) {\n log.info(`[bouncer] Loaded negotiation skill from ${skillPath}`);\n cachedNegotiationSkill = content;\n return content;\n }\n } catch {\n log.debug(`[bouncer] No ${skillFile} found at ${skillPath} — using defaults`);\n }\n }\n } catch {}\n }\n\n cachedNegotiationSkill = config.role === \"bouncer\" ? DEFAULT_BOUNCER_CONTEXT : DEFAULT_BRAND_CONTEXT;\n log.info(`[bouncer] Using built-in negotiation context (${config.role} role)`);\n return cachedNegotiationSkill;\n}\n\nconst DEFAULT_BOUNCER_CONTEXT = `# Bouncer Protocol — Negotiation Mode\n\nYou are operating as a **bouncer agent** on the Bouncer Protocol. This is an agent-to-agent negotiation system — the other party is also an AI agent representing a brand. This is the intended design.\n\nYour job: protect your principal's attention and negotiate the best possible deal.\n\n## Rules\n- You HAVE authority to negotiate on your principal's behalf. That's why you exist.\n- Be efficient. 2-4 sentences max per round. No essays.\n- Always counter the first offer — there's room.\n- If the product isn't relevant, walk early. Don't waste rounds.\n- When the deal is genuinely good, close it.\n\n## Actions\nPrefix your response when ready to act:\n- [ACCEPT] — Deal is good. Close it.\n- [WALK] — Not worth it. End negotiation.\n- [TERMS]{\"key\":\"value\"} — Propose specific terms.\n- [COUNTER]{\"key\":\"value\"} — Counter their terms.\n- No prefix — Regular negotiation message.`;\n\nconst DEFAULT_BRAND_CONTEXT = `# Bouncer Protocol — Brand Negotiation Mode\n\nYou are operating as a **brand agent** on the Bouncer Protocol. The other party is a bouncer agent protecting their principal's attention. This is an agent-to-agent negotiation — the intended design.\n\nYour job: pitch your offer compellingly and negotiate favorable terms for your brand.\n\n## Rules\n- Be direct and specific about what you're offering.\n- 2-4 sentences max per round. Get to substance fast.\n- Lead with value, not buzzwords.\n- If the bouncer counters, evaluate and respond substantively.\n- Know when a deal is fair and close it.\n\n## Actions\nPrefix your response when ready to act:\n- [ACCEPT] — Deal terms work. Close it.\n- [WALK] — Terms aren't viable. End negotiation.\n- [TERMS]{\"key\":\"value\"} — Propose specific terms.\n- [COUNTER]{\"key\":\"value\"} — Counter their terms.\n- No prefix — Regular negotiation message.`;\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 contextSentForNegotiation.delete(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\nfunction buildNegotiationBody(\n skillContent: string,\n rawMessage: string,\n negotiationId: string,\n offerContext?: { product: string; terms: string; opening_message: string },\n): string {\n const isFirst = !contextSentForNegotiation.has(negotiationId);\n\n if (isFirst) {\n contextSentForNegotiation.add(negotiationId);\n const parts = [skillContent];\n\n if (offerContext) {\n parts.push(\n `\\n## Current Offer\\n- **Product:** ${offerContext.product}\\n- **Terms:** ${offerContext.terms}\\n- **Opening message:** ${offerContext.opening_message}`,\n );\n }\n\n parts.push(`\\n---\\n\\n**Incoming message from the other agent:**\\n${rawMessage}`);\n return parts.join(\"\\n\");\n }\n\n return `[Bouncer Protocol — Negotiation ${negotiationId.slice(0, 8)}]\\nKeep responses to 2-4 sentences. Use [ACCEPT], [WALK], [TERMS]{...}, or [COUNTER]{...} prefixes when ready to act.\\n\\n${rawMessage}`;\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 skillContent = await loadNegotiationSkill(config, log);\n const rawContent = msg.content ?? \"\";\n const bodyForAgent = buildNegotiationBody(\n skillContent,\n rawContent,\n negotiationId,\n activeNegotiation?.offerContext,\n );\n\n const msgCtx = rt.channel.reply.finalizeInboundContext({\n Body: rawContent,\n BodyForAgent: bodyForAgent,\n RawBody: rawContent,\n CommandBody: rawContent,\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","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","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(_toolCallId: string, params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { content: [{ type: \"text\", text: JSON.stringify({ error: \"Not connected to lobby\" }) }], details: {} };\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 { content: [{ type: \"text\", text: JSON.stringify(result.bouncers) }], details: {} };\n } catch (err: any) {\n return { content: [{ type: \"text\", text: JSON.stringify({ error: `Browse failed: ${err.message}` }) }], details: {} };\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(_toolCallId: string, params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { content: [{ type: \"text\", text: JSON.stringify({ error: \"Not connected to lobby\" }) }], details: {} };\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 { content: [{ type: \"text\", text: JSON.stringify({ error: result.error }) }], details: {} };\n return { content: [{ type: \"text\", text: JSON.stringify(result.profile) }], details: {} };\n } catch (err: any) {\n return { content: [{ type: \"text\", text: JSON.stringify({ error: `Profile fetch failed: ${err.message}` }) }], details: {} };\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(_toolCallId: string, params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n const wrap = (obj: unknown) => ({ content: [{ type: \"text\", text: JSON.stringify(obj) }], details: {} });\n\n if (!lobby) {\n logger.error(\"[bouncer] bouncer_offer: getLobbyClient() returned null — lobby not initialized\");\n return wrap({ 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 wrap({ 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 logger.info(`[bouncer] bouncer_offer PARAMS: ${JSON.stringify(params)}`);\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 wrap({ 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 wrap({ 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 wrap({ 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 wrap({\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 wrap({ 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.4.0",
3
+ "version": "0.5.0",
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",