466 lines
12 KiB
TypeScript
466 lines
12 KiB
TypeScript
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<string | number>; message: string }>;
|
|
};
|
|
};
|
|
parse?: (value: unknown) => unknown;
|
|
validate?: (value: unknown) => PluginConfigValidation;
|
|
uiHints?: Record<string, PluginConfigUiHint>;
|
|
jsonSchema?: Record<string, unknown>;
|
|
};
|
|
|
|
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<ClawdbotConfig>;
|
|
defaultModel?: string;
|
|
notes?: string[];
|
|
};
|
|
|
|
export type ProviderAuthContext = {
|
|
config: ClawdbotConfig;
|
|
agentDir?: string;
|
|
workspaceDir?: string;
|
|
prompter: WizardPrompter;
|
|
runtime: RuntimeEnv;
|
|
isRemote: boolean;
|
|
openUrl: (url: string) => Promise<void>;
|
|
oauth: {
|
|
createVpsAwareHandlers: typeof createVpsAwareOAuthHandlers;
|
|
};
|
|
};
|
|
|
|
export type ProviderAuthMethod = {
|
|
id: string;
|
|
label: string;
|
|
hint?: string;
|
|
kind: ProviderAuthKind;
|
|
run: (ctx: ProviderAuthContext) => Promise<ProviderAuthResult>;
|
|
};
|
|
|
|
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<OAuthCredential>;
|
|
};
|
|
|
|
export type ClawdbotPluginGatewayMethod = {
|
|
method: string;
|
|
handler: GatewayRequestHandler;
|
|
};
|
|
|
|
export type ClawdbotPluginHttpHandler = (
|
|
req: IncomingMessage,
|
|
res: ServerResponse,
|
|
) => Promise<boolean> | boolean;
|
|
|
|
export type ClawdbotPluginCliContext = {
|
|
program: Command;
|
|
config: ClawdbotConfig;
|
|
workspaceDir?: string;
|
|
logger: PluginLogger;
|
|
};
|
|
|
|
export type ClawdbotPluginCliRegistrar = (ctx: ClawdbotPluginCliContext) => void | Promise<void>;
|
|
|
|
export type ClawdbotPluginServiceContext = {
|
|
config: ClawdbotConfig;
|
|
workspaceDir?: string;
|
|
stateDir: string;
|
|
logger: PluginLogger;
|
|
};
|
|
|
|
export type ClawdbotPluginService = {
|
|
id: string;
|
|
start: (ctx: ClawdbotPluginServiceContext) => void | Promise<void>;
|
|
stop?: (ctx: ClawdbotPluginServiceContext) => void | Promise<void>;
|
|
};
|
|
|
|
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<void>;
|
|
activate?: (api: ClawdbotPluginApi) => void | Promise<void>;
|
|
};
|
|
|
|
export type ClawdbotPluginModule =
|
|
| ClawdbotPluginDefinition
|
|
| ((api: ClawdbotPluginApi) => void | Promise<void>);
|
|
|
|
export type ClawdbotPluginApi = {
|
|
id: string;
|
|
name: string;
|
|
version?: string;
|
|
description?: string;
|
|
source: string;
|
|
config: ClawdbotConfig;
|
|
pluginConfig?: Record<string, unknown>;
|
|
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: <K extends PluginHookName>(
|
|
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<string, unknown>;
|
|
};
|
|
|
|
// message_sending hook
|
|
export type PluginHookMessageSendingEvent = {
|
|
to: string;
|
|
content: string;
|
|
metadata?: Record<string, unknown>;
|
|
};
|
|
|
|
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<string, unknown>;
|
|
};
|
|
|
|
export type PluginHookBeforeToolCallResult = {
|
|
params?: Record<string, unknown>;
|
|
block?: boolean;
|
|
blockReason?: string;
|
|
};
|
|
|
|
// after_tool_call hook
|
|
export type PluginHookAfterToolCallEvent = {
|
|
toolName: string;
|
|
params: Record<string, unknown>;
|
|
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> | PluginHookBeforeAgentStartResult | void;
|
|
agent_end: (event: PluginHookAgentEndEvent, ctx: PluginHookAgentContext) => Promise<void> | void;
|
|
before_compaction: (
|
|
event: PluginHookBeforeCompactionEvent,
|
|
ctx: PluginHookAgentContext,
|
|
) => Promise<void> | void;
|
|
after_compaction: (
|
|
event: PluginHookAfterCompactionEvent,
|
|
ctx: PluginHookAgentContext,
|
|
) => Promise<void> | void;
|
|
message_received: (
|
|
event: PluginHookMessageReceivedEvent,
|
|
ctx: PluginHookMessageContext,
|
|
) => Promise<void> | void;
|
|
message_sending: (
|
|
event: PluginHookMessageSendingEvent,
|
|
ctx: PluginHookMessageContext,
|
|
) => Promise<PluginHookMessageSendingResult | void> | PluginHookMessageSendingResult | void;
|
|
message_sent: (
|
|
event: PluginHookMessageSentEvent,
|
|
ctx: PluginHookMessageContext,
|
|
) => Promise<void> | void;
|
|
before_tool_call: (
|
|
event: PluginHookBeforeToolCallEvent,
|
|
ctx: PluginHookToolContext,
|
|
) => Promise<PluginHookBeforeToolCallResult | void> | PluginHookBeforeToolCallResult | void;
|
|
after_tool_call: (
|
|
event: PluginHookAfterToolCallEvent,
|
|
ctx: PluginHookToolContext,
|
|
) => Promise<void> | void;
|
|
tool_result_persist: (
|
|
event: PluginHookToolResultPersistEvent,
|
|
ctx: PluginHookToolResultPersistContext,
|
|
) => PluginHookToolResultPersistResult | void;
|
|
session_start: (
|
|
event: PluginHookSessionStartEvent,
|
|
ctx: PluginHookSessionContext,
|
|
) => Promise<void> | void;
|
|
session_end: (
|
|
event: PluginHookSessionEndEvent,
|
|
ctx: PluginHookSessionContext,
|
|
) => Promise<void> | void;
|
|
gateway_start: (
|
|
event: PluginHookGatewayStartEvent,
|
|
ctx: PluginHookGatewayContext,
|
|
) => Promise<void> | void;
|
|
gateway_stop: (
|
|
event: PluginHookGatewayStopEvent,
|
|
ctx: PluginHookGatewayContext,
|
|
) => Promise<void> | void;
|
|
};
|
|
|
|
export type PluginHookRegistration<K extends PluginHookName = PluginHookName> = {
|
|
pluginId: string;
|
|
hookName: K;
|
|
handler: PluginHookHandlerMap[K];
|
|
priority?: number;
|
|
source: string;
|
|
};
|