@vibearound/plugin-channel-sdk 0.3.0 → 0.4.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.
@@ -1,52 +1,39 @@
1
1
  /**
2
- * runChannelPlugin — shared main.ts boilerplate for every channel plugin.
2
+ * runChannelPlugin — the SDK entry point for every channel plugin.
3
3
  *
4
- * Each channel plugin used to have a ~120-line `main.ts` that was 85%
5
- * identical across Slack, Telegram, Discord, DingTalk, WeCom, etc:
6
- * connect to host, validate config keys, wire the standard sessionUpdate
7
- * and extNotification handlers, create the stream handler, start the bot,
8
- * wait for disconnect, stop. This helper absorbs that boilerplate so each
9
- * plugin's `main.ts` reduces to ~20 lines — a factory for the bot and a
10
- * factory for the stream handler.
4
+ * Handles the full ACP lifecycle: connect to host, validate config, create
5
+ * bot + renderer, start the bot, then await disconnect and stop. The plugin
6
+ * only implements platform-specific transport (sendText, sendBlock, editBlock).
11
7
  *
12
8
  * ## Usage
13
9
  *
14
10
  * ```ts
15
11
  * import { runChannelPlugin } from "@vibearound/plugin-channel-sdk";
16
- * import { SlackBot } from "./bot.js";
17
- * import { AgentStreamHandler } from "./agent-stream.js";
18
12
  *
19
13
  * runChannelPlugin({
20
14
  * name: "vibearound-slack",
21
15
  * version: "0.1.0",
22
16
  * requiredConfig: ["bot_token", "app_token"],
23
17
  * createBot: ({ config, agent, log, cacheDir }) =>
24
- * new SlackBot(
25
- * { bot_token: config.bot_token as string, app_token: config.app_token as string },
26
- * agent,
27
- * log,
28
- * cacheDir,
29
- * ),
30
- * createStreamHandler: (bot, log, verbose) =>
31
- * new AgentStreamHandler(bot, log, verbose),
18
+ * new SlackBot({ ... }, agent, log, cacheDir),
19
+ * createRenderer: (bot, log, verbose) =>
20
+ * new SlackRenderer(bot, log, verbose),
32
21
  * });
33
22
  * ```
34
23
  */
35
24
  import os from "node:os";
36
25
  import path from "node:path";
37
- import { connectToHost, normalizeExtMethod } from "./connection.js";
26
+ import { connectToHost, stripExtPrefix } from "./connection.js";
38
27
  import { extractErrorMessage } from "./errors.js";
39
28
  // ---------------------------------------------------------------------------
40
29
  // Implementation
41
30
  // ---------------------------------------------------------------------------
42
31
  /**
43
- * Run a channel plugin to completion.
32
+ * Run a channel plugin.
44
33
  *
45
- * Performs the ACP initialize handshake, validates required config,
46
- * constructs the bot + stream handler, starts the bot, waits for the host
47
- * connection to close, then stops the bot and exits the process.
48
- *
49
- * Never returns under normal operation — the process exits at the end.
34
+ * Handles the full ACP lifecycle: connect to host, validate config,
35
+ * construct bot + renderer, start the bot, then wait for the host
36
+ * to disconnect before stopping and exiting.
50
37
  */
