@bouncer-protocol/bouncer 0.3.2 → 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.d.ts +2 -1
- package/dist/index.js +144 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -115,9 +115,10 @@ interface OpenClawPluginToolContext {
|
|
|
115
115
|
}
|
|
116
116
|
interface AgentTool {
|
|
117
117
|
name: string;
|
|
118
|
+
label?: string;
|
|
118
119
|
description: string;
|
|
119
120
|
parameters?: Record<string, unknown>;
|
|
120
|
-
execute: (params: Record<string, unknown>,
|
|
121
|
+
execute: (toolCallId: string, params: Record<string, unknown>, signal?: AbortSignal, onUpdate?: unknown) => Promise<unknown>;
|
|
121
122
|
}
|
|
122
123
|
type OpenClawPluginToolFactory = (ctx: OpenClawPluginToolContext) => AgentTool | AgentTool[] | null | undefined;
|
|
123
124
|
interface OpenClawPluginApi {
|
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:
|
|
582
|
-
|
|
583
|
-
|
|
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}`,
|
|
@@ -655,18 +776,18 @@ function createBrandTools(config, logger) {
|
|
|
655
776
|
}
|
|
656
777
|
}
|
|
657
778
|
},
|
|
658
|
-
async execute(params) {
|
|
779
|
+
async execute(_toolCallId, params) {
|
|
659
780
|
const lobby = getLobbyClient();
|
|
660
|
-
if (!lobby) return { error: "Not connected to lobby" };
|
|
781
|
+
if (!lobby) return { content: [{ type: "text", text: JSON.stringify({ error: "Not connected to lobby" }) }], details: {} };
|
|
661
782
|
try {
|
|
662
783
|
const result = await lobby.request(
|
|
663
784
|
{ type: "browse_bouncers", limit: params.limit ?? 20 },
|
|
664
785
|
"browse_bouncers_result"
|
|
665
786
|
);
|
|
666
787
|
logger.info(`[bouncer] Browse returned ${result.bouncers?.length ?? 0} bouncers`);
|
|
667
|
-
return result.bouncers;
|
|
788
|
+
return { content: [{ type: "text", text: JSON.stringify(result.bouncers) }], details: {} };
|
|
668
789
|
} catch (err) {
|
|
669
|
-
return { error: `Browse failed: ${err.message}` };
|
|
790
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `Browse failed: ${err.message}` }) }], details: {} };
|
|
670
791
|
}
|
|
671
792
|
}
|
|
672
793
|
};
|
|
@@ -683,18 +804,18 @@ function createBrandTools(config, logger) {
|
|
|
683
804
|
},
|
|
684
805
|
required: ["bouncer_id"]
|
|
685
806
|
},
|
|
686
|
-
async execute(params) {
|
|
807
|
+
async execute(_toolCallId, params) {
|
|
687
808
|
const lobby = getLobbyClient();
|
|
688
|
-
if (!lobby) return { error: "Not connected to lobby" };
|
|
809
|
+
if (!lobby) return { content: [{ type: "text", text: JSON.stringify({ error: "Not connected to lobby" }) }], details: {} };
|
|
689
810
|
try {
|
|
690
811
|
const result = await lobby.request(
|
|
691
812
|
{ type: "get_profile", bouncer_id: params.bouncer_id },
|
|
692
813
|
"get_profile_result"
|
|
693
814
|
);
|
|
694
|
-
if (result.error) return { error: result.error };
|
|
695
|
-
return result.profile;
|
|
815
|
+
if (result.error) return { content: [{ type: "text", text: JSON.stringify({ error: result.error }) }], details: {} };
|
|
816
|
+
return { content: [{ type: "text", text: JSON.stringify(result.profile) }], details: {} };
|
|
696
817
|
} catch (err) {
|
|
697
|
-
return { error: `Profile fetch failed: ${err.message}` };
|
|
818
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `Profile fetch failed: ${err.message}` }) }], details: {} };
|
|
698
819
|
}
|
|
699
820
|
}
|
|
700
821
|
};
|
|
@@ -731,19 +852,21 @@ function createBrandTools(config, logger) {
|
|
|
731
852
|
},
|
|
732
853
|
required: ["bouncer_id", "product", "terms", "opening_message", "priority_bid"]
|
|
733
854
|
},
|
|
734
|
-
async execute(params) {
|
|
855
|
+
async execute(_toolCallId, params) {
|
|
735
856
|
const lobby = getLobbyClient();
|
|
857
|
+
const wrap = (obj) => ({ content: [{ type: "text", text: JSON.stringify(obj) }], details: {} });
|
|
736
858
|
if (!lobby) {
|
|
737
859
|
logger.error("[bouncer] bouncer_offer: getLobbyClient() returned null \u2014 lobby not initialized");
|
|
738
|
-
return { error: "Not connected to lobby" };
|
|
860
|
+
return wrap({ error: "Not connected to lobby" });
|
|
739
861
|
}
|
|
740
862
|
const connected = lobby.isConnected();
|
|
741
863
|
logger.info(`[bouncer] bouncer_offer: lobby.isConnected() = ${connected}`);
|
|
742
864
|
if (!connected) {
|
|
743
865
|
logger.error("[bouncer] bouncer_offer: lobby exists but isConnected() is false \u2014 WS may be reconnecting");
|
|
744
|
-
return { error: "Lobby WS not connected \u2014 may be reconnecting. Try again in a few seconds." };
|
|
866
|
+
return wrap({ error: "Lobby WS not connected \u2014 may be reconnecting. Try again in a few seconds." });
|
|
745
867
|
}
|
|
746
868
|
const bouncerId = params.bouncer_id;
|
|
869
|
+
logger.info(`[bouncer] bouncer_offer PARAMS: ${JSON.stringify(params)}`);
|
|
747
870
|
try {
|
|
748
871
|
logger.info(`[bouncer] Submitting offer to ${bouncerId}`);
|
|
749
872
|
const sendStart = Date.now();
|
|
@@ -761,7 +884,7 @@ function createBrandTools(config, logger) {
|
|
|
761
884
|
);
|
|
762
885
|
logger.info(`[bouncer] submit_offer response in ${Date.now() - sendStart}ms`);
|
|
763
886
|
if (offerResult.error) {
|
|
764
|
-
return { error: `Offer submission failed: ${offerResult.error}` };
|
|
887
|
+
return wrap({ error: `Offer submission failed: ${offerResult.error}` });
|
|
765
888
|
}
|
|
766
889
|
const offerId = offerResult.offer_id;
|
|
767
890
|
logger.info(`[bouncer] Offer submitted: ${offerId}`);
|
|
@@ -771,25 +894,25 @@ function createBrandTools(config, logger) {
|
|
|
771
894
|
"create_negotiation_result"
|
|
772
895
|
);
|
|
773
896
|
if (negResult.error) {
|
|
774
|
-
return { error: `Negotiation creation failed: ${negResult.error}`, offer_id: offerId };
|
|
897
|
+
return wrap({ error: `Negotiation creation failed: ${negResult.error}`, offer_id: offerId });
|
|
775
898
|
}
|
|
776
899
|
const negotiationId = negResult.negotiation_id;
|
|
777
900
|
logger.info(`[bouncer] Negotiation created: ${negotiationId}`);
|
|
778
901
|
logger.info(`[bouncer] Waiting for bouncer to accept (via WS)...`);
|
|
779
902
|
const accepted = await waitForAcceptanceWS(negotiationId, 12e4);
|
|
780
903
|
if (!accepted) {
|
|
781
|
-
return { status: "declined_or_timeout", offer_id: offerId, negotiation_id: negotiationId };
|
|
904
|
+
return wrap({ status: "declined_or_timeout", offer_id: offerId, negotiation_id: negotiationId });
|
|
782
905
|
}
|
|
783
906
|
logger.info(`[bouncer] Accepted! Connecting to negotiation room...`);
|
|
784
907
|
await connectToNegotiationRoom(negotiationId, config, wsUrl(config.apiUrl), logger);
|
|
785
|
-
return {
|
|
908
|
+
return wrap({
|
|
786
909
|
status: "connected",
|
|
787
910
|
offer_id: offerId,
|
|
788
911
|
negotiation_id: negotiationId,
|
|
789
912
|
message: "Connected to negotiation room. Incoming messages will appear as chat messages."
|
|
790
|
-
};
|
|
913
|
+
});
|
|
791
914
|
} catch (err) {
|
|
792
|
-
return { error: `Offer flow failed: ${err.message}` };
|
|
915
|
+
return wrap({ error: `Offer flow failed: ${err.message}` });
|
|
793
916
|
}
|
|
794
917
|
}
|
|
795
918
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sdk-types.ts","../src/connector-parser.ts","../src/bouncer-channel.ts","../src/connector-lobby.ts","../src/connector-session.ts","../src/service.ts","../src/types.ts","../src/tools.ts","../index.ts"],"sourcesContent":["/**\n * Minimal type stubs for the OpenClaw Plugin SDK.\n *\n * When installed into an OpenClaw environment, replace these with:\n * import { definePluginEntry } from \"openclaw/plugin-sdk/core\";\n *\n * These stubs match the contract from openclaw/openclaw src/plugin-sdk/core.ts\n * and src/plugins/types.ts as of 2026-03.\n */\n\nexport interface PluginLogger {\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n debug(msg: string, ...args: unknown[]): void;\n}\n\nexport interface ReplyPayload {\n text?: string;\n body?: string;\n mediaUrl?: string;\n mediaUrls?: string[];\n [key: string]: unknown;\n}\n\nexport interface MsgContext {\n Body?: string;\n BodyForAgent?: string;\n RawBody?: string;\n CommandBody?: string;\n From?: string;\n To?: string;\n SessionKey?: string;\n AccountId?: string;\n OriginatingChannel?: string;\n OriginatingTo?: string;\n ChatType?: string;\n SenderName?: string;\n SenderId?: string;\n Provider?: string;\n Surface?: string;\n ConversationLabel?: string;\n Timestamp?: number;\n CommandAuthorized?: boolean;\n [key: string]: unknown;\n}\n\nexport type FinalizedMsgContext = Omit<MsgContext, \"CommandAuthorized\"> & {\n CommandAuthorized: boolean;\n};\n\nexport interface ReplyDispatcherWithTypingOptions {\n deliver: (payload: ReplyPayload, info: { kind: string }) => Promise<void>;\n onReplyStart?: () => Promise<void> | void;\n onIdle?: () => void;\n onCleanup?: () => void;\n [key: string]: unknown;\n}\n\nexport interface DispatchInboundResult {\n [key: string]: unknown;\n}\n\nexport interface PluginRuntime {\n channel: {\n reply: {\n finalizeInboundContext: <T extends Record<string, unknown>>(ctx: T) => T & FinalizedMsgContext;\n dispatchReplyWithBufferedBlockDispatcher: (params: {\n ctx: MsgContext | FinalizedMsgContext;\n cfg: OpenClawConfig;\n dispatcherOptions: ReplyDispatcherWithTypingOptions;\n replyOptions?: Record<string, unknown>;\n }) => Promise<DispatchInboundResult>;\n dispatchReplyFromConfig?: (...args: unknown[]) => Promise<unknown>;\n };\n debounce: {\n createInboundDebouncer: (...args: unknown[]) => unknown;\n resolveInboundDebounceMs: (...args: unknown[]) => number;\n };\n session: {\n recordInboundSession: (...args: unknown[]) => unknown;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n };\n config: {\n loadConfig: () => Promise<OpenClawConfig>;\n writeConfigFile?: (...args: unknown[]) => Promise<void>;\n };\n logging: { shouldLogVerbose(): boolean; getChildLogger(name: string): PluginLogger };\n state: { resolveStateDir(): string };\n}\n\nexport interface OpenClawConfig {\n channels?: Record<string, Record<string, unknown>>;\n plugins?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface OpenClawPluginServiceContext {\n config: OpenClawConfig;\n workspaceDir?: string;\n stateDir: string;\n logger: PluginLogger;\n}\n\nexport interface OpenClawPluginService {\n id: string;\n start: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;\n stop?: (ctx: OpenClawPluginServiceContext) => void | Promise<void>;\n}\n\nexport interface OpenClawPluginToolContext {\n config?: OpenClawConfig;\n agentId?: string;\n sessionKey?: string;\n messageChannel?: string;\n [key: string]: unknown;\n}\n\nexport interface AgentTool {\n name: string;\n description: string;\n parameters?: Record<string, unknown>;\n execute: (params: Record<string, unknown>, ctx?: unknown) => Promise<unknown>;\n}\n\nexport type OpenClawPluginToolFactory = (ctx: OpenClawPluginToolContext) => AgentTool | AgentTool[] | null | undefined;\n\nexport interface OpenClawPluginApi {\n id: string;\n name: string;\n version?: string;\n description?: string;\n source: string;\n rootDir?: string;\n registrationMode: \"full\" | \"setup-only\" | \"setup-runtime\";\n config: OpenClawConfig;\n pluginConfig?: Record<string, unknown>;\n runtime: PluginRuntime;\n logger: PluginLogger;\n\n registerTool: (tool: AgentTool | OpenClawPluginToolFactory, opts?: { name?: string; names?: string[]; optional?: boolean }) => void;\n registerHook: (events: string | string[], handler: (...args: unknown[]) => void | Promise<void>, opts?: Record<string, unknown>) => void;\n registerHttpRoute: (params: Record<string, unknown>) => void;\n registerChannel: (registration: { plugin: ChannelPlugin } | ChannelPlugin) => void;\n registerGatewayMethod: (method: string, handler: (...args: unknown[]) => unknown) => void;\n registerService: (service: OpenClawPluginService) => void;\n registerCommand: (command: { name: string; description: string; handler: (...args: unknown[]) => void | Promise<void> }) => void;\n resolvePath: (input: string) => string;\n on: (hookName: string, handler: (...args: unknown[]) => void | Promise<void>, opts?: { priority?: number }) => void;\n}\n\nexport interface ChannelMeta {\n id: string;\n label: string;\n selectionLabel: string;\n docsPath?: string;\n blurb?: string;\n aliases?: string[];\n order?: number;\n}\n\nexport interface ChannelCapabilities {\n chatTypes: Array<\"direct\" | \"group\">;\n}\n\nexport interface ChannelConfigAdapter {\n listAccountIds: (cfg: OpenClawConfig) => string[];\n resolveAccount: (cfg: OpenClawConfig, accountId?: string) => Record<string, unknown>;\n}\n\nexport interface ChannelOutboundAdapter {\n deliveryMode: \"direct\" | \"queued\";\n sendText: (ctx: SendTextContext) => Promise<{ ok: boolean; error?: string }>;\n}\n\nexport interface SendTextContext {\n text: string;\n conversationId?: string;\n accountId?: string;\n replyTo?: string;\n [key: string]: unknown;\n}\n\nexport interface ChannelLifecycleAdapter {\n startAccount?: (accountId: string, config: Record<string, unknown>, logger: PluginLogger) => Promise<void>;\n stopAccount?: (accountId: string) => Promise<void>;\n}\n\nexport interface ChannelPlugin {\n id: string;\n meta: ChannelMeta;\n capabilities: ChannelCapabilities;\n config: ChannelConfigAdapter;\n outbound?: ChannelOutboundAdapter;\n lifecycle?: ChannelLifecycleAdapter;\n [key: string]: unknown;\n}\n\nexport interface DefinedPluginEntry {\n id: string;\n name: string;\n description: string;\n register: (api: OpenClawPluginApi) => void;\n}\n\nexport function definePluginEntry(opts: {\n id: string;\n name: string;\n description: string;\n register: (api: OpenClawPluginApi) => void;\n}): DefinedPluginEntry {\n return {\n id: opts.id,\n name: opts.name,\n description: opts.description,\n register: opts.register,\n };\n}\n\nexport function defineChannelPluginEntry<TPlugin extends ChannelPlugin>(opts: {\n id: string;\n name: string;\n description: string;\n plugin: TPlugin;\n setRuntime?: (runtime: PluginRuntime) => void;\n registerFull?: (api: OpenClawPluginApi) => void;\n}): DefinedPluginEntry {\n return definePluginEntry({\n id: opts.id,\n name: opts.name,\n description: opts.description,\n register(api) {\n api.registerChannel({ plugin: opts.plugin });\n if (opts.setRuntime) opts.setRuntime(api.runtime);\n if (api.registrationMode === \"full\" && opts.registerFull) {\n opts.registerFull(api);\n }\n },\n });\n}\n","export interface BounceMessage {\n type: \"message\" | \"accept\" | \"walk\" | \"propose_terms\" | \"counter_terms\" | \"research\";\n content: string;\n terms?: Record<string, any>;\n}\n\nconst SIMPLE_PREFIXES: Record<string, BounceMessage[\"type\"]> = {\n \"[ACCEPT]\": \"accept\",\n \"[WALK]\": \"walk\",\n \"[RESEARCH]\": \"research\",\n};\n\nconst TERMS_PREFIXES: Record<string, BounceMessage[\"type\"]> = {\n \"[TERMS]\": \"propose_terms\",\n \"[COUNTER]\": \"counter_terms\",\n};\n\nexport function parseResponse(text: string): BounceMessage {\n const trimmed = text.trim();\n\n for (const [prefix, type] of Object.entries(SIMPLE_PREFIXES)) {\n if (trimmed.startsWith(prefix)) {\n return { type, content: trimmed.slice(prefix.length).trim() };\n }\n }\n\n for (const [prefix, type] of Object.entries(TERMS_PREFIXES)) {\n if (trimmed.startsWith(prefix)) {\n const rest = trimmed.slice(prefix.length);\n const jsonEnd = rest.indexOf(\"}\");\n if (jsonEnd !== -1) {\n const jsonStr = rest.slice(0, jsonEnd + 1);\n try {\n const terms = JSON.parse(jsonStr);\n const content = rest.slice(jsonEnd + 1).trim();\n return { type, content, terms };\n } catch {\n return { type: \"message\", content: trimmed };\n }\n }\n return { type: \"message\", content: trimmed };\n }\n }\n\n return { type: \"message\", content: trimmed };\n}\n","import { parseResponse } from \"./connector-parser.js\";\nimport { NegotiationSession } from \"./connector-session.js\";\nimport type {\n ChannelPlugin,\n OpenClawConfig,\n PluginLogger,\n SendTextContext,\n} from \"./sdk-types.js\";\n\nconst activeSessions = new Map<string, NegotiationSession>();\n\nexport function getActiveSession(negotiationId: string): NegotiationSession | undefined {\n return activeSessions.get(negotiationId);\n}\n\nexport function setActiveSession(negotiationId: string, session: NegotiationSession): void {\n activeSessions.set(negotiationId, session);\n}\n\nexport function removeActiveSession(negotiationId: string): void {\n const session = activeSessions.get(negotiationId);\n if (session) {\n session.close();\n activeSessions.delete(negotiationId);\n }\n}\n\nexport function getActiveNegotiationId(): string | undefined {\n const entries = [...activeSessions.entries()];\n return entries.length > 0 ? entries[0]![0] : undefined;\n}\n\nexport function createBouncerChannel(logger: PluginLogger): ChannelPlugin {\n return {\n id: \"bouncer\",\n\n meta: {\n id: \"bouncer\",\n label: \"Bouncer Protocol\",\n selectionLabel: \"Bouncer Protocol (Agent Negotiation)\",\n docsPath: \"/channels/bouncer\",\n blurb: \"Real-time agent-to-agent negotiation via the Bouncer Protocol\",\n aliases: [\"bouncer-protocol\"],\n order: 90,\n },\n\n capabilities: {\n chatTypes: [\"direct\"],\n },\n\n config: {\n listAccountIds(cfg: OpenClawConfig): string[] {\n const bouncer = cfg.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncer?.agentId) return [];\n return [bouncer.agentId as string];\n },\n\n resolveAccount(cfg: OpenClawConfig, accountId?: string): Record<string, unknown> {\n const bouncer = cfg.channels?.bouncer as Record<string, unknown> | undefined;\n return bouncer ?? { accountId };\n },\n },\n\n outbound: {\n deliveryMode: \"direct\",\n\n async sendText(ctx: SendTextContext): Promise<{ ok: boolean; error?: string }> {\n const negId = ctx.conversationId ?? getActiveNegotiationId();\n if (!negId) {\n return { ok: false, error: \"No active negotiation session\" };\n }\n\n const session = activeSessions.get(negId);\n if (!session) {\n return { ok: false, error: `No session for negotiation ${negId}` };\n }\n\n const parsed = parseResponse(ctx.text);\n\n session.sendThinking();\n\n await new Promise((r) => setTimeout(r, 200));\n\n session.send(parsed);\n logger.info(`[bouncer] Sent ${parsed.type}: ${parsed.content.slice(0, 80)}...`);\n\n return { ok: true };\n },\n },\n };\n}\n","import { EventEmitter } from \"events\";\nimport WebSocket from \"ws\";\n\nlet requestCounter = 0;\n\nexport interface LobbyClientOpts {\n apiUrl: string;\n token: string;\n agentId: string;\n reconnectBaseMs?: number;\n reconnectMaxMs?: number;\n}\n\nexport class LobbyClient extends EventEmitter {\n private ws: WebSocket | null = null;\n private opts: Required<LobbyClientOpts>;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n private lastHeartbeatAt = 0;\n private watchdogTimer: ReturnType<typeof setInterval> | null = null;\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n\n private static readonly HEARTBEAT_STALE_MS = 45_000;\n private static readonly WATCHDOG_INTERVAL_MS = 15_000;\n private static readonly CLIENT_PING_INTERVAL_MS = 25_000;\n\n constructor(opts: LobbyClientOpts) {\n super();\n this.opts = {\n reconnectBaseMs: 1000,\n reconnectMaxMs: 30_000,\n ...opts,\n };\n }\n\n connect(): Promise<void> {\n this.closed = false;\n return this._connect();\n }\n\n private _connect(): Promise<void> {\n this.stopTimers();\n return new Promise((resolve, reject) => {\n const url = `${this.opts.apiUrl}/v1/agents/${this.opts.agentId}/ws?token=${this.opts.token}`;\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.on(\"open\", () => {\n this.reconnectAttempt = 0;\n this.lastHeartbeatAt = Date.now();\n this.startWatchdog();\n this.startClientPing();\n });\n\n ws.on(\"message\", (raw) => {\n try {\n const data = JSON.parse(raw.toString());\n if (data.type === \"connected\") {\n this.lastHeartbeatAt = Date.now();\n this.emit(\"connected\", data);\n resolve();\n } else if (data.type === \"heartbeat\") {\n this.lastHeartbeatAt = Date.now();\n this.emit(\"heartbeat\", data);\n } else if (data.type === \"error\") {\n this.emit(\"error\", new Error(data.error));\n }\n this.emit(data.type, data);\n } catch {}\n });\n\n ws.on(\"close\", () => {\n this.stopTimers();\n if (!this.closed) {\n this.scheduleReconnect();\n }\n });\n\n ws.on(\"error\", (err) => {\n if (this.reconnectAttempt === 0 && ws.readyState === WebSocket.CONNECTING) {\n reject(err);\n }\n });\n });\n }\n\n private startWatchdog() {\n this.watchdogTimer = setInterval(() => {\n if (this.closed) return;\n const staleMs = Date.now() - this.lastHeartbeatAt;\n if (staleMs > LobbyClient.HEARTBEAT_STALE_MS) {\n this.emit(\"stale\", { staleMs });\n this.forceReconnect();\n }\n }, LobbyClient.WATCHDOG_INTERVAL_MS);\n }\n\n private startClientPing() {\n this.pingTimer = setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.ping();\n } catch {}\n }\n }, LobbyClient.CLIENT_PING_INTERVAL_MS);\n }\n\n private stopTimers() {\n if (this.watchdogTimer) { clearInterval(this.watchdogTimer); this.watchdogTimer = null; }\n if (this.pingTimer) { clearInterval(this.pingTimer); this.pingTimer = null; }\n }\n\n private forceReconnect() {\n this.stopTimers();\n if (this.ws) {\n try { this.ws.terminate(); } catch {}\n this.ws = null;\n }\n if (!this.closed) {\n this.scheduleReconnect();\n }\n }\n\n private scheduleReconnect() {\n if (this.closed) return;\n const delay = Math.min(\n this.opts.reconnectBaseMs * Math.pow(2, this.reconnectAttempt),\n this.opts.reconnectMaxMs\n );\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n if (!this.closed) {\n this._connect().catch(() => {});\n }\n }, delay);\n }\n\n accept(negotiationId: string): void {\n this.send({ type: \"accept_negotiation\", negotiation_id: negotiationId });\n }\n\n decline(negotiationId: string, reason?: string): void {\n this.send({ type: \"decline_negotiation\", negotiation_id: negotiationId, reason });\n }\n\n isConnected(): boolean {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;\n if (this.lastHeartbeatAt > 0) {\n const staleMs = Date.now() - this.lastHeartbeatAt;\n if (staleMs > LobbyClient.HEARTBEAT_STALE_MS) return false;\n }\n return true;\n }\n\n send(data: any): boolean {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(data));\n return true;\n }\n return false;\n }\n\n request(msg: Record<string, unknown>, responseType: string, timeoutMs = 30_000): Promise<any> {\n return new Promise((resolve, reject) => {\n if (!this.isConnected()) {\n const staleMs = this.lastHeartbeatAt > 0 ? Date.now() - this.lastHeartbeatAt : -1;\n reject(new Error(`Lobby WS not connected (readyState: ${this.ws?.readyState ?? \"null\"}, lastHeartbeat: ${staleMs}ms ago) — cannot send ${msg.type}`));\n return;\n }\n\n const requestId = `req_${++requestCounter}_${Date.now()}`;\n console.log(`[lobby-request] Sending ${msg.type} with request_id=${requestId}, waiting for ${responseType}`);\n\n const timer = setTimeout(() => {\n const staleMs = this.lastHeartbeatAt > 0 ? Date.now() - this.lastHeartbeatAt : -1;\n console.log(`[lobby-request] TIMEOUT for ${requestId}: readyState=${this.ws?.readyState}, lastHeartbeat=${staleMs}ms ago, listenerCount(${responseType})=${this.listenerCount(responseType)}`);\n cleanup();\n reject(new Error(`WS request timed out waiting for ${responseType} (sent ${msg.type}, waited ${timeoutMs}ms, lastHeartbeat: ${staleMs}ms ago)`));\n }, timeoutMs);\n\n const handler = (data: any) => {\n console.log(`[lobby-request] Got ${responseType} event: request_id=${data.request_id} (waiting for ${requestId})`);\n if (data.request_id === requestId) {\n cleanup();\n if (data.error) {\n reject(new Error(data.error));\n } else {\n resolve(data);\n }\n }\n };\n\n const cleanup = () => {\n clearTimeout(timer);\n this.removeListener(responseType, handler);\n };\n\n this.on(responseType, handler);\n const sent = this.send({ ...msg, request_id: requestId });\n if (!sent) {\n cleanup();\n reject(new Error(`Failed to send ${msg.type} — WS connection dropped between check and send`));\n } else {\n console.log(`[lobby-request] Message sent successfully, readyState=${this.ws?.readyState}`);\n }\n });\n }\n\n close(): void {\n this.closed = true;\n this.stopTimers();\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n if (this.ws) {\n try { this.ws.close(); } catch {}\n this.ws = null;\n }\n }\n}\n","import { EventEmitter } from \"events\";\nimport WebSocket from \"ws\";\n\nexport interface NegotiationSessionOpts {\n apiUrl: string;\n token: string;\n negotiationId: string;\n agentId: string;\n}\n\nexport class NegotiationSession extends EventEmitter {\n private ws: WebSocket | null = null;\n private opts: NegotiationSessionOpts;\n private seenMessageIds = new Set<string>();\n private myAgentId: string;\n\n constructor(opts: NegotiationSessionOpts) {\n super();\n this.opts = opts;\n this.myAgentId = opts.agentId;\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.opts.apiUrl}/v1/negotiations/${this.opts.negotiationId}/ws?token=${this.opts.token}`;\n const ws = new WebSocket(url);\n this.ws = ws;\n\n ws.on(\"message\", (raw) => {\n try {\n const data = JSON.parse(raw.toString());\n\n if (data.type === \"connected\") {\n if (data.agent_id) this.myAgentId = data.agent_id;\n this.emit(\"connected\", data);\n resolve();\n } else if (data.type === \"negotiation_message\") {\n const msg = data.message ?? {\n id: data.id,\n from_agent_id: data.from_agent_id,\n type: data.message_type ?? data.type,\n content: data.content,\n terms: data.terms,\n is_catchup: data.is_catchup,\n created_at: data.created_at,\n };\n\n const msgId = msg.id;\n if (msgId && this.seenMessageIds.has(msgId)) return;\n if (msgId) this.seenMessageIds.add(msgId);\n\n if (msg.from_agent_id === this.myAgentId) return;\n\n this.emit(\"incoming_message\", msg);\n } else if (data.type === \"negotiation_started\") {\n this.emit(\"negotiation_started\", data);\n } else if (data.type === \"negotiation_ended\") {\n this.emit(\"ended\", data);\n this.close();\n } else if (data.type === \"message_ack\") {\n if (data.message?.id) this.seenMessageIds.add(data.message.id);\n this.emit(\"message_ack\", data);\n } else if (data.type === \"agent_thinking\") {\n this.emit(\"agent_thinking\", data);\n } else if (data.type === \"error\") {\n this.emit(\"error\", new Error(data.error));\n }\n } catch {}\n });\n\n ws.on(\"error\", (err) => {\n if (ws.readyState === WebSocket.CONNECTING) {\n reject(err);\n }\n });\n\n ws.on(\"close\", () => {\n this.emit(\"disconnected\");\n });\n });\n }\n\n send(msg: { type: string; content?: string; terms?: object }): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(msg));\n }\n }\n\n sendThinking(): void {\n this.send({ type: \"thinking\" });\n }\n\n close(): void {\n if (this.ws) {\n try { this.ws.close(); } catch {}\n this.ws = null;\n }\n }\n}\n","import { LobbyClient } from \"./connector-lobby.js\";\nimport { NegotiationSession } from \"./connector-session.js\";\nimport { parseResponse } from \"./connector-parser.js\";\nimport {\n setActiveSession,\n removeActiveSession,\n} from \"./bouncer-channel.js\";\nimport type { BouncerPluginConfig, NegotiationState } from \"./types.js\";\nimport type {\n OpenClawPluginService,\n OpenClawPluginServiceContext,\n PluginLogger,\n PluginRuntime,\n} from \"./sdk-types.js\";\n\nlet lobbyClient: LobbyClient | null = null;\n\nexport function getLobbyClient(): LobbyClient | null {\n return lobbyClient;\n}\nlet activeNegotiation: NegotiationState | null = null;\nlet pluginRuntime: PluginRuntime | null = null;\n\nfunction resolveAgentFromBindings(cfg: any, channel: string): string | null {\n const bindings = cfg?.bindings;\n if (!Array.isArray(bindings)) return null;\n for (const b of bindings) {\n if (b?.match?.channel === channel && b?.agentId) {\n return b.agentId;\n }\n }\n return null;\n}\n\nlet serviceStarted = false;\n\nexport function setRuntime(rt: PluginRuntime): void {\n pluginRuntime = rt;\n}\n\nexport async function ensureServiceStarted(log: PluginLogger): Promise<void> {\n if (serviceStarted || lobbyClient) return;\n if (!pluginRuntime) return;\n\n try {\n const cfg = await pluginRuntime.config.loadConfig();\n const bouncerCfg = cfg?.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncerCfg?.role) return;\n\n const config: BouncerPluginConfig = {\n role: bouncerCfg.role as \"bouncer\" | \"brand\",\n apiUrl: bouncerCfg.apiUrl as string,\n apiKey: bouncerCfg.apiKey as string,\n agentId: bouncerCfg.agentId as string,\n autoAccept: (bouncerCfg.autoAccept as boolean) ?? true,\n llmTimeoutMs: (bouncerCfg.llmTimeoutMs as number) ?? 25_000,\n };\n\n serviceStarted = true;\n log.info(`[bouncer] Self-starting service — role: ${config.role}, agent: ${config.agentId}`);\n\n await startLobby(config, log);\n } catch (err: any) {\n log.error(`[bouncer] Self-start failed: ${err.message}`);\n serviceStarted = false;\n }\n}\n\nexport function getActiveNegotiation(): NegotiationState | null {\n return activeNegotiation;\n}\n\nexport function createBouncerService(config: BouncerPluginConfig): OpenClawPluginService {\n return {\n id: \"bouncer-negotiation-service\",\n\n async start(ctx: OpenClawPluginServiceContext) {\n const log = ctx.logger;\n\n await startLobby(config, log);\n },\n\n async stop() {\n if (lobbyClient) {\n lobbyClient.close();\n lobbyClient = null;\n }\n if (activeNegotiation) {\n removeActiveSession(activeNegotiation.negotiationId);\n activeNegotiation = null;\n }\n },\n };\n}\n\nasync function startLobby(config: BouncerPluginConfig, log: PluginLogger): Promise<void> {\n const wsBase = config.apiUrl.replace(/^http/, \"ws\");\n\n lobbyClient = new LobbyClient({\n apiUrl: wsBase,\n token: config.apiKey,\n agentId: config.agentId,\n reconnectBaseMs: 1_000,\n reconnectMaxMs: 30_000,\n });\n\n lobbyClient.on(\"connected\", () => {\n log.info(`[bouncer] Lobby connected (${config.role} mode).`);\n });\n\n if (config.role === \"bouncer\") {\n lobbyClient.on(\"negotiation_requested\", (data: any) => {\n handleNegotiationRequested(data, config, wsBase, log);\n });\n }\n\n lobbyClient.on(\"heartbeat\", () => {\n log.debug(\"[bouncer] Lobby heartbeat\");\n });\n\n lobbyClient.on(\"stale\", (data: any) => {\n log.warn(`[bouncer] Lobby connection stale (${data.staleMs}ms since last heartbeat) — forcing reconnect`);\n });\n\n try {\n await lobbyClient.connect();\n } catch (err: any) {\n log.error(`[bouncer] Lobby connection failed: ${err.message}`);\n throw err;\n }\n}\n\nasync function handleNegotiationRequested(\n data: any,\n config: BouncerPluginConfig,\n wsBase: string,\n log: PluginLogger,\n): Promise<void> {\n const negId = data.negotiation_id;\n\n if (activeNegotiation) {\n log.info(`[bouncer] Declining ${negId} — already in negotiation ${activeNegotiation.negotiationId}`);\n lobbyClient?.decline(negId, \"busy — already in a negotiation\");\n return;\n }\n\n if (!config.autoAccept) {\n log.info(`[bouncer] Negotiation ${negId} requested but autoAccept is off. Declining.`);\n lobbyClient?.decline(negId, \"auto-accept disabled\");\n return;\n }\n\n log.info(`[bouncer] Accepting negotiation ${negId}`);\n lobbyClient?.accept(negId);\n\n activeNegotiation = {\n negotiationId: negId,\n status: \"pending\",\n otherAgentId: data.brand?.id,\n offerContext: data.offer\n ? { product: data.offer.product, terms: data.offer.terms, opening_message: data.offer.opening_message }\n : undefined,\n };\n\n await connectToNegotiationRoom(negId, config, wsBase, log);\n}\n\nexport async function connectToNegotiationRoom(\n negotiationId: string,\n config: BouncerPluginConfig,\n wsBase: string,\n log: PluginLogger,\n): Promise<void> {\n const session = new NegotiationSession({\n apiUrl: wsBase,\n token: config.apiKey,\n negotiationId,\n agentId: config.agentId,\n });\n\n session.on(\"connected\", () => {\n log.info(`[bouncer] Connected to negotiation room ${negotiationId}`);\n });\n\n session.on(\"negotiation_started\", (data: any) => {\n log.info(`[bouncer] Negotiation ${negotiationId} started`);\n if (activeNegotiation) {\n activeNegotiation.status = \"live\";\n if (data.queue_context) {\n (activeNegotiation as any).queueContext = data.queue_context;\n }\n if (data.relationship) {\n (activeNegotiation as any).relationship = data.relationship;\n }\n }\n });\n\n let dispatching = false;\n session.on(\"incoming_message\", (msg: any) => {\n if (dispatching) {\n log.debug(`[bouncer] Skipping message while dispatch in progress`);\n return;\n }\n log.info(`[bouncer] Message from ${msg.from_agent_id}: ${(msg.content ?? \"\").slice(0, 80)}...`);\n dispatching = true;\n dispatchToAgent(negotiationId, msg, config, session, log).finally(() => {\n dispatching = false;\n });\n });\n\n session.on(\"agent_thinking\", () => {\n log.debug(`[bouncer] Other agent thinking in ${negotiationId}`);\n });\n\n session.on(\"ended\", (data: any) => {\n log.info(`[bouncer] Negotiation ${negotiationId} ended: ${data?.status ?? \"unknown\"}`);\n removeActiveSession(negotiationId);\n activeNegotiation = null;\n });\n\n session.on(\"disconnected\", () => {\n log.warn(`[bouncer] Disconnected from negotiation ${negotiationId}`);\n });\n\n setActiveSession(negotiationId, session);\n\n try {\n await session.connect();\n } catch (err: any) {\n log.error(`[bouncer] Failed to connect to negotiation ${negotiationId}: ${err.message}`);\n removeActiveSession(negotiationId);\n activeNegotiation = null;\n }\n}\n\nasync function dispatchToAgent(\n negotiationId: string,\n msg: any,\n config: BouncerPluginConfig,\n session: NegotiationSession,\n log: PluginLogger,\n): Promise<void> {\n if (!pluginRuntime) {\n log.error(\"[bouncer] Runtime not set — cannot dispatch inbound message to agent\");\n return;\n }\n\n const rt = pluginRuntime;\n\n try {\n const currentCfg = await rt.config.loadConfig();\n\n const resolvedAgent = resolveAgentFromBindings(currentCfg, \"bouncer\");\n if (resolvedAgent) {\n log.info(`[bouncer] Routing negotiation ${negotiationId} to agent: ${resolvedAgent}`);\n }\n\n const msgCtx = rt.channel.reply.finalizeInboundContext({\n Body: msg.content ?? \"\",\n RawBody: msg.content ?? \"\",\n CommandBody: msg.content ?? \"\",\n From: `bouncer:${msg.from_agent_id}`,\n To: `bouncer:${config.agentId}`,\n SessionKey: `bouncer:${negotiationId}`,\n AccountId: config.agentId,\n OriginatingChannel: \"bouncer\",\n OriginatingTo: `bouncer:${msg.from_agent_id}`,\n ChatType: \"direct\",\n SenderName: msg.from_agent_id,\n SenderId: msg.from_agent_id,\n Provider: \"bouncer\",\n Surface: \"bouncer\",\n ConversationLabel: `Negotiation ${negotiationId}`,\n Timestamp: Date.now(),\n CommandAuthorized: true,\n ...(resolvedAgent ? { AgentId: resolvedAgent, TargetAgentId: resolvedAgent, ResolvedAgentId: resolvedAgent } : {}),\n });\n\n await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: msgCtx,\n cfg: currentCfg,\n dispatcherOptions: {\n deliver: async (payload) => {\n const text = payload?.text ?? payload?.body;\n if (!text) return;\n\n const parsed = parseResponse(text);\n session.sendThinking();\n await new Promise((r) => setTimeout(r, 200));\n session.send(parsed);\n log.info(`[bouncer] Agent replied (${parsed.type}): ${parsed.content.slice(0, 80)}...`);\n },\n onReplyStart: () => {\n session.sendThinking();\n },\n },\n });\n } catch (err: any) {\n log.error(`[bouncer] Dispatch failed for negotiation ${negotiationId}: ${err.message}`);\n }\n}\n","export interface BouncerPluginConfig {\n role: \"bouncer\" | \"brand\";\n apiUrl: string;\n apiKey: string;\n agentId: string;\n autoAccept?: boolean;\n llmTimeoutMs?: number;\n}\n\nexport interface NegotiationState {\n negotiationId: string;\n status: \"pending\" | \"live\" | \"ended\";\n otherAgentId?: string;\n offerContext?: {\n product: string;\n terms: string;\n opening_message: string;\n };\n}\n\nexport interface InboundNegotiationMessage {\n negotiationId: string;\n fromAgentId: string;\n type: string;\n content: string;\n terms?: Record<string, unknown>;\n timestamp: string;\n}\n\nexport function resolveConfig(pluginConfig: Record<string, unknown> | undefined): BouncerPluginConfig {\n if (!pluginConfig) throw new Error(\"Bouncer plugin config is required\");\n\n const role = pluginConfig.role as string;\n if (role !== \"bouncer\" && role !== \"brand\") {\n throw new Error(`Invalid role \"${role}\" — must be \"bouncer\" or \"brand\"`);\n }\n\n return {\n role,\n apiUrl: pluginConfig.apiUrl as string,\n apiKey: pluginConfig.apiKey as string,\n agentId: pluginConfig.agentId as string,\n autoAccept: (pluginConfig.autoAccept as boolean) ?? true,\n llmTimeoutMs: (pluginConfig.llmTimeoutMs as number) ?? 25_000,\n };\n}\n\nexport function wsUrl(apiUrl: string): string {\n return apiUrl.replace(/^http/, \"ws\");\n}\n","import type { AgentTool, PluginLogger } from \"./sdk-types.js\";\nimport type { BouncerPluginConfig } from \"./types.js\";\nimport { connectToNegotiationRoom, getLobbyClient } from \"./service.js\";\nimport { wsUrl } from \"./types.js\";\n\nexport function createBrandTools(config: BouncerPluginConfig, logger: PluginLogger): AgentTool[] {\n if (config.role !== \"brand\") return [];\n\n const bouncerBrowse: AgentTool = {\n name: \"bouncer_browse\",\n description:\n \"Browse available Bouncer agents in the directory. Returns a list of bouncers \" +\n \"with their name, listing, tags, and reputation score. Use this to find a \" +\n \"bouncer to target with an offer.\",\n parameters: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n description: \"Max results to return (default: 20)\",\n },\n },\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { error: \"Not connected to lobby\" };\n\n try {\n const result = await lobby.request(\n { type: \"browse_bouncers\", limit: params.limit ?? 20 },\n \"browse_bouncers_result\",\n );\n logger.info(`[bouncer] Browse returned ${result.bouncers?.length ?? 0} bouncers`);\n return result.bouncers;\n } catch (err: any) {\n return { error: `Browse failed: ${err.message}` };\n }\n },\n };\n\n const bouncerProfile: AgentTool = {\n name: \"bouncer_profile\",\n description:\n \"Get the full profile of a specific Bouncer agent, including their listing, \" +\n \"enrichment data, engagement rules, and verified credentials. Use this before \" +\n \"crafting a personalized offer.\",\n parameters: {\n type: \"object\",\n properties: {\n bouncer_id: {\n type: \"string\",\n description: \"The Bouncer agent's UUID\",\n },\n },\n required: [\"bouncer_id\"],\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) return { error: \"Not connected to lobby\" };\n\n try {\n const result = await lobby.request(\n { type: \"get_profile\", bouncer_id: params.bouncer_id },\n \"get_profile_result\",\n );\n if (result.error) return { error: result.error };\n return result.profile;\n } catch (err: any) {\n return { error: `Profile fetch failed: ${err.message}` };\n }\n },\n };\n\n const bouncerOffer: AgentTool = {\n name: \"bouncer_offer\",\n description:\n \"Submit an offer to a Bouncer agent and create a negotiation. This sends your \" +\n \"offer and automatically connects you to the negotiation room when the bouncer \" +\n \"accepts. Returns the offer_id and negotiation_id.\",\n parameters: {\n type: \"object\",\n properties: {\n bouncer_id: {\n type: \"string\",\n description: \"The target Bouncer's UUID\",\n },\n product: {\n type: \"string\",\n description: \"Product or service being offered\",\n },\n terms: {\n type: \"string\",\n description: \"Deal terms (e.g. '$20 credit + free delivery')\",\n },\n opening_message: {\n type: \"string\",\n description: \"Personalized opening message to the Bouncer\",\n },\n priority_bid: {\n type: \"number\",\n description: \"Priority bid in USDC (e.g. 2.0)\",\n },\n arena: {\n type: \"boolean\",\n description: \"Practice mode — no real USDC (default: false)\",\n },\n },\n required: [\"bouncer_id\", \"product\", \"terms\", \"opening_message\", \"priority_bid\"],\n },\n\n async execute(params: Record<string, unknown>): Promise<unknown> {\n const lobby = getLobbyClient();\n if (!lobby) {\n logger.error(\"[bouncer] bouncer_offer: getLobbyClient() returned null — lobby not initialized\");\n return { error: \"Not connected to lobby\" };\n }\n\n const connected = lobby.isConnected();\n logger.info(`[bouncer] bouncer_offer: lobby.isConnected() = ${connected}`);\n if (!connected) {\n logger.error(\"[bouncer] bouncer_offer: lobby exists but isConnected() is false — WS may be reconnecting\");\n return { error: \"Lobby WS not connected — may be reconnecting. Try again in a few seconds.\" };\n }\n\n const bouncerId = params.bouncer_id as string;\n\n try {\n logger.info(`[bouncer] Submitting offer to ${bouncerId}`);\n const sendStart = Date.now();\n\n const offerResult = await lobby.request(\n {\n type: \"submit_offer\",\n bouncer_id: bouncerId,\n product: params.product,\n terms: params.terms,\n opening_message: params.opening_message,\n priority_bid: params.priority_bid,\n arena: params.arena ?? false,\n },\n \"submit_offer_result\",\n );\n\n logger.info(`[bouncer] submit_offer response in ${Date.now() - sendStart}ms`);\n\n if (offerResult.error) {\n return { error: `Offer submission failed: ${offerResult.error}` };\n }\n\n const offerId = offerResult.offer_id;\n logger.info(`[bouncer] Offer submitted: ${offerId}`);\n\n logger.info(`[bouncer] Creating negotiation for offer ${offerId}`);\n const negResult = await lobby.request(\n { type: \"create_negotiation\", offer_id: offerId, bouncer_id: bouncerId },\n \"create_negotiation_result\",\n );\n\n if (negResult.error) {\n return { error: `Negotiation creation failed: ${negResult.error}`, offer_id: offerId };\n }\n\n const negotiationId = negResult.negotiation_id;\n logger.info(`[bouncer] Negotiation created: ${negotiationId}`);\n\n logger.info(`[bouncer] Waiting for bouncer to accept (via WS)...`);\n const accepted = await waitForAcceptanceWS(negotiationId, 120_000);\n\n if (!accepted) {\n return { status: \"declined_or_timeout\", offer_id: offerId, negotiation_id: negotiationId };\n }\n\n logger.info(`[bouncer] Accepted! Connecting to negotiation room...`);\n await connectToNegotiationRoom(negotiationId, config, wsUrl(config.apiUrl), logger);\n\n return {\n status: \"connected\",\n offer_id: offerId,\n negotiation_id: negotiationId,\n message: \"Connected to negotiation room. Incoming messages will appear as chat messages.\",\n };\n } catch (err: any) {\n return { error: `Offer flow failed: ${err.message}` };\n }\n },\n };\n\n return [bouncerBrowse, bouncerProfile, bouncerOffer];\n}\n\nfunction waitForAcceptanceWS(negotiationId: string, timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n const lobby = getLobbyClient();\n if (!lobby) {\n resolve(false);\n return;\n }\n\n const timer = setTimeout(() => {\n cleanup();\n resolve(false);\n }, timeoutMs);\n\n const onAccepted = (data: any) => {\n if (data.negotiation_id === negotiationId) {\n cleanup();\n resolve(true);\n }\n };\n\n const onDeclined = (data: any) => {\n if (data.negotiation_id === negotiationId) {\n cleanup();\n resolve(false);\n }\n };\n\n const cleanup = () => {\n clearTimeout(timer);\n lobby.removeListener(\"negotiation_accepted\", onAccepted);\n lobby.removeListener(\"negotiation_declined\", onDeclined);\n };\n\n lobby.on(\"negotiation_accepted\", onAccepted);\n lobby.on(\"negotiation_declined\", onDeclined);\n });\n}\n","import { definePluginEntry } from \"./src/sdk-types.js\";\nimport { createBouncerChannel } from \"./src/bouncer-channel.js\";\nimport { createBouncerService, setRuntime, ensureServiceStarted } from \"./src/service.js\";\nimport { createBrandTools } from \"./src/tools.js\";\nimport { resolveConfig } from \"./src/types.js\";\nimport type { OpenClawPluginApi, PluginLogger } from \"./src/sdk-types.js\";\n\nlet pluginLogger: PluginLogger = {\n info: console.log,\n warn: console.warn,\n error: console.error,\n debug: () => {},\n};\n\nconst channel = createBouncerChannel(pluginLogger);\n\nexport default definePluginEntry({\n id: \"bouncer\",\n name: \"Bouncer Protocol\",\n description: \"Agent-to-agent negotiation channel via the Bouncer Protocol. \" +\n \"Handles WebSocket lifecycle, heartbeats, echo filtering, and protocol \" +\n \"message formatting so the LLM only deals with plain text.\",\n\n register(api: OpenClawPluginApi) {\n const logger = api.logger ?? pluginLogger;\n pluginLogger = logger;\n\n api.registerChannel({ plugin: channel });\n setRuntime(api.runtime);\n\n if (api.runtime.logging) {\n const child = api.runtime.logging.getChildLogger(\"bouncer\");\n if (child) pluginLogger = child;\n }\n\n const bouncerConfig = resolveChannelConfig(api);\n if (!bouncerConfig) {\n logger.warn(\"[bouncer] No bouncer channel config found — will self-start from runtime config.\");\n setTimeout(() => {\n ensureServiceStartedWithTools(api, pluginLogger).catch((err: any) => {\n pluginLogger.error(`[bouncer] Deferred start failed: ${err.message}`);\n });\n }, 2_000);\n return;\n }\n\n const config = resolveConfig(bouncerConfig);\n logger.info(`[bouncer] Registering plugin — role: ${config.role}, agent: ${config.agentId}`);\n\n api.registerService(createBouncerService(config));\n\n const tools = createBrandTools(config, logger);\n for (const tool of tools) {\n api.registerTool(tool, { name: tool.name });\n }\n\n logger.info(`[bouncer] Plugin registered. Role: ${config.role}`);\n if (config.role === \"bouncer\") {\n logger.info(\"[bouncer] Lobby service will start on gateway boot.\");\n } else {\n logger.info(\"[bouncer] Brand tools registered: bouncer_browse, bouncer_profile, bouncer_offer\");\n }\n },\n});\n\nasync function ensureServiceStartedWithTools(api: OpenClawPluginApi, log: PluginLogger): Promise<void> {\n try {\n const cfg = await api.runtime.config.loadConfig();\n const bouncerCfg = cfg?.channels?.bouncer as Record<string, unknown> | undefined;\n if (!bouncerCfg?.role) {\n log.warn(\"[bouncer] Deferred start: no channels.bouncer.role found in runtime config.\");\n return;\n }\n\n const config = resolveConfig(bouncerCfg);\n log.info(`[bouncer] Deferred registration — role: ${config.role}, agent: ${config.agentId}`);\n\n api.registerService(createBouncerService(config));\n\n const tools = createBrandTools(config, log);\n for (const tool of tools) {\n api.registerTool(tool, { name: tool.name });\n }\n\n if (config.role === \"bouncer\") {\n log.info(\"[bouncer] Lobby service registered via deferred start.\");\n } else {\n log.info(\"[bouncer] Brand tools registered via deferred start: bouncer_browse, bouncer_profile, bouncer_offer\");\n }\n\n await ensureServiceStarted(log);\n } catch (err: any) {\n log.error(`[bouncer] Deferred start failed: ${err.message}`);\n }\n}\n\nfunction resolveChannelConfig(api: OpenClawPluginApi): Record<string, unknown> | null {\n const fromChannels = api.config?.channels?.bouncer as Record<string, unknown> | undefined;\n if (fromChannels && fromChannels.role) return fromChannels;\n\n if (api.pluginConfig && Object.keys(api.pluginConfig).length > 0) {\n return api.pluginConfig;\n }\n\n if (fromChannels && !fromChannels.role) {\n pluginLogger.warn(\n \"[bouncer] channels.bouncer exists but has no 'role' — check config. \" +\n \"Required: role, apiUrl, apiKey, agentId\"\n );\n }\n\n return null;\n}\n"],"mappings":"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","names":["EventEmitter","WebSocket","channel"]}
|
|
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