Inject hire_agent and file_approval into CEO agent (C4 part 3/5)
Wire the two internal tools from parts 1-2 end-to-end: - `invokeInternalTool` RPC method added to RuntimeBridge; worker tool `execute` calls route here, handler dispatches by tool name via the new `agent-runtime/internal-tools/router.ts`. - `InternalToolCallbacks` (`onApprovalCreated` / `onApprovalResolved` / `onDomainChanged`) are late-bound on the bridge via `setInternalToolCallbacks`; `wire-api-server` now cross-wires the same callbacks used by the HTTP approval route so thread integration / automation fire identically across both entry points. - `RunJob.internalTools` (new field) carries the per-run tool list main decides at dispatch time via `orchestration/internal-tool- selector.ts`. Selection rule: `hire_agent` → any agent with `canRequestHire` authority; `file_approval` → CEOs only (scoped to the `approve_ceo_strategy` use case). - Worker `createPiAgent` call site now assembles `codingTools + internalTools` before handing to pi. Exhaustiveness guard on the switch catches new tool names at compile time. No prompt-level wiring yet — the `initial-user-turn` and `team-building.en.md` updates ship in parts 4 and 5 so this commit only adds the tool surface without changing the CEO's observable behaviour (the existing HTTP path is still the one the prompt tells the CEO to call). tests: pnpm typecheck + pnpm test:unit (529) + pnpm test:eval (8/8) green
This commit is contained in:
1 parent
d65f156732
commit
b839ce4f23
9 files changed
+265
-6
No files matched your search
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Dispatch router for main-side internal-tool handlers (C4 part 3/5).
|
||||
*
|
||||
* The worker RPC method `invokeInternalTool` lands here; this module
|
||||
* picks the right handler by `toolName` and delegates. Adding a new
|
||||
* internal tool means: (a) new worker-side tool definition under
|
||||
* `src/main/worker/runtime/internal-tools/`, (b) new handler under
|
||||
* `src/main/agent-runtime/internal-tools/`, (c) one new `case` in the
|
||||
* switch below. No third file to update, no registry lookup — the
|
||||
* compile-time `never`-exhaustiveness on the default case catches a
|
||||
* missing branch at build time.
|
||||
*
|
||||
* The router never catches: every handler throws a classified
|
||||
* `AppError` on failure and the caller (`RuntimeBridge`) translates the
|
||||
* throw into the `{ ok: false, error }` RPC envelope. Silent swallow
|
||||
* would collapse tool-error plus tool-success onto the same success
|
||||
* wire shape, which is the exact failure mode the tool-error
|
||||
* convention exists to prevent.
|
||||
*/
|
||||
|
||||
import { HIRE_AGENT_TOOL_NAME } from "@main/worker/runtime/internal-tools/hire-agent-tool";
|
||||
import { FILE_APPROVAL_TOOL_NAME } from "@main/worker/runtime/internal-tools/file-approval-tool";
|
||||
import type {
|
||||
InvokeInternalToolRpcPayload,
|
||||
InvokeInternalToolRpcResult,
|
||||
} from "@main/worker/runtime/internal-tools/internal-tool-rpc";
|
||||
import {
|
||||
handleHireAgentToolCall,
|
||||
type HireAgentHandlerDeps,
|
||||
} from "./hire-agent-handler";
|
||||
import {
|
||||
handleFileApprovalToolCall,
|
||||
type FileApprovalHandlerDeps,
|
||||
} from "./file-approval-handler";
|
||||
import { UserInputError } from "@main/errors";
|
||||
|
||||
export interface InternalToolRouterDeps {
|
||||
hireAgent: HireAgentHandlerDeps;
|
||||
fileApproval: FileApprovalHandlerDeps;
|
||||
}
|
||||
|
||||
export interface InternalToolRouterContext {
|
||||
companyId: string;
|
||||
agentId: string;
|
||||
}
|
||||
|
||||
export function routeInternalToolCall(
|
||||
deps: InternalToolRouterDeps,
|
||||
ctx: InternalToolRouterContext,
|
||||
payload: InvokeInternalToolRpcPayload,
|
||||
): InvokeInternalToolRpcResult {
|
||||
switch (payload.toolName) {
|
||||
case HIRE_AGENT_TOOL_NAME:
|
||||
return handleHireAgentToolCall(deps.hireAgent, ctx, payload.args);
|
||||
case FILE_APPROVAL_TOOL_NAME:
|
||||
return handleFileApprovalToolCall(deps.fileApproval, ctx, payload.args);
|
||||
default:
|
||||
throw new UserInputError({
|
||||
code: "internal_tool.unknown",
|
||||
message: `Unknown internal tool: ${payload.toolName}`,
|
||||
context: { toolName: payload.toolName },
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user