51
38
  export async function runChannelPlugin(spec) {
52
39
  const prefix = `[${spec.name.replace(/^vibearound-/, "")}-plugin]`;
@@ -63,10 +50,10 @@ export async function runChannelPlugin(spec) {
63
50
  }
64
51
  async function runInner(spec, log) {
65
52
  log("info", "initializing ACP connection...");
66
- let streamHandler = null;
53
+ let renderer = null;
67
54
  const { agent, meta, agentInfo, conn } = await connectToHost({ name: spec.name, version: spec.version }, () => ({
68
55
  async sessionUpdate(params) {
69
- streamHandler?.onSessionUpdate(params);
56
+ renderer?.onSessionUpdate(params);
70
57
  },
71
58
  async requestPermission(params) {
72
59
  const first = params.options?.[0];
@@ -76,23 +63,38 @@ async function runInner(spec, log) {
76
63
  throw new Error("No permission options provided");
77
64
  },
78
65
  async extNotification(method, params) {
79
- switch (normalizeExtMethod(method)) {
80
- case "channel/system_text": {
81
- const text = params.text;
82
- streamHandler?.onSystemText(text);
66
+ const chatId = typeof params.chatId === "string" ? params.chatId : undefined;
67
+ switch (stripExtPrefix(method)) {
68
+ case "va/system_text": {
69
+ const text = typeof params.text === "string" ? params.text : "";
70
+ if (chatId && renderer) {
71
+ renderer.onSystemText(chatId, text);
72
+ }
83
73
  break;
84
74
  }
85
- case "channel/agent_ready": {
86
- const agentName = params.agent;
87
- const version = params.version;
75
+ case "va/agent_ready": {
76
+ const agentName = typeof params.agent === "string" ? params.agent : "unknown";
77
+ const version = typeof params.version === "string" ? params.version : "";
88
78
  log("info", `agent_ready: ${agentName} v${version}`);
89
- streamHandler?.onAgentReady(agentName, version);
79
+ if (chatId && renderer) {
80
+ renderer.onAgentReady(chatId, agentName, version);
81
+ }
90
82
  break;
91
83
  }
92
- case "channel/session_ready": {
93
- const sessionId = params.sessionId;
84
+ case "va/session_ready": {
85
+ const sessionId = typeof params.sessionId === "string" ? params.sessionId : "";
94
86
  log("info", `session_ready: ${sessionId}`);
95
- streamHandler?.onSessionReady(sessionId);
87
+ if (chatId && renderer) {
88
+ renderer.onSessionReady(chatId, sessionId);
89
+ }
90
+ break;
91
+ }
92
+ case "va/command_menu": {
93
+ const systemCommands = Array.isArray(params.systemCommands) ? params.systemCommands : [];
94
+ const agentCommands = Array.isArray(params.agentCommands) ? params.agentCommands : [];
95
+ if (chatId && renderer) {
96
+ renderer.onCommandMenu(chatId, systemCommands, agentCommands);
97
+ }
96
98
  break;
97
99
  }
98
100
  default:
@@ -101,9 +103,6 @@ async function runInner(spec, log) {
101
103
  },
102
104
  }));
103
105
  const config = meta.config;
104
- // Validate required config keys up front so a misconfigured plugin fails
105
- // with a clear error instead of some downstream "undefined is not a
106
- // string" crash in the bot constructor.
107
106
  for (const key of spec.requiredConfig ?? []) {
108
107
  if (config[key] === undefined || config[key] === null || config[key] === "") {
109
108
  throw new Error(`${key} is required in config`);
@@ -120,8 +119,8 @@ async function runInner(spec, log) {
120
119
  showThinking: verboseRaw?.show_thinking ?? false,
121
120
  showToolUse: verboseRaw?.show_tool_use ?? false,
122
121
  };
123
- streamHandler = spec.createStreamHandler(bot, log, verbose);
124
- bot.setStreamHandler(streamHandler);
122
+ renderer = spec.createRenderer(bot, log, verbose);
123
+ bot.setStreamHandler(renderer);
125
124
  await bot.start();
126
125
  log("info", "plugin started");
127
126
  await conn.closed;
@@ -129,4 +128,4 @@ async function runInner(spec, log) {
129
128
  await bot.stop();
130
129
  process.exit(0);
131
130
  }
132
- //# sourceMappingURL=run-plugin.js.map
131
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -25,35 +25,29 @@
25
25
  *
26
26
  * ## Usage
27
27
  *
28
+ * Subclass and implement `sendText` + `sendBlock` (+ optionally `editBlock`):
29
+ *
28
30
  * ```ts
29
31
  * class MyRenderer extends BlockRenderer<string> {
30
- * protected async sendBlock(channelId, kind, content) {
31
- * const msg = await myApi.sendMessage(channelId, content);
32
+ * protected async sendText(chatId, text) {
33
+ * await myApi.sendMessage(chatId, text);
34
+ * }
35
+ * protected async sendBlock(chatId, kind, content) {
36
+ * const msg = await myApi.sendMessage(chatId, content);
32
37
  * return msg.id;
33
38
  * }
34
- * protected async editBlock(channelId, ref, kind, content, sealed) {
39
+ * protected async editBlock(chatId, ref, kind, content, sealed) {
35
40
  * await myApi.editMessage(ref, content);
36
41
  * }
37
42
  * }
38
- *
39
- * // In main.ts:
40
- * const renderer = new MyRenderer({ verbose: { showThinking: false } });
41
- *
42
- * // When user sends a message:
43
- * renderer.onPromptSent(channelId);
44
- * try {
45
- * await agent.prompt({ sessionId, content });
46
- * await renderer.onTurnEnd(channelId);
47
- * } catch (e) {
48
- * await renderer.onTurnError(channelId, String(e));
49
- * }
50
- *
51
- * // In the ACP client's sessionUpdate handler:
52
- * renderer.onSessionUpdate(notification);
53
43
  * ```
44
+ *
45
+ * The SDK's `runChannelPlugin` wires all ACP events to this renderer
46
+ * automatically — plugins don't call onSessionUpdate/onPromptSent/etc
47
+ * directly.
54
48
  */
55
49
  import type { SessionNotification } from "@agentclientprotocol/sdk";
56
- import type { BlockKind, BlockRendererOptions, VerboseConfig } from "./types.js";
50
+ import type { BlockKind, BlockRendererOptions, CommandEntry, VerboseConfig } from "./types.js";
57
51
  /**
58
52
  * Abstract base class for block-based rendering of ACP session streams.
59
53
  *
@@ -62,18 +56,29 @@ import type { BlockKind, BlockRendererOptions, VerboseConfig } from "./types.js"
62
56
  * return type of `sendBlock` and the first argument of `editBlock`.
63
57
  */
64
58
  export declare abstract class BlockRenderer<TRef = string> {
59
+ /** When true, blocks are sent and edited in real-time. When false, each
60
+ * block is held until complete, then sent once (send-only mode). */
61
+ protected readonly streaming: boolean;
65
62
  protected readonly flushIntervalMs: number;
66
63
  protected readonly minEditIntervalMs: number;
67
64
  protected readonly verbose: VerboseConfig;
68
65
  private states;
66
+ /** The chatId of the most recent prompt. Used as fallback target for
67
+ * notifications that arrive without an explicit chatId. */
68
+ private lastActiveChatId;
69
69
  constructor(options?: BlockRendererOptions);
70
70
  /**
71
- * Send a new block message to the platform.
71
+ * Send a plain text message to the IM. Used for system text, agent ready
72
+ * notifications, session ready, and error messages.
73
+ */
74
+ protected abstract sendText(chatId: string, text: string): Promise<void>;
75
+ /**
76
+ * Send a new streaming block message to the platform.
72
77
  *
73
78
  * Return the platform message reference that will be passed to future
74
79
  * `editBlock` calls. Return `null` if editing is not supported.
75
80
  */
76
- protected abstract sendBlock(channelId: string, kind: BlockKind, content: string): Promise<TRef | null>;
81
+ protected abstract sendBlock(chatId: string, kind: BlockKind, content: string): Promise<TRef | null>;
77
82
  /**
78
83
  * Edit an existing block message in-place.
79
84
  *
@@ -83,7 +88,7 @@ export declare abstract class BlockRenderer<TRef = string> {
83
88
  * @param sealed - `true` when this is the final edit (block done streaming).
84
89
  * Use to switch from a "streaming" card format to a finalized one.
85
90
  */
86
- protected editBlock?(channelId: string, ref: TRef, kind: BlockKind, content: string, sealed: boolean): Promise<void>;
91
+ protected editBlock?(chatId: string, ref: TRef, kind: BlockKind, content: string, sealed: boolean): Promise<void>;
87
92
  /**
88
93
  * Format block content before sending or editing.
89
94
  *
@@ -97,54 +102,55 @@ export declare abstract class BlockRenderer<TRef = string> {
97
102
  protected formatContent(kind: BlockKind, content: string, _sealed: boolean): string;
98
103
  /**
99
104
  * Called after the last block has been flushed and the turn is complete.
100
- * Override to perform cleanup (e.g. remove a "typing" indicator, a
101
- * processing reaction, etc.).
105
+ * Override to perform cleanup (e.g. remove a "typing" indicator).
102
106
  */
103
- protected onAfterTurnEnd(_channelId: string): Promise<void>;
107
+ protected onAfterTurnEnd(_chatId: string): Promise<void>;
104
108
  /**
105
- * Called after a turn error, once state has been cleaned up.
106
- * Override to send an error message to the user.
109
+ * Called after a turn error. Default sends an error message via sendText.
110
+ * Override for platform-specific error rendering (e.g. error card).
107
111
  */
108
- protected onAfterTurnError(_channelId: string, _error: string): Promise<void>;
109
- /**
110
- * Map an ACP `sessionId` to the channel ID used internally.
111
- *
112
- * Default: identity (sessionId === channelId).
113
- *
114
- * Override if your plugin namespaces channel IDs (e.g. Feishu uses
115
- * `"feishu:<sessionId>"`, WeChat uses `"weixin-openclaw-bridge:<sessionId>"`).
116
- */
117
- protected sessionIdToChannelId(sessionId: string): string;
112
+ protected onAfterTurnError(chatId: string, error: string): Promise<void>;
118
113
  /**
119
114
  * Process an ACP `sessionUpdate` notification from the host.
120
115
  *
121
116
  * Routes the event to the correct block based on its variant, appending
122
117
  * deltas to the current block or starting a new one when the kind changes.
123
118
  *
124
- * Call this from the ACP `Client.sessionUpdate` handler.
119
+ * Called automatically by `runChannelPlugin` — plugins don't call this directly.
125
120
  */
126
121
  onSessionUpdate(notification: SessionNotification): void;
127
122
  /**
128
- * Call this before sending a prompt to the agent.
123
+ * Call before sending a prompt. Tracks the active chatId and clears
124
+ * leftover state from a previous turn.
125
+ */
126
+ onPromptSent(chatId: string): void;
127
+ /** Handle `va/system_text` from host. */
128
+ onSystemText(chatId: string, text: string): void;
129
+ /** Handle `va/agent_ready` from host. */
130
+ onAgentReady(chatId: string, agent: string, version: string): void;
131
+ /** Handle `va/session_ready` from host. */
132
+ onSessionReady(chatId: string, sessionId: string): void;
133
+ /**
134
+ * Handle `va/command_menu` from host — display available commands.
129
135
  *
130
- * Clears any leftover state from a previous turn so the new turn starts
131
- * with a clean slate.
136
+ * Default renders a plain-text list. Override for platform-specific
137
+ * rendering (e.g. Feishu interactive card, Slack Block Kit, Telegram
138
+ * inline keyboard).
132
139
  */
133
- onPromptSent(channelId: string): void;
140
+ onCommandMenu(chatId: string, systemCommands: CommandEntry[], agentCommands: CommandEntry[]): void;
134
141
  /**
135
142
  * Call this after `agent.prompt()` resolves (turn complete).
136
143
  *
137
144
  * Seals and flushes the last block, then waits for all pending sends/edits
138
145
  * to complete before calling `onAfterTurnEnd`.
139
146
  */
140
- onTurnEnd(channelId: string): Promise<void>;
147
+ onTurnEnd(chatId: string): Promise<void>;
141
148
  /**
142
149
  * Call this when `agent.prompt()` throws (turn error).
143
150
  *
144
- * Discards pending state and calls `onAfterTurnError` so the subclass can
145
- * send an error message to the user.
151
+ * Discards pending state and calls `onAfterTurnError`.
146
152
  */
147
- onTurnError(channelId: string, error: string): Promise<void>;
153
+ onTurnError(chatId: string, error: string): Promise<void>;
148
154
  private appendToBlock;
149
155
  private scheduleFlush;
150
156
  private flush;
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6EjF;;;;;;GAMG;AACH,8BAAsB,aAAa,CAAC,IAAI,GAAG,MAAM;IAC/C,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAE1C,OAAO,CAAC,MAAM,CAAyC;gBAE3C,OAAO,GAAE,oBAAyB;IAa9C;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,CAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAEvB;;;;;;;;OAQG;IACH,SAAS,CAAC,SAAS,CAAC,CAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAEhB;;;;;;;;;OASG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM;IAQnF;;;;OAIG;IACH,SAAS,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;OAGG;IACH,SAAS,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7E;;;;;;;OAOG;IACH,SAAS,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAQzD;;;;;;;OAOG;IACH,eAAe,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;IAgDxD;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAWrC;;;;;OAKG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBjD;;;;;OAKG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlE,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,KAAK;IA+Bb,OAAO,CAAC,YAAY;YAMN,UAAU;CAqBzB"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6E/F;;;;;;GAMG;AACH,8BAAsB,aAAa,CAAC,IAAI,GAAG,MAAM;IAC/C;yEACqE;IACrE,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IACtC,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAE1C,OAAO,CAAC,MAAM,CAAyC;IAEvD;gEAC4D;IAC5D,OAAO,CAAC,gBAAgB,CAAuB;gBAEnC,OAAO,GAAE,oBAAyB;IAc9C;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAExE;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAMvB;;;;;;;;OAQG;IACH,SAAS,CAAC,SAAS,CAAC,CAClB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAEhB;;;;;;;;;OASG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM;IAQnF;;;OAGG;IACH,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD;;;OAGG;cACa,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9E;;;;;;;OAOG;IACH,eAAe,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;IA4CxD;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAgBlC,yCAAyC;IACzC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhD,yCAAyC;IACzC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlE,2CAA2C;IAC3C,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIvD;;;;;;OAMG;IACH,aAAa,CACX,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,YAAY,EAAE,EAC9B,aAAa,EAAE,YAAY,EAAE,GAC5B,IAAI;IA0BP;;;;;OAKG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB9C;;;;OAIG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/D,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,KAAK;IA4Bb,OAAO,CAAC,YAAY;YAMN,UAAU;CAqBzB"}