mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 15:02:32 +00:00
feat(coding-agent): add event bus for tool/hook communication (#431)
* feat(coding-agent): add event bus for tool/hook communication Adds pi.events API enabling custom tools and hooks to communicate via pub/sub. Tools can emit events, hooks can listen. Shared EventBus instance created per session in createAgentSession(). - EventBus interface with emit() and on() methods - on() returns unsubscribe function - Threaded through hook and tool loaders - Documented in hooks.md and custom-tools.md * fix(coding-agent): wrap event handlers to catch errors * docs: note async handler error handling for event bus * feat(coding-agent): add sendMessage to tools, nextTurn delivery mode - Custom tools now have pi.sendMessage() for direct agent notifications - New deliverAs: 'nextTurn' queues messages for next user prompt - Fix: hooks and tools now share the same eventBus (was isolated before) * fix(coding-agent): nextTurn delivery should always queue, even when streaming
This commit is contained in:
parent
12805f61bd
commit
9c9e6822e3
13 changed files with 293 additions and 33 deletions
|
|
@ -15,6 +15,7 @@ import { fileURLToPath } from "node:url";
|
|||
import { createJiti } from "jiti";
|
||||
import { getAgentDir, isBunBinary } from "../../config.js";
|
||||
import { theme } from "../../modes/interactive/theme/theme.js";
|
||||
import { createEventBus, type EventBus } from "../event-bus.js";
|
||||
import type { ExecOptions } from "../exec.js";
|
||||
import { execCommand } from "../exec.js";
|
||||
import type { HookUIContext } from "../hooks/types.js";
|
||||
|
|
@ -213,10 +214,12 @@ export async function loadCustomTools(
|
|||
paths: string[],
|
||||
cwd: string,
|
||||
builtInToolNames: string[],
|
||||
eventBus?: EventBus,
|
||||
): Promise<CustomToolsLoadResult> {
|
||||
const tools: LoadedCustomTool[] = [];
|
||||
const errors: Array<{ path: string; error: string }> = [];
|
||||
const seenNames = new Set<string>(builtInToolNames);
|
||||
const resolvedEventBus = eventBus ?? createEventBus();
|
||||
|
||||
// Shared API object - all tools get the same instance
|
||||
const sharedApi: CustomToolAPI = {
|
||||
|
|
@ -225,6 +228,8 @@ export async function loadCustomTools(
|
|||
execCommand(command, args, options?.cwd ?? cwd, options),
|
||||
ui: createNoOpUIContext(),
|
||||
hasUI: false,
|
||||
events: resolvedEventBus,
|
||||
sendMessage: () => {},
|
||||
};
|
||||
|
||||
for (const toolPath of paths) {
|
||||
|
|
@ -259,6 +264,9 @@ export async function loadCustomTools(
|
|||
sharedApi.ui = uiContext;
|
||||
sharedApi.hasUI = hasUI;
|
||||
},
|
||||
setSendMessageHandler(handler) {
|
||||
sharedApi.sendMessage = handler;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -303,12 +311,14 @@ function discoverToolsInDir(dir: string): string[] {
|
|||
* @param cwd - Current working directory
|
||||
* @param builtInToolNames - Names of built-in tools to check for conflicts
|
||||
* @param agentDir - Agent config directory. Default: from getAgentDir()
|
||||
* @param eventBus - Optional shared event bus (creates isolated bus if not provided)
|
||||
*/
|
||||
export async function discoverAndLoadCustomTools(
|
||||
configuredPaths: string[],
|
||||
cwd: string,
|
||||
builtInToolNames: string[],
|
||||
agentDir: string = getAgentDir(),
|
||||
eventBus?: EventBus,
|
||||
): Promise<CustomToolsLoadResult> {
|
||||
const allPaths: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
|
@ -335,5 +345,5 @@ export async function discoverAndLoadCustomTools(
|
|||
// 3. Explicitly configured paths (can override/add)
|
||||
addPaths(configuredPaths.map((p) => resolveToolPath(p, cwd)));
|
||||
|
||||
return loadCustomTools(allPaths, cwd, builtInToolNames);
|
||||
return loadCustomTools(allPaths, cwd, builtInToolNames, eventBus);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue