import type { IncomingMessage, ServerResponse } from "node:http"; import type { Command } from "commander"; import type { AgentMessage } from "@mariozechner/pi-agent-core"; import type { AuthProfileCredential, OAuthCredential } from "../agents/auth-profiles/types.js"; import type { AnyAgentTool } from "../agents/tools/common.js"; import type { ChannelDock } from "../channels/dock.js"; import type { ChannelPlugin } from "../channels/plugins/types.js"; import type { ClawdbotConfig } from "../config/config.js"; import type { InternalHookHandler } from "../hooks/internal-hooks.js"; import type { HookEntry } from "../hooks/types.js"; import type { ModelProviderConfig } from "../config/types.js"; import type { RuntimeEnv } from "../runtime.js"; import type { WizardPrompter } from "../wizard/prompts.js"; import type { createVpsAwareOAuthHandlers } from "../commands/oauth-flow.js"; import type { GatewayRequestHandler } from "../gateway/server-methods/types.js"; import type { PluginRuntime } from "./runtime/types.js"; export type { PluginRuntime } from "./runtime/types.js"; export type PluginLogger = { debug?: (message: string) => void; info: (message: string) => void; warn: (message: string) => void; error: (message: string) => void; }; export type PluginConfigUiHint = { label?: string; help?: string; advanced?: boolean; sensitive?: boolean; placeholder?: string; }; export type PluginKind = "memory"; export type PluginConfigValidation = | { ok: true; value?: unknown } | { ok: false; errors: string[] }; export type ClawdbotPluginConfigSchema = { safeParse?: (value: unknown) => { success: boolean; data?: unknown; error?: { issues?: Array<{ path: Array; message: string }>; }; }; parse?: (value: unknown) => unknown; validate?: (value: unknown) => PluginConfigValidation; uiHints?: Record; jsonSchema?: Record; }; export type ClawdbotPluginToolContext = { config?: ClawdbotConfig; workspaceDir?: string; agentDir?: string; agentId?: string; sessionKey?: string; messageChannel?: string; agentAccountId?: string; sandboxed?: boolean; }; export type ClawdbotPluginToolFactory = ( ctx: ClawdbotPluginToolContext, ) => AnyAgentTool | AnyAgentTool[] | null | undefined; export type ClawdbotPluginToolOptions = { name?: string; names?: string[]; optional?: boolean; }; export type ClawdbotPluginHookOptions = { entry?: HookEntry; name?: string; description?: string; register?: boolean; }; export type ProviderAuthKind = "oauth" | "api_key" | "token" | "device_code" | "custom"; export type ProviderAuthResult = { profiles: Array<{ profileId: string; credential: AuthProfileCredential }>; configPatch?: Partial; defaultModel?: string; notes?: string[]; }; export type ProviderAuthContext = { config: ClawdbotConfig; agentDir?: string; workspaceDir?: string; prompter: WizardPrompter; runtime: RuntimeEnv; isRemote: boolean; openUrl: (url: string) => Promise; oauth: { createVpsAwareHandlers: typeof createVpsAwareOAuthHandlers; }; }; export type ProviderAuthMethod = { id: string; label: string; hint?: string; kind: ProviderAuthKind; run: (ctx: ProviderAuthContext) => Promise; }; export type ProviderPlugin = { id: string; label: string; docsPath?: string; aliases?: string[]; envVars?: string[]; models?: ModelProviderConfig; auth: ProviderAuthMethod[]; formatApiKey?: (cred: AuthProfileCredential) => string; refreshOAuth?: (cred: OAuthCredential) => Promise; }; export type ClawdbotPluginGatewayMethod = { method: string; handler: GatewayRequestHandler; }; export type ClawdbotPluginHttpHandler = ( req: IncomingMessage, res: ServerResponse, ) => Promise | boolean; export type ClawdbotPluginCliContext = { program: Command; config: ClawdbotConfig; workspaceDir?: string; logger: PluginLogger; }; export type ClawdbotPluginCliRegistrar = (ctx: ClawdbotPluginCliContext) => void | Promise; export type ClawdbotPluginServiceContext = { config: ClawdbotConfig; workspaceDir?: string; stateDir: string; logger: PluginLogger; }; export type ClawdbotPluginService = { id: string; start: (ctx: ClawdbotPluginServiceContext) => void | Promise; stop?: (ctx: ClawdbotPluginServiceContext) => void | Promise; }; export type ClawdbotPluginChannelRegistration = { plugin: ChannelPlugin; dock?: ChannelDock; }; export type ClawdbotPluginDefinition = { id?: string; name?: string; description?: string; version?: string; kind?: PluginKind; configSchema?: ClawdbotPluginConfigSchema; register?: (api: ClawdbotPluginApi) => void | Promise; activate?: (api: ClawdbotPluginApi) => void | Promise; }; export type ClawdbotPluginModule = | ClawdbotPluginDefinition | ((api: ClawdbotPluginApi) => void | Promise); export type ClawdbotPluginApi = { id: string; name: string; version?: string; description?: string; source: string; config: ClawdbotConfig; pluginConfig?: Record; runtime: PluginRuntime; logger: PluginLogger; registerTool: ( tool: AnyAgentTool | ClawdbotPluginToolFactory, opts?: ClawdbotPluginToolOptions, ) => void; registerHook: ( events: string | string[], handler: InternalHookHandler, opts?: ClawdbotPluginHookOptions, ) => void; registerHttpHandler: (handler: ClawdbotPluginHttpHandler) => void; registerChannel: (registration: ClawdbotPluginChannelRegistration | ChannelPlugin) => void; registerGatewayMethod: (method: string, handler: GatewayRequestHandler) => void; registerCli: (registrar: ClawdbotPluginCliRegistrar, opts?: { commands?: string[] }) => void; registerService: (service: ClawdbotPluginService) => void; registerProvider: (provider: ProviderPlugin) => void; resolvePath: (input: string) => string; /** Register a lifecycle hook handler */ on: ( hookName: K, handler: PluginHookHandlerMap[K], opts?: { priority?: number }, ) => void; }; export type PluginOrigin = "bundled" | "global" | "workspace" | "config"; export type PluginDiagnostic = { level: "warn" | "error"; message: string; pluginId?: string; source?: string; }; // ============================================================================ // Plugin Hooks // ============================================================================ export type PluginHookName = | "before_agent_start" | "agent_end" | "before_compaction" | "after_compaction" | "message_received" | "message_sending" | "message_sent" | "before_tool_call" | "after_tool_call" | "tool_result_persist" | "session_start" | "session_end" | "gateway_start" | "gateway_stop"; // Agent context shared across agent hooks export type PluginHookAgentContext = { agentId?: string; sessionKey?: string; workspaceDir?: string; messageProvider?: string; }; // before_agent_start hook export type PluginHookBeforeAgentStartEvent = { prompt: string; messages?: unknown[]; }; export type PluginHookBeforeAgentStartResult = { systemPrompt?: string; prependContext?: string; }; // agent_end hook export type PluginHookAgentEndEvent = { messages: unknown[]; success: boolean; error?: string; durationMs?: number; }; // Compaction hooks export type PluginHookBeforeCompactionEvent = { messageCount: number; tokenCount?: number; }; export type PluginHookAfterCompactionEvent = { messageCount: number; tokenCount?: number; compactedCount: number; }; // Message context export type PluginHookMessageContext = { channelId: string; accountId?: string; conversationId?: string; }; // message_received hook export type PluginHookMessageReceivedEvent = { from: string; content: string; timestamp?: number; metadata?: Record; }; // message_sending hook export type PluginHookMessageSendingEvent = { to: string; content: string; metadata?: Record; }; export type PluginHookMessageSendingResult = { content?: string; cancel?: boolean; }; // message_sent hook export type PluginHookMessageSentEvent = { to: string; content: string; success: boolean; error?: string; }; // Tool context export type PluginHookToolContext = { agentId?: string; sessionKey?: string; toolName: string; }; // before_tool_call hook export type PluginHookBeforeToolCallEvent = { toolName: string; params: Record; }; export type PluginHookBeforeToolCallResult = { params?: Record; block?: boolean; blockReason?: string; }; // after_tool_call hook export type PluginHookAfterToolCallEvent = { toolName: string; params: Record; result?: unknown; error?: string; durationMs?: number; }; // tool_result_persist hook export type PluginHookToolResultPersistContext = { agentId?: string; sessionKey?: string; toolName?: string; toolCallId?: string; }; export type PluginHookToolResultPersistEvent = { toolName?: string; toolCallId?: string; /** * The toolResult message about to be written to the session transcript. * Handlers may return a modified message (e.g. drop non-essential fields). */ message: AgentMessage; /** True when the tool result was synthesized by a guard/repair step. */ isSynthetic?: boolean; }; export type PluginHookToolResultPersistResult = { message?: AgentMessage; }; // Session context export type PluginHookSessionContext = { agentId?: string; sessionId: string; }; // session_start hook export type PluginHookSessionStartEvent = { sessionId: string; resumedFrom?: string; }; // session_end hook export type PluginHookSessionEndEvent = { sessionId: string; messageCount: number; durationMs?: number; }; // Gateway context export type PluginHookGatewayContext = { port?: number; }; // gateway_start hook export type PluginHookGatewayStartEvent = { port: number; }; // gateway_stop hook export type PluginHookGatewayStopEvent = { reason?: string; }; // Hook handler types mapped by hook name export type PluginHookHandlerMap = { before_agent_start: ( event: PluginHookBeforeAgentStartEvent, ctx: PluginHookAgentContext, ) => Promise | PluginHookBeforeAgentStartResult | void; agent_end: (event: PluginHookAgentEndEvent, ctx: PluginHookAgentContext) => Promise | void; before_compaction: ( event: PluginHookBeforeCompactionEvent, ctx: PluginHookAgentContext, ) => Promise | void; after_compaction: ( event: PluginHookAfterCompactionEvent, ctx: PluginHookAgentContext, ) => Promise | void; message_received: ( event: PluginHookMessageReceivedEvent, ctx: PluginHookMessageContext, ) => Promise | void; message_sending: ( event: PluginHookMessageSendingEvent, ctx: PluginHookMessageContext, ) => Promise | PluginHookMessageSendingResult | void; message_sent: ( event: PluginHookMessageSentEvent, ctx: PluginHookMessageContext, ) => Promise | void; before_tool_call: ( event: PluginHookBeforeToolCallEvent, ctx: PluginHookToolContext, ) => Promise | PluginHookBeforeToolCallResult | void; after_tool_call: ( event: PluginHookAfterToolCallEvent, ctx: PluginHookToolContext, ) => Promise | void; tool_result_persist: ( event: PluginHookToolResultPersistEvent, ctx: PluginHookToolResultPersistContext, ) => PluginHookToolResultPersistResult | void; session_start: ( event: PluginHookSessionStartEvent, ctx: PluginHookSessionContext, ) => Promise | void; session_end: ( event: PluginHookSessionEndEvent, ctx: PluginHookSessionContext, ) => Promise | void; gateway_start: ( event: PluginHookGatewayStartEvent, ctx: PluginHookGatewayContext, ) => Promise | void; gateway_stop: ( event: PluginHookGatewayStopEvent, ctx: PluginHookGatewayContext, ) => Promise | void; }; export type PluginHookRegistration = { pluginId: string; hookName: K; handler: PluginHookHandlerMap[K]; priority?: number; source: string; };